Updated token response using Nimbus (#650)
Change-Id: Id33f3f4422da63f24d430e4f8d0a6618edf8ec2e
diff --git a/full/Changes b/full/Changes
index 8d030e7..b31f263 100644
--- a/full/Changes
+++ b/full/Changes
@@ -18,6 +18,7 @@
- Removed Apache Oltu API from token requests (#650)
- Removed OpenID
- Fixed clearing cache
+- Updated token response using Nimbus (#650)
# version 0.71
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 40ef907..3e43fcd 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
@@ -12,13 +12,10 @@
import java.util.Map;
import java.util.Set;
-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.TokenType;
import org.springframework.beans.factory.annotation.Autowired;
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;
@@ -26,11 +23,8 @@
import com.nimbusds.oauth2.sdk.ResourceOwnerPasswordCredentialsGrant;
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.id.ClientID;
+import com.nimbusds.oauth2.sdk.token.BearerAccessToken;
+import com.nimbusds.oauth2.sdk.token.Tokens;
import com.unboundid.ldap.sdk.LDAPException;
import de.ids_mannheim.korap.authentication.AuthenticationManager;
@@ -50,11 +44,7 @@
import de.ids_mannheim.korap.oauth2.entity.Authorization;
import de.ids_mannheim.korap.oauth2.entity.OAuth2Client;
import de.ids_mannheim.korap.oauth2.entity.RefreshToken;
-import de.ids_mannheim.korap.oauth2.oltu.OAuth2RevokeAllTokenSuperRequest;
-import de.ids_mannheim.korap.oauth2.oltu.OAuth2RevokeTokenRequest;
-import de.ids_mannheim.korap.oauth2.oltu.OAuth2RevokeTokenSuperRequest;
import jakarta.persistence.NoResultException;
-import jakarta.ws.rs.core.Response.Status;
/**
* OAuth2TokenService manages business logic related to OAuth2
@@ -103,7 +93,6 @@
* client_secret, required if client_secret was issued
* for the client in client registration.
* @return an authorization
- * @throws OAuthSystemException
* @throws KustvaktException
*/
protected Authorization retrieveAuthorization (
@@ -149,9 +138,9 @@
return authenticationTime;
}
- public OAuthResponse requestAccessToken (
+ public AccessTokenResponse requestAccessToken (
TokenRequest tokenRequest, String clientId, String clientSecret)
- throws KustvaktException, OAuthSystemException {
+ throws KustvaktException {
AuthorizationGrant authGrant = tokenRequest.getAuthorizationGrant();
GrantType grantType = authGrant.getType();
@@ -215,12 +204,11 @@
* @param clientSecret
* @return if successful, a new access token
* @throws KustvaktException
- * @throws OAuthSystemException
*/
- private OAuthResponse requestAccessTokenWithRefreshToken (
+ private AccessTokenResponse requestAccessTokenWithRefreshToken (
String refreshTokenStr, Set<String> requestScopes, String clientId,
String clientSecret)
- throws KustvaktException, OAuthSystemException {
+ throws KustvaktException {
if (refreshTokenStr == null || refreshTokenStr.isEmpty()) {
throw new KustvaktException(StatusCodes.MISSING_PARAMETER,
@@ -292,13 +280,12 @@
* client id, required
* @param clientSecret
* client secret, required
- * @return an {@link OAuthResponse}
- * @throws OAuthSystemException
+ * @return an {@link AccessTokenResponse}
* @throws KustvaktException
*/
- private OAuthResponse requestAccessTokenWithAuthorizationCode (String code,
+ private AccessTokenResponse requestAccessTokenWithAuthorizationCode (String code,
String redirectionURI, String clientId, String clientSecret)
- throws OAuthSystemException, KustvaktException {
+ throws KustvaktException {
Authorization authorization = retrieveAuthorization(code, redirectionURI,
clientId, clientSecret);
@@ -336,13 +323,12 @@
* password, required
* @param scopes
* authorization scopes, optional
- * @return an {@link OAuthResponse}
+ * @return an {@link AccessTokenResponse}
* @throws KustvaktException
- * @throws OAuthSystemException
*/
- private OAuthResponse requestAccessTokenWithPassword (String clientId,
+ private AccessTokenResponse requestAccessTokenWithPassword (String clientId,
String clientSecret, String username, String password,
- Set<String> scopes) throws KustvaktException, OAuthSystemException {
+ Set<String> scopes) throws KustvaktException {
OAuth2Client client =
clientService.authenticateClient(clientId, clientSecret);
@@ -390,13 +376,12 @@
* client_secret parameter, required
* @param scopes
* authorization scopes, optional
- * @return an {@link OAuthResponse}
+ * @return an {@link AccessTokenResponse}
* @throws KustvaktException
- * @throws OAuthSystemException
*/
- protected OAuthResponse requestAccessTokenWithClientCredentials (
+ protected AccessTokenResponse requestAccessTokenWithClientCredentials (
String clientId, String clientSecret, Set<String> scopes)
- throws KustvaktException, OAuthSystemException {
+ throws KustvaktException {
if (clientSecret == null || clientSecret.isEmpty()) {
throw new KustvaktException(
@@ -428,7 +413,7 @@
}
/**
- * Creates an OAuthResponse containing an access token of type
+ * Creates an OAuth response containing an access token of type
* Bearer. By default, MD generator is used to generates access
* token of 128 bit values, represented in hexadecimal comprising
* 32 bytes. The generated value is subsequently encoded in
@@ -449,67 +434,59 @@
* a user id
* @param authenticationTime
* the user authentication time
- * @return an {@link OAuthResponse}
- * @throws OAuthSystemException
+ * @return an {@link AccessTokenResponse}
* @throws KustvaktException
*/
- private OAuthResponse createsAccessTokenResponse (Set<String> scopes,
+ private AccessTokenResponse createsAccessTokenResponse (Set<String> scopes,
Set<AccessScope> accessScopes, String clientId, String userId,
ZonedDateTime authenticationTime, OAuth2Client client)
- throws OAuthSystemException, KustvaktException {
+ throws KustvaktException {
String random = randomGenerator.createRandomCode();
random += randomGenerator.createRandomCode();
- if (clientService.isPublicClient(client)){
+ if (clientService.isPublicClient(client)) {
// refresh token == null, getAccessTokenLongExpiry
- return createsAccessTokenResponse(scopes, accessScopes, clientId,
- userId, authenticationTime);
- }
+ return createsAccessTokenResponse(null, scopes, accessScopes,
+ clientId, userId, authenticationTime);
+ }
else {
// refresh token != null, getAccessTokenExpiry
// default refresh token expiry: 365 days in seconds
RefreshToken refreshToken = refreshDao.storeRefreshToken(random,
userId, authenticationTime, client, accessScopes);
- return createsAccessTokenResponse(scopes, accessScopes, clientId,
- userId, authenticationTime, refreshToken);
+ return createsAccessTokenResponse(refreshToken, scopes,
+ accessScopes, clientId, userId, authenticationTime);
}
}
- private OAuthResponse createsAccessTokenResponse (Set<String> scopes,
+ private AccessTokenResponse createsAccessTokenResponse (
+ RefreshToken refreshToken, Set<String> scopes,
Set<AccessScope> accessScopes, String clientId, String userId,
- ZonedDateTime authenticationTime, RefreshToken refreshToken)
- throws OAuthSystemException, KustvaktException {
+ ZonedDateTime authenticationTime) throws KustvaktException {
String accessToken = randomGenerator.createRandomCode();
accessToken +=randomGenerator.createRandomCode();
tokenDao.storeAccessToken(accessToken, refreshToken, accessScopes,
userId, clientId, authenticationTime);
- return OAuthASResponse.tokenResponse(Status.OK.getStatusCode())
- .setAccessToken(accessToken)
- .setTokenType(TokenType.BEARER.toString())
- .setExpiresIn(String.valueOf(config.getAccessTokenExpiry()))
- .setRefreshToken(refreshToken.getToken())
- .setScope(String.join(" ", scopes)).buildJSONMessage();
- }
-
- private OAuthResponse createsAccessTokenResponse (Set<String> scopes,
- Set<AccessScope> accessScopes, String clientId, String userId,
- ZonedDateTime authenticationTime)
- throws OAuthSystemException, KustvaktException {
+ Tokens tokens = null;
+ if (refreshToken !=null) {
+ BearerAccessToken bearerToken = new BearerAccessToken(accessToken,
+ (long) config.getAccessTokenExpiry(), Scope.parse(scopes));
+ com.nimbusds.oauth2.sdk.token.RefreshToken rf =
+ new com.nimbusds.oauth2.sdk.token.RefreshToken(
+ refreshToken.getToken());
+ tokens = new Tokens(bearerToken, rf);
+ }
+ else {
+ BearerAccessToken bearerToken = new BearerAccessToken(accessToken,
+ (long) config.getAccessTokenLongExpiry(), Scope.parse(scopes));
+ tokens = new Tokens(bearerToken, null);
+ }
+ return new AccessTokenResponse(tokens);
+ }
- String accessToken = randomGenerator.createRandomCode();
- accessToken +=randomGenerator.createRandomCode();
- tokenDao.storeAccessToken(accessToken, null, accessScopes,
- userId, clientId, authenticationTime);
-
- return OAuthASResponse.tokenResponse(Status.OK.getStatusCode())
- .setAccessToken(accessToken)
- .setTokenType(TokenType.BEARER.toString())
- .setExpiresIn(String.valueOf(config.getAccessTokenLongExpiry()))
- .setScope(String.join(" ", scopes)).buildJSONMessage();
- }
public void revokeToken (String clientId, String clientSecret,
String token, String tokenType) throws KustvaktException {
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 077383f..9ece449 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
@@ -9,7 +9,13 @@
import org.apache.oltu.oauth2.common.message.OAuthResponse;
import org.apache.oltu.oauth2.common.message.OAuthResponse.OAuthErrorResponseBuilder;
+import com.nimbusds.oauth2.sdk.AccessTokenResponse;
+import com.nimbusds.oauth2.sdk.AuthorizationErrorResponse;
+import com.nimbusds.oauth2.sdk.ErrorObject;
+import com.nimbusds.oauth2.sdk.ErrorResponse;
import com.nimbusds.oauth2.sdk.OAuth2Error;
+import com.nimbusds.oauth2.sdk.TokenErrorResponse;
+import com.nimbusds.oauth2.sdk.id.State;
import de.ids_mannheim.korap.exceptions.KustvaktException;
import de.ids_mannheim.korap.exceptions.StatusCodes;
@@ -69,9 +75,12 @@
catch (OAuthSystemException e1) {
throwit(e1, state);
}
- Response r = createResponse(oAuthResponse);
+ Response r = createResponse(oAuthResponse.getResponseStatus(),
+ oAuthResponse.getBody(), oAuthResponse.getLocationUri());
return new WebApplicationException(r);
}
+
+
@Override
public WebApplicationException throwit (KustvaktException e){
@@ -136,6 +145,19 @@
}
return ex;
}
+
+ private ErrorResponse createErrorResponse (
+ KustvaktException e, String statusCode, String state){
+ ErrorResponse r = null;
+
+ if (e.getRedirectUri()!=null) {
+ ErrorObject eo = new ErrorObject(statusCode, e.getMessage());
+ State s = new State(state);
+ r = new AuthorizationErrorResponse(e.getRedirectUri(), eo, s, null);
+ }
+
+ return r;
+ }
/**
* RFC 6749 regarding authorization error response:
@@ -156,19 +178,18 @@
* @param oAuthResponse
* @return
*/
- public Response createResponse (OAuthResponse oAuthResponse) {
+ public Response createResponse (int status, String body, String uri) {
ResponseBuilder builder =
- Response.status(oAuthResponse.getResponseStatus());
- builder.entity(oAuthResponse.getBody());
+ Response.status(status);
+ builder.entity(body);
builder.header(HttpHeaders.CACHE_CONTROL, "no-store");
builder.header(HttpHeaders.PRAGMA, "no-store");
- if (oAuthResponse.getResponseStatus() == Status.UNAUTHORIZED
+ if (status == Status.UNAUTHORIZED
.getStatusCode()) {
builder.header(HttpHeaders.WWW_AUTHENTICATE,
"Basic realm=\"Kustvakt\"");
}
- String uri = oAuthResponse.getLocationUri();
if (uri != null && !uri.isEmpty()) {
try {
builder.location(new URI(uri));
@@ -186,4 +207,28 @@
ResponseBuilder builder = Response.temporaryRedirect(locationUri);
return builder.build();
}
+
+ public Response createResponse (AccessTokenResponse tokenResponse) {
+ String jsonString = tokenResponse.toJSONObject().toJSONString();
+ return createResponse(Status.OK, 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();
+ }
}
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 0686a89..369687a 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
@@ -5,11 +5,10 @@
import java.time.ZonedDateTime;
import java.util.List;
-import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
-import org.apache.oltu.oauth2.common.message.OAuthResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
+import com.nimbusds.oauth2.sdk.AccessTokenResponse;
import com.nimbusds.oauth2.sdk.AuthorizationErrorResponse;
import com.nimbusds.oauth2.sdk.AuthorizationGrant;
import com.nimbusds.oauth2.sdk.ClientCredentialsGrant;
@@ -17,13 +16,11 @@
import com.nimbusds.oauth2.sdk.ParseException;
import com.nimbusds.oauth2.sdk.Scope;
import com.nimbusds.oauth2.sdk.TokenRequest;
-import com.nimbusds.oauth2.sdk.TokenRevocationRequest;
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.id.ClientID;
-import com.nimbusds.oauth2.sdk.token.Token;
import de.ids_mannheim.korap.constant.OAuth2Scope;
import de.ids_mannheim.korap.exceptions.KustvaktException;
@@ -265,7 +262,6 @@
@FormParam("client_secret") String clientSecret,
MultivaluedMap<String, String> form) {
- OAuthResponse oAuthResponse = null;
try {
URI requestURI;
UriBuilder builder = UriBuilder.fromPath(
@@ -315,8 +311,9 @@
Scope.parse(form.getFirst("scope")));
}
- oAuthResponse = tokenService.requestAccessToken(tokenRequest,
+ AccessTokenResponse r = tokenService.requestAccessToken(tokenRequest,
clientId, clientSecret);
+ return responseHandler.createResponse(r);
}
catch (ParseException | IllegalArgumentException e) {
throw new KustvaktException(StatusCodes.INVALID_REQUEST,
@@ -327,11 +324,6 @@
catch (KustvaktException e) {
throw responseHandler.throwit(e);
}
- catch (OAuthSystemException e) {
- throw responseHandler.throwit(e);
- }
-
- return responseHandler.createResponse(oAuthResponse);
}
/**