-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add AWS CognitoAuthTokenProvider module (#536)
* Add AWS CognitoAuthTokenProvider module An HttpClient AuthTokenProvider for AWS Cognito * Packaging pom on aws-cognito * Release aws-cognito/http-client-authtoken independently
- Loading branch information
Showing
7 changed files
with
276 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
<parent> | ||
<groupId>org.avaje</groupId> | ||
<artifactId>java11-oss</artifactId> | ||
<version>4.5</version> | ||
</parent> | ||
|
||
<groupId>io.avaje.aws</groupId> | ||
<artifactId>avaje-cognito-client-token</artifactId> | ||
<version>1.0-RC1</version> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>io.avaje</groupId> | ||
<artifactId>avaje-http-client</artifactId> | ||
<version>2.8</version> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>io.avaje</groupId> | ||
<artifactId>avaje-json-core</artifactId> | ||
<version>3.0-RC5</version> | ||
</dependency> | ||
|
||
<!-- test dependencies --> | ||
<dependency> | ||
<groupId>io.avaje</groupId> | ||
<artifactId>avaje-json-node</artifactId> | ||
<version>3.0-RC5</version> | ||
<scope>test</scope> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>io.avaje</groupId> | ||
<artifactId>junit</artifactId> | ||
<version>1.5</version> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
</project> |
93 changes: 93 additions & 0 deletions
93
...ient-authtoken/src/main/java/io/avaje/aws/client/cognito/AmzCognitoAuthTokenProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package io.avaje.aws.client.cognito; | ||
|
||
import io.avaje.http.client.AuthToken; | ||
import io.avaje.http.client.AuthTokenProvider; | ||
import io.avaje.http.client.BasicAuthIntercept; | ||
import io.avaje.http.client.HttpClientRequest; | ||
import io.avaje.json.simple.SimpleMapper; | ||
|
||
import java.net.http.HttpResponse; | ||
import java.time.Instant; | ||
|
||
final class AmzCognitoAuthTokenProvider implements CognitoAuthTokenProvider.Builder { | ||
|
||
private String url; | ||
private String clientId; | ||
private String clientSecret; | ||
private String scope; | ||
|
||
@Override | ||
public CognitoAuthTokenProvider.Builder url(String url) { | ||
this.url = url; | ||
return this; | ||
} | ||
|
||
@Override | ||
public CognitoAuthTokenProvider.Builder clientId(String clientId) { | ||
this.clientId = clientId; | ||
return this; | ||
} | ||
|
||
@Override | ||
public CognitoAuthTokenProvider.Builder clientSecret(String clientSecret) { | ||
this.clientSecret = clientSecret; | ||
return this; | ||
} | ||
|
||
@Override | ||
public CognitoAuthTokenProvider.Builder scope(String scope) { | ||
this.scope = scope; | ||
return this; | ||
} | ||
|
||
@Override | ||
public AuthTokenProvider build() { | ||
return new Provider(url, clientId, clientSecret, scope); | ||
} | ||
|
||
private static final class Provider implements AuthTokenProvider { | ||
|
||
private static final SimpleMapper MAPPER = SimpleMapper.builder().build(); | ||
|
||
private final String url; | ||
private final String clientId; | ||
private final String scope; | ||
private final String authHeader; | ||
|
||
public Provider(String url, String clientId, String clientSecret, String scope) { | ||
this.url = url; | ||
this.clientId = clientId; | ||
this.scope = scope; | ||
this.authHeader = "Basic " + BasicAuthIntercept.encode(clientId, clientSecret); | ||
} | ||
|
||
@Override | ||
public AuthToken obtainToken(HttpClientRequest request) { | ||
HttpResponse<String> res = request | ||
.url(url) | ||
.header("Authorization", authHeader) | ||
.formParam("grant_type", "client_credentials") | ||
.formParam("client_id", clientId) | ||
.formParam("scope", scope) | ||
.POST() | ||
.asString(); | ||
|
||
if (res.statusCode() != 200) { | ||
throw new IllegalStateException("Error response getting access token statusCode:" + res.statusCode() + " res:" + res); | ||
} | ||
return decodeAuthToken(res.body()); | ||
} | ||
|
||
private AuthToken decodeAuthToken(String responseBody) { | ||
final var responseMap = MAPPER.fromJsonObject(responseBody); | ||
final var accessToken = (String) responseMap.get("access_token"); | ||
final var expiresIn = (Long) responseMap.get("expires_in"); | ||
|
||
var validUntil = Instant.now() | ||
.plusSeconds(expiresIn) | ||
.minusSeconds(60); | ||
|
||
return AuthToken.of(accessToken, validUntil); | ||
} | ||
} | ||
} |
65 changes: 65 additions & 0 deletions
65
...-client-authtoken/src/main/java/io/avaje/aws/client/cognito/CognitoAuthTokenProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package io.avaje.aws.client.cognito; | ||
|
||
import io.avaje.http.client.AuthTokenProvider; | ||
|
||
/** | ||
* AuthTokenProvider for AWS Cognito providing Bearer access tokens. | ||
* | ||
* <pre>{@code | ||
* | ||
* AuthTokenProvider authTokenProvider = CognitoAuthTokenProvider.builder() | ||
* .url("https://foo.amazoncognito.com/oauth2/token") | ||
* .clientId("<something>") | ||
* .clientSecret("<something>") | ||
* .scope("default/default") | ||
* .build(); | ||
* | ||
* // specify the authTokenProvider on the HttpClient ... | ||
* | ||
* HttpClient client = HttpClient.builder() | ||
* .authTokenProvider(authTokenProvider) | ||
* .baseUrl(myApplicationUrl) | ||
* .build(); | ||
* | ||
* }</pre> | ||
*/ | ||
public interface CognitoAuthTokenProvider extends AuthTokenProvider { | ||
|
||
/** | ||
* Return a builder for the CognitoAuthTokenProvider. | ||
*/ | ||
static Builder builder() { | ||
return new AmzCognitoAuthTokenProvider(); | ||
} | ||
|
||
/** | ||
* The builder for the AWS Cognito AuthTokenProvider. | ||
*/ | ||
interface Builder { | ||
|
||
/** | ||
* Set the url used to obtain access tokens. | ||
*/ | ||
Builder url(String url); | ||
|
||
/** | ||
* Set the clientId. | ||
*/ | ||
Builder clientId(String clientId); | ||
|
||
/** | ||
* Set the clientSecret. | ||
*/ | ||
Builder clientSecret(String clientSecret); | ||
|
||
/** | ||
* Set the scope. | ||
*/ | ||
Builder scope(String scope); | ||
|
||
/** | ||
* Build and return the AuthTokenProvider. | ||
*/ | ||
AuthTokenProvider build(); | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
aws-cognito/http-client-authtoken/src/main/java/module-info.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
module io.avaje.aws.client.cognito { | ||
|
||
exports io.avaje.aws.client.cognito; | ||
|
||
requires transitive io.avaje.http.client; | ||
requires transitive io.avaje.json; | ||
} |
49 changes: 49 additions & 0 deletions
49
...ent-authtoken/src/test/java/io/avaje/aws/client/cognito/CognitoAuthTokenProviderTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package io.avaje.aws.client.cognito; | ||
|
||
import io.avaje.http.client.AuthTokenProvider; | ||
import io.avaje.http.client.HttpClientRequest; | ||
import io.avaje.http.client.HttpClientResponse; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import java.net.http.HttpResponse; | ||
|
||
import static org.mockito.ArgumentMatchers.anyString; | ||
import static org.mockito.Mockito.*; | ||
|
||
@SuppressWarnings("unchecked") | ||
class CognitoAuthTokenProviderTest { | ||
|
||
@Test | ||
void obtainToken() { | ||
final String url = "https://<something>.amazoncognito.com/oauth2/token"; | ||
final String clientId = "<something>"; | ||
final String clientSecret = "<something>"; | ||
|
||
AuthTokenProvider authTokenProvider = CognitoAuthTokenProvider.builder() | ||
.url(url) | ||
.clientId(clientId) | ||
.clientSecret(clientSecret) | ||
.scope("default/default") | ||
.build(); | ||
|
||
HttpResponse<String> httpResponse = mock(HttpResponse.class); | ||
when(httpResponse.statusCode()).thenReturn(200); | ||
when(httpResponse.body()).thenReturn("{\"access_token\":\"1234\",\"expires_in\":3600}"); | ||
|
||
HttpClientResponse clientResponse = mock(HttpClientResponse.class); | ||
when(clientResponse.asString()).thenReturn(httpResponse); | ||
|
||
HttpClientRequest httpClientRequest = mock(HttpClientRequest.class); | ||
when(httpClientRequest.url(anyString())).thenReturn(httpClientRequest); | ||
|
||
when(httpClientRequest.header(anyString(), anyString())).thenReturn(httpClientRequest); | ||
when(httpClientRequest.formParam(anyString(), anyString())).thenReturn(httpClientRequest); | ||
when(httpClientRequest.POST()).thenReturn(clientResponse); | ||
|
||
// act | ||
authTokenProvider.obtainToken(httpClientRequest); | ||
|
||
// verify the Authorization header has been obtained and set | ||
verify(httpClientRequest).header("Authorization", "Basic PHNvbWV0aGluZz46PHNvbWV0aGluZz4="); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
<parent> | ||
<groupId>org.avaje</groupId> | ||
<artifactId>java11-oss</artifactId> | ||
<version>4.5</version> | ||
</parent> | ||
|
||
<artifactId>aws-cognito</artifactId> | ||
<packaging>pom</packaging> | ||
|
||
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters