Implemented OpenID token service for authorization code flow.
Change-Id: Ibfeceb73bff1b53020764f8664d587b0e2415129
diff --git a/core/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java b/core/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java
index b885924..ed1a11f 100644
--- a/core/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java
+++ b/core/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java
@@ -129,6 +129,7 @@
public static final int INVALID_AUTHORIZATION = 1809;
public static final int UNSUPPORTED_GRANT_TYPE = 1810;
+ public static final int UNSUPPORTED_AUTHENTICATION_METHOD = 1811;
/**
diff --git a/full/Changes b/full/Changes
index 4c99586..8a401af 100644
--- a/full/Changes
+++ b/full/Changes
@@ -1,10 +1,12 @@
version 0.60.4
-18/06/2018
+19/06/2018
- implemented OAuth2 authorization code request with OpenID Authentication (margaretha)
- enabled OAuth2 authorization without OpenID authentication using Nimbus library (margaretha)
- implemented response handler for OpenID authentication errors in authorization requests (margaretha)
- added tests regarding OpenID authentication in authorization requests (margaretha)
- implemented OAuth2 authorization error response via redirect URI instead of JSON (margaretha)
+ - added state to OAuth2 authorization error response (margaretha)
+ - implemented OpenID token service for authorization code flow (margaretha)
version 0.60.3
06/06/2018
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/ClientDeregistrationValidator.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/ClientDeregistrationValidator.java
similarity index 94%
rename from full/src/main/java/de/ids_mannheim/korap/oauth2/ClientDeregistrationValidator.java
rename to full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/ClientDeregistrationValidator.java
index 422b346..72be70d 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/ClientDeregistrationValidator.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/ClientDeregistrationValidator.java
@@ -1,4 +1,4 @@
-package de.ids_mannheim.korap.oauth2;
+package de.ids_mannheim.korap.oauth2.oltu;
import javax.servlet.http.HttpServletRequest;
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/OAuth2AuthorizationRequest.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/OAuth2AuthorizationRequest.java
similarity index 95%
rename from full/src/main/java/de/ids_mannheim/korap/oauth2/OAuth2AuthorizationRequest.java
rename to full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/OAuth2AuthorizationRequest.java
index a5d9add..503a5c8 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/OAuth2AuthorizationRequest.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/OAuth2AuthorizationRequest.java
@@ -1,4 +1,4 @@
-package de.ids_mannheim.korap.oauth2;
+package de.ids_mannheim.korap.oauth2.oltu;
import javax.servlet.http.HttpServletRequest;
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/OAuth2DeregisterClientRequest.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/OAuth2DeregisterClientRequest.java
similarity index 95%
rename from full/src/main/java/de/ids_mannheim/korap/oauth2/OAuth2DeregisterClientRequest.java
rename to full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/OAuth2DeregisterClientRequest.java
index ecc2bc0..3da0c02 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/OAuth2DeregisterClientRequest.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/OAuth2DeregisterClientRequest.java
@@ -1,4 +1,4 @@
-package de.ids_mannheim.korap.oauth2;
+package de.ids_mannheim.korap.oauth2.oltu;
import javax.servlet.http.HttpServletRequest;
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuTokenService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuTokenService.java
new file mode 100644
index 0000000..0df9a3c
--- /dev/null
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuTokenService.java
@@ -0,0 +1,116 @@
+package de.ids_mannheim.korap.oauth2.oltu.service;
+
+import java.util.Set;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.oltu.oauth2.as.issuer.OAuthIssuer;
+import org.apache.oltu.oauth2.as.request.AbstractOAuthTokenRequest;
+import org.apache.oltu.oauth2.as.response.OAuthASResponse;
+import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
+import org.apache.oltu.oauth2.common.message.OAuthResponse;
+import org.apache.oltu.oauth2.common.message.types.GrantType;
+import org.apache.oltu.oauth2.common.message.types.TokenType;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
+import de.ids_mannheim.korap.oauth2.constant.OAuth2Error;
+import de.ids_mannheim.korap.oauth2.dao.AccessTokenDao;
+import de.ids_mannheim.korap.oauth2.entity.AccessScope;
+import de.ids_mannheim.korap.oauth2.entity.Authorization;
+import de.ids_mannheim.korap.oauth2.service.OAuth2TokenService;
+
+@Service
+public class OltuTokenService extends OAuth2TokenService {
+
+ @Autowired
+ private OAuthIssuer oauthIssuer;
+
+ @Autowired
+ private AccessTokenDao tokenDao;
+
+ public OAuthResponse requestAccessToken (
+ AbstractOAuthTokenRequest oAuthRequest)
+ throws KustvaktException, OAuthSystemException {
+
+ String grantType = oAuthRequest.getGrantType();
+
+ if (grantType.equals(GrantType.AUTHORIZATION_CODE.toString())) {
+ Authorization authorization =
+ requestAccessTokenWithAuthorizationCode(
+ oAuthRequest.getCode(),
+ oAuthRequest.getRedirectURI(),
+ oAuthRequest.getClientId(),
+ oAuthRequest.getClientSecret());
+ return createsAccessTokenResponse(authorization);
+ }
+ else if (grantType.equals(GrantType.PASSWORD.toString())) {
+ requestAccessTokenWithPassword(oAuthRequest.getUsername(),
+ oAuthRequest.getPassword(), oAuthRequest.getScopes(),
+ oAuthRequest.getClientId(), oAuthRequest.getClientSecret());
+ return createsAccessTokenResponse(oAuthRequest.getScopes(),
+ oAuthRequest.getUsername());
+ }
+ else if (grantType.equals(GrantType.CLIENT_CREDENTIALS.toString())) {
+ Set<String> scopes = requestAccessTokenWithClientCredentials(
+ oAuthRequest.getClientId(), oAuthRequest.getClientSecret(),
+ oAuthRequest.getScopes());
+ return createsAccessTokenResponse(scopes, null);
+ }
+ else {
+ throw new KustvaktException(StatusCodes.UNSUPPORTED_GRANT_TYPE,
+ grantType + " is not supported.",
+ OAuth2Error.UNSUPPORTED_GRANT_TYPE);
+ }
+
+ }
+
+ /**
+ * Creates an OAuthResponse containing an access token and a
+ * refresh token with type Bearer.
+ *
+ * @return an OAuthResponse containing an access token
+ * @throws OAuthSystemException
+ * @throws KustvaktException
+ */
+ private OAuthResponse createsAccessTokenResponse (Set<String> scopes,
+ String userId) throws OAuthSystemException, KustvaktException {
+
+ String accessToken = oauthIssuer.accessToken();
+ // String refreshToken = oauthIssuer.refreshToken();
+
+ Set<AccessScope> accessScopes =
+ scopeService.convertToAccessScope(scopes);
+ tokenDao.storeAccessToken(accessToken, accessScopes, userId);
+
+ return OAuthASResponse.tokenResponse(Status.OK.getStatusCode())
+ .setAccessToken(accessToken)
+ .setTokenType(TokenType.BEARER.toString())
+ .setExpiresIn(String.valueOf(config.getTokenTTL()))
+ // .setRefreshToken(refreshToken)
+ .setScope(String.join(" ", scopes)).buildJSONMessage();
+ }
+
+ private OAuthResponse createsAccessTokenResponse (
+ Authorization authorization)
+ throws OAuthSystemException, KustvaktException {
+ String accessToken = oauthIssuer.accessToken();
+ // String refreshToken = oauthIssuer.refreshToken();
+
+ tokenDao.storeAccessToken(authorization, accessToken);
+
+ String scopes = scopeService
+ .convertAccessScopesToString(authorization.getScopes());
+
+ OAuthResponse r =
+ OAuthASResponse.tokenResponse(Status.OK.getStatusCode())
+ .setAccessToken(accessToken)
+ .setTokenType(TokenType.BEARER.toString())
+ .setExpiresIn(String.valueOf(config.getTokenTTL()))
+ // .setRefreshToken(refreshToken)
+ .setScope(scopes).buildJSONMessage();
+ return r;
+ }
+}
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/OpenIdHttpRequestWrapper.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/OpenIdHttpRequestWrapper.java
new file mode 100644
index 0000000..8f6d80b
--- /dev/null
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/OpenIdHttpRequestWrapper.java
@@ -0,0 +1,38 @@
+package de.ids_mannheim.korap.oauth2.openid;
+
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import com.nimbusds.oauth2.sdk.ParseException;
+import com.nimbusds.oauth2.sdk.http.HTTPRequest;
+
+public class OpenIdHttpRequestWrapper extends HTTPRequest {
+
+ private Map<String, String> params;
+
+ public OpenIdHttpRequestWrapper (Method method, URL url) {
+ super(method, url);
+ }
+
+ @Override
+ public Map<String, String> getQueryParameters () {
+ return this.params;
+ }
+
+ public void toHttpRequest (HttpServletRequest servletRequest,
+ Map<String, String> map) throws ParseException {
+
+ this.params = map;
+ this.setClientIPAddress(servletRequest.getRemoteAddr());
+ this.setContentType(servletRequest.getContentType());
+
+ Enumeration<String> headerNames = servletRequest.getHeaderNames();
+ while (headerNames.hasMoreElements()) {
+ String name = headerNames.nextElement().toString();
+ this.setHeader(name, servletRequest.getHeader(name));
+ }
+ }
+}
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/service/OpenIdTokenService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/service/OpenIdTokenService.java
new file mode 100644
index 0000000..8ce9b16
--- /dev/null
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/service/OpenIdTokenService.java
@@ -0,0 +1,125 @@
+package de.ids_mannheim.korap.oauth2.openid.service;
+
+import java.net.URI;
+import java.util.Set;
+
+import org.springframework.stereotype.Service;
+
+import com.nimbusds.oauth2.sdk.AccessTokenResponse;
+import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant;
+import com.nimbusds.oauth2.sdk.AuthorizationGrant;
+import com.nimbusds.oauth2.sdk.GrantType;
+import com.nimbusds.oauth2.sdk.Scope;
+import com.nimbusds.oauth2.sdk.TokenRequest;
+import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
+import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
+import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic;
+import com.nimbusds.oauth2.sdk.auth.ClientSecretPost;
+import com.nimbusds.oauth2.sdk.token.AccessToken;
+import com.nimbusds.oauth2.sdk.token.BearerAccessToken;
+import com.nimbusds.oauth2.sdk.token.RefreshToken;
+import com.nimbusds.oauth2.sdk.token.Tokens;
+import com.nimbusds.openid.connect.sdk.OIDCTokenResponse;
+import com.nimbusds.openid.connect.sdk.token.OIDCTokens;
+
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
+import de.ids_mannheim.korap.oauth2.constant.OAuth2Error;
+import de.ids_mannheim.korap.oauth2.entity.AccessScope;
+import de.ids_mannheim.korap.oauth2.entity.Authorization;
+import de.ids_mannheim.korap.oauth2.service.OAuth2TokenService;
+
+@Service
+public class OpenIdTokenService extends OAuth2TokenService {
+
+ public AccessTokenResponse requestAccessToken (TokenRequest tokenRequest)
+ throws KustvaktException {
+ AuthorizationGrant grant = tokenRequest.getAuthorizationGrant();
+ GrantType grantType = grant.getType();
+ ClientAuthentication clientAuthentication =
+ tokenRequest.getClientAuthentication();
+ String[] clientCredentials =
+ extractClientCredentials(clientAuthentication);
+
+ if (grantType.equals(GrantType.AUTHORIZATION_CODE)) {
+ AuthorizationCodeGrant codeGrant = (AuthorizationCodeGrant) grant;
+ String authorizationCode =
+ codeGrant.getAuthorizationCode().getValue();
+ URI redirectionURI = codeGrant.getRedirectionURI();
+ String redirectURI = null;
+ if (redirectionURI != null) {
+ redirectURI = redirectionURI.toString();
+ }
+ Authorization authorization =
+ requestAccessTokenWithAuthorizationCode(authorizationCode,
+ redirectURI, clientCredentials[0],
+ clientCredentials[1]);
+ return createsAccessTokenResponse(authorization);
+ }
+ else if (grantType.equals(GrantType.PASSWORD)) {
+
+ }
+ else if (grantType.equals(GrantType.CLIENT_CREDENTIALS)) {
+
+ }
+ else {
+ throw new KustvaktException(StatusCodes.UNSUPPORTED_GRANT_TYPE,
+ grantType + " is not supported.",
+ OAuth2Error.UNSUPPORTED_GRANT_TYPE);
+ }
+ return null;
+ }
+
+
+ private AccessTokenResponse createsAccessTokenResponse (
+ Authorization authorization) {
+ Set<AccessScope> scopes = authorization.getScopes();
+ String[] scopeArray = scopes.stream().map(scope -> scope.toString())
+ .toArray(String[]::new);
+ Scope scope = new Scope(scopeArray);
+ AccessToken accessToken =
+ new BearerAccessToken(config.getTokenTTL(), scope);
+ RefreshToken refreshToken = new RefreshToken();
+
+ if (scope.contains("openid")) {
+ // id token should be encrypted according to keys and
+ // algorithms the client specified during registration
+ String idToken = "thisIsIdToken";
+ OIDCTokens tokens =
+ new OIDCTokens(idToken, accessToken, refreshToken);
+ return new OIDCTokenResponse(tokens);
+ }
+ else {
+ Tokens tokens = new Tokens(accessToken, refreshToken);
+ return new AccessTokenResponse(tokens);
+ }
+ }
+
+
+ private String[] extractClientCredentials (
+ ClientAuthentication clientAuthentication)
+ throws KustvaktException {
+
+ ClientAuthenticationMethod method = clientAuthentication.getMethod();
+ String clientSecret;
+ String clientId;
+ if (method.equals(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)) {
+ ClientSecretBasic basic = (ClientSecretBasic) clientAuthentication;
+ clientSecret = basic.getClientSecret().getValue();
+ clientId = basic.getClientID().getValue();
+ }
+ else if (method.equals(ClientAuthenticationMethod.CLIENT_SECRET_POST)) {
+ ClientSecretPost post = (ClientSecretPost) clientAuthentication;
+ clientSecret = post.getClientSecret().getValue();
+ clientId = post.getClientID().getValue();
+ }
+ else {
+ // client authentication method is not supported
+ throw new KustvaktException(
+ StatusCodes.UNSUPPORTED_AUTHENTICATION_METHOD,
+ method.getValue() + " is not supported.",
+ OAuth2Error.INVALID_CLIENT);
+ }
+ return new String[] { clientId, clientSecret };
+ }
+}
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2AuthorizationService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2AuthorizationService.java
index 6bb584f..b103e33 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2AuthorizationService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2AuthorizationService.java
@@ -152,8 +152,12 @@
}
String authorizedUri = authorization.getRedirectURI();
- if (authorizedUri != null && !authorizedUri.isEmpty()
- && !authorizedUri.equals(redirectURI)) {
+ if (authorizedUri != null && !authorizedUri.isEmpty()) {
+ if (!authorizedUri.equals(redirectURI))
+ throw new KustvaktException(StatusCodes.INVALID_REDIRECT_URI,
+ "Invalid redirect URI", OAuth2Error.INVALID_GRANT);
+ }
+ else if (redirectURI != null && !redirectURI.isEmpty()) {
throw new KustvaktException(StatusCodes.INVALID_REDIRECT_URI,
"Invalid redirect URI", OAuth2Error.INVALID_GRANT);
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ScopeService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ScopeService.java
index 15b51e3..f47fa3c 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ScopeService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ScopeService.java
@@ -50,9 +50,14 @@
}
public String convertAccessScopesToString (Set<AccessScope> scopes) {
+ Set<String> set = convertAccessScopesToStringSet(scopes);
+ return String.join(" ", set);
+ }
+
+ public Set<String> convertAccessScopesToStringSet (Set<AccessScope> scopes) {
Set<String> set = scopes.stream().map(scope -> scope.toString())
.collect(Collectors.toSet());
- return String.join(" ", set);
+ return set;
}
/**
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2TokenService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2TokenService.java
index e6609d4..c64274d 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2TokenService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2TokenService.java
@@ -4,15 +4,6 @@
import java.util.Map;
import java.util.Set;
-import javax.ws.rs.core.Response.Status;
-
-import org.apache.oltu.oauth2.as.issuer.OAuthIssuer;
-import org.apache.oltu.oauth2.as.request.AbstractOAuthTokenRequest;
-import org.apache.oltu.oauth2.as.response.OAuthASResponse;
-import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
-import org.apache.oltu.oauth2.common.message.OAuthResponse;
-import org.apache.oltu.oauth2.common.message.types.GrantType;
-import org.apache.oltu.oauth2.common.message.types.TokenType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -22,8 +13,6 @@
import de.ids_mannheim.korap.exceptions.StatusCodes;
import de.ids_mannheim.korap.interfaces.AuthenticationManagerIface;
import de.ids_mannheim.korap.oauth2.constant.OAuth2Error;
-import de.ids_mannheim.korap.oauth2.dao.AccessTokenDao;
-import de.ids_mannheim.korap.oauth2.entity.AccessScope;
import de.ids_mannheim.korap.oauth2.entity.Authorization;
import de.ids_mannheim.korap.oauth2.entity.OAuth2Client;
@@ -39,50 +28,17 @@
@Autowired
private OAuth2ClientService clientService;
-
+
@Autowired
private OAuth2AuthorizationService authorizationService;
-
- @Autowired
- private OAuth2ScopeService scopeService;
- @Autowired
- private AccessTokenDao tokenDao;
@Autowired
- private FullConfiguration config;
+ protected OAuth2ScopeService scopeService;
+
+ @Autowired
+ protected FullConfiguration config;
@Autowired
private AuthenticationManagerIface authenticationManager;
- @Autowired
- private OAuthIssuer oauthIssuer;
-
- public OAuthResponse requestAccessToken (
- AbstractOAuthTokenRequest oAuthRequest)
- throws KustvaktException, OAuthSystemException {
-
- String grantType = oAuthRequest.getGrantType();
-
- if (grantType.equals(GrantType.AUTHORIZATION_CODE.toString())) {
- return requestAccessTokenWithAuthorizationCode(
- oAuthRequest.getCode(), oAuthRequest.getRedirectURI(),
- oAuthRequest.getClientId(), oAuthRequest.getClientSecret());
- }
- else if (grantType.equals(GrantType.PASSWORD.toString())) {
- return requestAccessTokenWithPassword(oAuthRequest.getUsername(),
- oAuthRequest.getPassword(), oAuthRequest.getScopes(),
- oAuthRequest.getClientId(), oAuthRequest.getClientSecret());
- }
- else if (grantType.equals(GrantType.CLIENT_CREDENTIALS.toString())) {
- return requestAccessTokenWithClientCredentials(
- oAuthRequest.getClientId(), oAuthRequest.getClientSecret(),
- oAuthRequest.getScopes());
- }
- else {
- throw new KustvaktException(StatusCodes.UNSUPPORTED_GRANT_TYPE,
- grantType + " is not supported.",
- OAuth2Error.UNSUPPORTED_GRANT_TYPE);
- }
-
- }
/**
* RFC 6749:
@@ -98,15 +54,13 @@
* @param clientSecret
* clilent_secret, required if client_secret was issued
* for the client in client registration.
- * @return an OAuthResponse containing an access token if
- * successful
+ * @return an authorization
* @throws OAuthSystemException
* @throws KustvaktException
*/
- private OAuthResponse requestAccessTokenWithAuthorizationCode (
+ protected Authorization requestAccessTokenWithAuthorizationCode (
String authorizationCode, String redirectURI, String clientId,
- String clientSecret)
- throws KustvaktException, OAuthSystemException {
+ String clientSecret) throws KustvaktException {
Authorization authorization =
authorizationService.retrieveAuthorization(authorizationCode);
@@ -119,7 +73,7 @@
authorizationService.addTotalAttempts(authorization);
throw e;
}
- return createsAccessTokenResponse(authorization);
+ return authorization;
}
@@ -152,10 +106,9 @@
* @throws KustvaktException
* @throws OAuthSystemException
*/
- private OAuthResponse requestAccessTokenWithPassword (String username,
+ protected void requestAccessTokenWithPassword (String username,
String password, Set<String> scopes, String clientId,
- String clientSecret)
- throws KustvaktException, OAuthSystemException {
+ String clientSecret) throws KustvaktException {
OAuth2Client client =
clientService.authenticateClient(clientId, clientSecret);
@@ -167,7 +120,6 @@
authenticateUser(username, password, scopes);
// verify or limit scopes ?
- return createsAccessTokenResponse(scopes, username);
}
public void authenticateUser (String username, String password,
@@ -204,9 +156,9 @@
* @throws KustvaktException
* @throws OAuthSystemException
*/
- private OAuthResponse requestAccessTokenWithClientCredentials (
+ protected Set<String> requestAccessTokenWithClientCredentials (
String clientId, String clientSecret, Set<String> scopes)
- throws KustvaktException, OAuthSystemException {
+ throws KustvaktException {
if (clientSecret == null || clientSecret.isEmpty()) {
throw new KustvaktException(
@@ -228,54 +180,9 @@
scopes = scopeService.filterScopes(scopes,
config.getClientCredentialsScopes());
- return createsAccessTokenResponse(scopes, null);
+ return scopes;
}
- /**
- * Creates an OAuthResponse containing an access token and a
- * refresh token with type Bearer.
- *
- * @return an OAuthResponse containing an access token
- * @throws OAuthSystemException
- * @throws KustvaktException
- */
- private OAuthResponse createsAccessTokenResponse (Set<String> scopes,
- String userId) throws OAuthSystemException, KustvaktException {
- String accessToken = oauthIssuer.accessToken();
- // String refreshToken = oauthIssuer.refreshToken();
-
- Set<AccessScope> accessScopes =
- scopeService.convertToAccessScope(scopes);
- tokenDao.storeAccessToken(accessToken, accessScopes, userId);
-
- return OAuthASResponse.tokenResponse(Status.OK.getStatusCode())
- .setAccessToken(accessToken)
- .setTokenType(TokenType.BEARER.toString())
- .setExpiresIn(String.valueOf(config.getTokenTTL()))
- // .setRefreshToken(refreshToken)
- .setScope(String.join(" ", scopes)).buildJSONMessage();
- }
-
- private OAuthResponse createsAccessTokenResponse (
- Authorization authorization)
- throws OAuthSystemException, KustvaktException {
- String accessToken = oauthIssuer.accessToken();
- // String refreshToken = oauthIssuer.refreshToken();
-
- tokenDao.storeAccessToken(authorization, accessToken);
-
- String scopes = scopeService
- .convertAccessScopesToString(authorization.getScopes());
-
- OAuthResponse r =
- OAuthASResponse.tokenResponse(Status.OK.getStatusCode())
- .setAccessToken(accessToken)
- .setTokenType(TokenType.BEARER.toString())
- .setExpiresIn(String.valueOf(config.getTokenTTL()))
- // .setRefreshToken(refreshToken)
- .setScope(scopes).buildJSONMessage();
- return r;
- }
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/OAuth2ResponseHandler.java b/full/src/main/java/de/ids_mannheim/korap/web/OAuth2ResponseHandler.java
index d244e90..959803c 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/OAuth2ResponseHandler.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/OAuth2ResponseHandler.java
@@ -46,21 +46,44 @@
return throwit(StatusCodes.OAUTH2_SYSTEM_ERROR, e.getMessage());
}
+ public WebApplicationException throwit (OAuthSystemException e,
+ String state) {
+ if (state != null && !state.isEmpty()) {
+ return throwit(StatusCodes.OAUTH2_SYSTEM_ERROR, e.getMessage(),
+ "state=" + state);
+ }
+ return throwit(e);
+ }
+
public WebApplicationException throwit (OAuthProblemException e) {
+ return throwit(e, null);
+ }
+
+ public WebApplicationException throwit (OAuthProblemException e,
+ String state) {
OAuthResponse oAuthResponse = null;
try {
- oAuthResponse = OAuthResponse.errorResponse(e.getResponseStatus())
- .error(e).buildJSONMessage();
+ OAuthErrorResponseBuilder builder = OAuthResponse.errorResponse(e.getResponseStatus())
+ .error(e);
+
+ if (state != null && !state.isEmpty()) {
+ builder.setState(state);
+ }
+ oAuthResponse = builder.buildJSONMessage();
}
catch (OAuthSystemException e1) {
- throwit(e1);
+ throwit(e1, state);
}
Response r = createResponse(oAuthResponse);
return new WebApplicationException(r);
}
@Override
- public WebApplicationException throwit (KustvaktException e) {
+ public WebApplicationException throwit (KustvaktException e){
+ return throwit(e, null);
+ }
+
+ public WebApplicationException throwit (KustvaktException e, String state) {
OAuthResponse oAuthResponse = null;
String errorCode = e.getEntity();
try {
@@ -68,7 +91,7 @@
|| errorCode.equals(OAuth2Error.UNAUTHORIZED_CLIENT)
|| errorCode.equals(OAuth2Error.INVALID_TOKEN)) {
oAuthResponse = createOAuthResponse(e,
- Status.UNAUTHORIZED.getStatusCode());
+ Status.UNAUTHORIZED.getStatusCode(), state);
}
else if (errorCode.equals(OAuth2Error.INVALID_GRANT)
|| errorCode.equals(OAuth2Error.INVALID_REQUEST)
@@ -77,26 +100,26 @@
|| errorCode.equals(OAuth2Error.UNSUPPORTED_RESPONSE_TYPE)
|| errorCode.equals(OAuth2Error.ACCESS_DENIED)) {
oAuthResponse = createOAuthResponse(e,
- Status.BAD_REQUEST.getStatusCode());
+ Status.BAD_REQUEST.getStatusCode(), state);
}
else if (errorCode.equals(OAuth2Error.INSUFFICIENT_SCOPE)) {
oAuthResponse = createOAuthResponse(e,
- Status.FORBIDDEN.getStatusCode());
+ Status.FORBIDDEN.getStatusCode(), state);
}
else if (errorCode.equals(OAuth2Error.SERVER_ERROR)) {
oAuthResponse = createOAuthResponse(e,
- Status.INTERNAL_SERVER_ERROR.getStatusCode());
+ Status.INTERNAL_SERVER_ERROR.getStatusCode(), state);
}
else if (errorCode.equals(OAuth2Error.TEMPORARILY_UNAVAILABLE)) {
oAuthResponse = createOAuthResponse(e,
- Status.SERVICE_UNAVAILABLE.getStatusCode());
+ Status.SERVICE_UNAVAILABLE.getStatusCode(), state);
}
else {
return super.throwit(e);
}
}
catch (OAuthSystemException e1) {
- return throwit(e1);
+ return throwit(e1, state);
}
Response r = createResponse(oAuthResponse);
@@ -104,12 +127,16 @@
}
private OAuthResponse createOAuthResponse (KustvaktException e,
- int statusCode) throws OAuthSystemException {
+ int statusCode, String state) throws OAuthSystemException {
OAuthProblemException oAuthProblemException = OAuthProblemException
- .error(e.getEntity()).description(e.getMessage());
+ .error(e.getEntity()).state(state).description(e.getMessage());
OAuthErrorResponseBuilder responseBuilder = OAuthResponse
.errorResponse(statusCode).error(oAuthProblemException);
+ if (state!=null && !state.isEmpty()){
+ responseBuilder.setState(state);
+ }
+
URI redirectUri = e.getRedirectUri();
if (redirectUri != null) {
responseBuilder.location(redirectUri.toString());
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/OpenIdResponseHandler.java b/full/src/main/java/de/ids_mannheim/korap/web/OpenIdResponseHandler.java
index 21cecdb..eb6a19e 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/OpenIdResponseHandler.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/OpenIdResponseHandler.java
@@ -7,13 +7,17 @@
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
+import javax.ws.rs.core.Response.Status;
+import org.apache.http.HttpHeaders;
import org.springframework.stereotype.Service;
+import com.nimbusds.oauth2.sdk.AccessTokenResponse;
import com.nimbusds.oauth2.sdk.AuthorizationErrorResponse;
import com.nimbusds.oauth2.sdk.ErrorObject;
import com.nimbusds.oauth2.sdk.ParseException;
import com.nimbusds.oauth2.sdk.ResponseMode;
+import com.nimbusds.oauth2.sdk.TokenErrorResponse;
import com.nimbusds.oauth2.sdk.id.State;
import com.nimbusds.oauth2.sdk.token.BearerTokenError;
import com.nimbusds.openid.connect.sdk.AuthenticationErrorResponse;
@@ -52,10 +56,12 @@
final static Map<String, ErrorObject> tokenErrorObjectMap = new HashMap<>();
{
- errorObjectMap.put(OAuth2Error.INSUFFICIENT_SCOPE,
+ tokenErrorObjectMap.put(OAuth2Error.INSUFFICIENT_SCOPE,
BearerTokenError.INSUFFICIENT_SCOPE);
- errorObjectMap.put(OAuth2Error.INVALID_TOKEN,
+ tokenErrorObjectMap.put(OAuth2Error.INVALID_TOKEN,
BearerTokenError.INVALID_TOKEN);
+ tokenErrorObjectMap.put(OAuth2Error.INVALID_REQUEST,
+ BearerTokenError.INVALID_REQUEST);
}
public OpenIdResponseHandler (AuditingIface iface) {
@@ -140,4 +146,71 @@
}
+ public void createTokenErrorResponse (KustvaktException e) {
+
+ String errorCode = e.getEntity();
+ ErrorObject errorObject = tokenErrorObjectMap.get(errorCode);
+ if (errorObject == null) {
+ errorObject = errorObjectMap.get(errorCode);
+ if (errorObject == null) {
+ errorObject = new ErrorObject(e.getEntity(), e.getMessage());
+ }
+ }
+
+ TokenErrorResponse errorResponse = new TokenErrorResponse(errorObject);
+ Status status = determineErrorStatus(errorCode);
+ createResponse(errorResponse, status);
+ }
+
+ public Response createResponse (AccessTokenResponse tokenResponse,
+ Status status) {
+ String jsonString = tokenResponse.toJSONObject().toJSONString();
+ return createResponse(status, jsonString);
+ }
+
+ public Response createResponse (TokenErrorResponse tokenResponse,
+ Status status) {
+ String jsonString = tokenResponse.toJSONObject().toJSONString();
+ return createResponse(status, jsonString);
+ }
+
+ private Response createResponse(Status status, Object entity){
+ ResponseBuilder builder = Response.status(status);
+ builder.entity(entity);
+ builder.header(HttpHeaders.CACHE_CONTROL, "no-store");
+ builder.header(HttpHeaders.PRAGMA, "no-store");
+
+ if (status == Status.UNAUTHORIZED) {
+ builder.header(HttpHeaders.WWW_AUTHENTICATE,
+ "Basic realm=\"Kustvakt\"");
+ }
+ return builder.build();
+ }
+
+ private Status determineErrorStatus (String errorCode) {
+ Status status = Status.BAD_REQUEST;
+ if (errorCode.equals(OAuth2Error.INVALID_CLIENT)
+ || errorCode.equals(OAuth2Error.UNAUTHORIZED_CLIENT)
+ || errorCode.equals(OAuth2Error.INVALID_TOKEN)) {
+ status = Status.UNAUTHORIZED;
+ }
+ else if (errorCode.equals(OAuth2Error.INVALID_GRANT)
+ || errorCode.equals(OAuth2Error.INVALID_REQUEST)
+ || errorCode.equals(OAuth2Error.INVALID_SCOPE)
+ || errorCode.equals(OAuth2Error.UNSUPPORTED_GRANT_TYPE)
+ || errorCode.equals(OAuth2Error.UNSUPPORTED_RESPONSE_TYPE)
+ || errorCode.equals(OAuth2Error.ACCESS_DENIED)) {
+ status = Status.BAD_REQUEST;
+ }
+ else if (errorCode.equals(OAuth2Error.INSUFFICIENT_SCOPE)) {
+ status = Status.FORBIDDEN;
+ }
+ else if (errorCode.equals(OAuth2Error.SERVER_ERROR)) {
+ status = Status.INTERNAL_SERVER_ERROR;
+ }
+ else if (errorCode.equals(OAuth2Error.TEMPORARILY_UNAVAILABLE)) {
+ status = Status.SERVICE_UNAVAILABLE;
+ }
+ return status;
+ }
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2Controller.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2Controller.java
index 6614f11..3726f17 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2Controller.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2Controller.java
@@ -25,9 +25,9 @@
import com.sun.jersey.spi.container.ResourceFilters;
import de.ids_mannheim.korap.exceptions.KustvaktException;
-import de.ids_mannheim.korap.oauth2.OAuth2AuthorizationRequest;
+import de.ids_mannheim.korap.oauth2.oltu.OAuth2AuthorizationRequest;
import de.ids_mannheim.korap.oauth2.oltu.service.OltuAuthorizationService;
-import de.ids_mannheim.korap.oauth2.service.OAuth2TokenService;
+import de.ids_mannheim.korap.oauth2.oltu.service.OltuTokenService;
import de.ids_mannheim.korap.security.context.TokenContext;
import de.ids_mannheim.korap.web.OAuth2ResponseHandler;
import de.ids_mannheim.korap.web.filter.AuthenticationFilter;
@@ -41,7 +41,7 @@
@Autowired
private OAuth2ResponseHandler responseHandler;
@Autowired
- private OAuth2TokenService oAuth2Service;
+ private OltuTokenService tokenService;
@Autowired
private OltuAuthorizationService authorizationService;
@@ -74,6 +74,7 @@
public Response requestAuthorizationCode (
@Context HttpServletRequest request,
@Context SecurityContext context,
+ @FormParam("state") String state,
MultivaluedMap<String, String> form) {
TokenContext tokenContext = (TokenContext) context.getUserPrincipal();
@@ -89,13 +90,13 @@
return responseHandler.sendRedirect(uri);
}
catch (OAuthSystemException e) {
- throw responseHandler.throwit(e);
+ throw responseHandler.throwit(e, state);
}
catch (OAuthProblemException e) {
- throw responseHandler.throwit(e);
+ throw responseHandler.throwit(e, state);
}
catch (KustvaktException e) {
- throw responseHandler.throwit(e);
+ throw responseHandler.throwit(e, state);
}
}
@@ -167,7 +168,7 @@
}
OAuthResponse oAuthResponse =
- oAuth2Service.requestAccessToken(oAuthRequest);
+ tokenService.requestAccessToken(oAuthRequest);
return responseHandler.createResponse(oAuthResponse);
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2WithOpenIdController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2WithOpenIdController.java
index 82affd6..d0e69d7 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2WithOpenIdController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2WithOpenIdController.java
@@ -1,6 +1,8 @@
package de.ids_mannheim.korap.web.controller;
+import java.net.MalformedURLException;
import java.net.URI;
+import java.net.URL;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
@@ -13,18 +15,24 @@
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
+import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.SecurityContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
+import com.nimbusds.oauth2.sdk.AccessTokenResponse;
import com.nimbusds.oauth2.sdk.ParseException;
import com.nimbusds.oauth2.sdk.ResponseMode;
+import com.nimbusds.oauth2.sdk.TokenRequest;
+import com.nimbusds.oauth2.sdk.http.HTTPRequest.Method;
import com.nimbusds.oauth2.sdk.id.State;
import com.sun.jersey.spi.container.ResourceFilters;
import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.oauth2.openid.OpenIdHttpRequestWrapper;
import de.ids_mannheim.korap.oauth2.openid.service.OpenIdAuthorizationService;
+import de.ids_mannheim.korap.oauth2.openid.service.OpenIdTokenService;
import de.ids_mannheim.korap.security.context.TokenContext;
import de.ids_mannheim.korap.web.OpenIdResponseHandler;
import de.ids_mannheim.korap.web.filter.AuthenticationFilter;
@@ -38,6 +46,8 @@
@Autowired
private OpenIdAuthorizationService authzService;
@Autowired
+ private OpenIdTokenService tokenService;
+ @Autowired
private OpenIdResponseHandler openIdResponseHandler;
/**
@@ -132,4 +142,46 @@
return builder.build();
}
+
+ @POST
+ @Path("token")
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
+ public Response requestAccessToken (
+ @Context HttpServletRequest servletRequest,
+ MultivaluedMap<String, String> form) {
+
+ Map<String, String> map = MapUtils.toMap(form);
+ Method method = Method.valueOf(servletRequest.getMethod());
+ URL url = null;
+ try {
+ url = new URL(servletRequest.getRequestURL().toString());
+ }
+ catch (MalformedURLException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ try {
+ OpenIdHttpRequestWrapper httpRequest =
+ new OpenIdHttpRequestWrapper(method, url);
+ httpRequest.toHttpRequest(servletRequest, map);
+
+ TokenRequest tokenRequest = TokenRequest.parse(httpRequest);
+ AccessTokenResponse tokenResponse =
+ tokenService.requestAccessToken(tokenRequest);
+ return openIdResponseHandler.createResponse(tokenResponse,
+ Status.OK);
+ }
+ catch (ParseException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ catch (KustvaktException e) {
+ openIdResponseHandler.createTokenErrorResponse(e);
+ }
+
+ return null;
+
+ }
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuthClientController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuthClientController.java
index cb00c12..2c36ad6 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuthClientController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuthClientController.java
@@ -23,7 +23,7 @@
import de.ids_mannheim.korap.dto.OAuth2ClientDto;
import de.ids_mannheim.korap.exceptions.KustvaktException;
-import de.ids_mannheim.korap.oauth2.OAuth2DeregisterClientRequest;
+import de.ids_mannheim.korap.oauth2.oltu.OAuth2DeregisterClientRequest;
import de.ids_mannheim.korap.oauth2.service.OAuth2ClientService;
import de.ids_mannheim.korap.security.context.TokenContext;
import de.ids_mannheim.korap.web.OAuth2ResponseHandler;
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ControllerTest.java
index f7aa89a..97efe8d 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ControllerTest.java
@@ -77,6 +77,7 @@
form.add("response_type", "code");
form.add("client_id", "fCBbQkAyYzI4NzUxMg");
form.add("redirect_uri", redirectUri);
+ form.add("state", "thisIsMyState");
ClientResponse response = requestAuthorizationConfidentialClient(form);
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
@@ -87,13 +88,15 @@
node.at("/error").asText());
assertEquals("Invalid redirect URI",
node.at("/error_description").asText());
+ assertEquals("thisIsMyState", node.at("/state").asText());
}
@Test
public void testAuthorizeMissingRequiredParameters ()
throws KustvaktException {
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
- // missing code
+ form.add("state", "thisIsMyState");
+ // missing response_type
ClientResponse response = requestAuthorizationConfidentialClient(form);
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
@@ -104,6 +107,7 @@
node.at("/error").asText());
assertEquals("Missing response_type parameter value",
node.at("/error_description").asText());
+ assertEquals("thisIsMyState", node.at("/state").asText());
// missing client_id
form.add("response_type", "code");
@@ -118,7 +122,8 @@
public void testAuthorizeInvalidResponseType () throws KustvaktException {
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
form.add("response_type", "string");
-
+ form.add("state", "thisIsMyState");
+
ClientResponse response = requestAuthorizationConfidentialClient(form);
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
@@ -128,6 +133,7 @@
node.at("/error").asText());
assertEquals("Invalid response_type parameter value",
node.at("/error_description").asText());
+ assertEquals("thisIsMyState", node.at("/state").asText());
}
@Test
@@ -136,7 +142,8 @@
form.add("response_type", "code");
form.add("client_id", "fCBbQkAyYzI4NzUxMg");
form.add("scope", "read_address");
-
+ form.add("state", "thisIsMyState");
+
ClientResponse response = requestAuthorizationConfidentialClient(form);
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
@@ -145,6 +152,7 @@
UriComponentsBuilder.fromUri(location).build().getQueryParams();
assertEquals(OAuth2Error.INVALID_SCOPE, params.getFirst("error"));
assertEquals("read_address+is+an+invalid+scope", params.getFirst("error_description"));
+ assertEquals("thisIsMyState", params.getFirst("state"));
}
private ClientResponse requestToken (MultivaluedMap<String, String> form)
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2OpenIdControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2OpenIdControllerTest.java
index d4a337d..c4156d6 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2OpenIdControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2OpenIdControllerTest.java
@@ -9,6 +9,7 @@
import javax.ws.rs.core.MultivaluedMap;
import org.apache.http.entity.ContentType;
+import org.apache.oltu.oauth2.common.message.types.TokenType;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.MultiValueMap;
@@ -47,6 +48,15 @@
ContentType.APPLICATION_FORM_URLENCODED)
.entity(form).post(ClientResponse.class);
}
+
+ private ClientResponse sendTokenRequest (MultivaluedMap<String, String> form)
+ throws KustvaktException {
+ return resource().path("oauth2").path("openid").path("token")
+ .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+ .header(HttpHeaders.CONTENT_TYPE,
+ ContentType.APPLICATION_FORM_URLENCODED)
+ .entity(form).post(ClientResponse.class);
+ }
@Test
public void testRequestAuthorizationCode ()
@@ -176,4 +186,40 @@
assertEquals("unsupported+response_type%3A+id_token",
params.getFirst("error_description"));
}
+
+ @Test
+ public void testRequestAccessToken () throws KustvaktException {
+ MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+ form.add("response_type", "code");
+ form.add("client_id", "fCBbQkAyYzI4NzUxMg");
+ form.add("redirect_uri", redirectUri);
+ form.add("scope", "openid");
+ form.add("state", "thisIsMyState");
+
+ ClientResponse response = sendAuthorizationRequest(form);
+ URI location = response.getLocation();
+ MultiValueMap<String, String> params =
+ UriComponentsBuilder.fromUri(location).build().getQueryParams();
+ String code = params.getFirst("code");
+
+ MultivaluedMap<String, String> tokenForm = new MultivaluedMapImpl();
+ tokenForm.add("grant_type", "authorization_code");
+ tokenForm.add("redirect_uri", redirectUri);
+ tokenForm.add("client_id", "fCBbQkAyYzI4NzUxMg");
+ tokenForm.add("client_secret", "secret");
+ tokenForm.add("code", code);
+
+ ClientResponse tokenResponse = sendTokenRequest(tokenForm);
+ String entity = tokenResponse.getEntity(String.class);
+// System.out.println(entity);
+
+ JsonNode node = JsonUtils.readTree(entity);
+ assertNotNull(node.at("/access_token").asText());
+ assertNotNull(node.at("/refresh_token").asText());
+ assertEquals(TokenType.BEARER.toString(),
+ node.at("/token_type").asText());
+ assertNotNull(node.at("/expires_in").asText());
+ assertNotNull(node.at("/id_token").asText());
+
+ }
}