Repository: cxf Updated Branches: refs/heads/master 89cdf0a99 -> 5239e3a36
Cleaning up AbstractImplicitService and prototyping the code to deal with id_token response type in OidcImplicitService, not complete yet Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/5239e3a3 Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/5239e3a3 Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/5239e3a3 Branch: refs/heads/master Commit: 5239e3a36abed124856276e36cc2384f32e22c38 Parents: 89cdf0a Author: Sergey Beryozkin <sberyoz...@gmail.com> Authored: Fri Feb 5 13:32:33 2016 +0000 Committer: Sergey Beryozkin <sberyoz...@gmail.com> Committed: Fri Feb 5 13:32:33 2016 +0000 ---------------------------------------------------------------------- .../services/AbstractImplicitGrantService.java | 84 ++++++++------------ .../services/AuthorizationCodeGrantService.java | 7 +- .../services/RedirectionBasedGrantService.java | 21 ++++- .../security/oidc/idp/OidcImplicitService.java | 48 +++++++++-- 4 files changed, 94 insertions(+), 66 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/5239e3a3/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AbstractImplicitGrantService.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AbstractImplicitGrantService.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AbstractImplicitGrantService.java index 5133374..f3c466b 100644 --- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AbstractImplicitGrantService.java +++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AbstractImplicitGrantService.java @@ -63,26 +63,18 @@ public abstract class AbstractImplicitGrantService extends RedirectionBasedGrant UserSubject userSubject, ServerAccessToken preAuthorizedToken) { - boolean tokenCanBeReturned = preAuthorizedToken != null; ServerAccessToken token = null; if (preAuthorizedToken == null) { - tokenCanBeReturned = canAccessTokenBeReturned(state, requestedScope, approvedScope); - if (tokenCanBeReturned) { - AccessTokenRegistration reg = new AccessTokenRegistration(); - reg.setClient(client); - reg.setGrantType(super.getSupportedGrantType()); - reg.setSubject(userSubject); - reg.setRequestedScope(requestedScope); - if (approvedScope == null || approvedScope.isEmpty()) { - // no down-scoping done by a user, all of the requested scopes have been authorized - reg.setApprovedScope(requestedScope); - } else { - reg.setApprovedScope(approvedScope); - } - reg.setAudiences(Collections.singletonList(state.getAudience())); - reg.setNonce(state.getNonce()); - token = getDataProvider().createAccessToken(reg); - } + AccessTokenRegistration reg = new AccessTokenRegistration(); + reg.setClient(client); + reg.setGrantType(super.getSupportedGrantType()); + reg.setSubject(userSubject); + reg.setRequestedScope(requestedScope); + reg.setApprovedScope(getApprovedScope(requestedScope, approvedScope)); + + reg.setAudiences(Collections.singletonList(state.getAudience())); + reg.setNonce(state.getNonce()); + token = getDataProvider().createAccessToken(reg); } else { token = preAuthorizedToken; if (state.getNonce() != null) { @@ -90,39 +82,20 @@ public abstract class AbstractImplicitGrantService extends RedirectionBasedGrant } } - ClientAccessToken clientToken = null; - if (token != null) { - clientToken = OAuthUtils.toClientAccessToken(token, isWriteOptionalParameters()); - } else { - // this is not ideal - it is only done to have OIDC Implicit to have an id_token added - // via AccessTokenResponseFilter. Note if id_token is needed (with or without access token) - // then the service needs to be injected with SubjectCreator, example, DefaultSubjectCreator - // extension which will have a chance to attach id_token to Subject properties which are checked - // by id_token AccessTokenResponseFilter. If at is also needed then OAuthDataProvider may deal - // with attaching id_token itself in which case no SubjectCreator injection is necessary - clientToken = new ClientAccessToken(); - } + ClientAccessToken clientToken = OAuthUtils.toClientAccessToken(token, isWriteOptionalParameters()); processClientAccessToken(clientToken, token); - + // return the token by appending it as a fragment parameter to the redirect URI StringBuilder sb = getUriWithFragment(state.getRedirectUri()); - if (tokenCanBeReturned) { - sb.append(OAuthConstants.ACCESS_TOKEN).append("=").append(clientToken.getTokenKey()); - sb.append("&"); - sb.append(OAuthConstants.ACCESS_TOKEN_TYPE).append("=").append(clientToken.getTokenType()); - } - if (state.getState() != null) { - sb.append("&"); - sb.append(OAuthConstants.STATE).append("=").append(state.getState()); - } + sb.append(OAuthConstants.ACCESS_TOKEN).append("=").append(clientToken.getTokenKey()); + sb.append("&"); + sb.append(OAuthConstants.ACCESS_TOKEN_TYPE).append("=").append(clientToken.getTokenType()); if (isWriteOptionalParameters()) { - if (tokenCanBeReturned) { - sb.append("&").append(OAuthConstants.ACCESS_TOKEN_EXPIRES_IN) - .append("=").append(clientToken.getExpiresIn()); - } + sb.append("&").append(OAuthConstants.ACCESS_TOKEN_EXPIRES_IN) + .append("=").append(clientToken.getExpiresIn()); if (!StringUtils.isEmpty(clientToken.getApprovedScope())) { sb.append("&").append(OAuthConstants.SCOPE).append("=") .append(HttpUtils.queryEncode(clientToken.getApprovedScope())); @@ -131,20 +104,25 @@ public abstract class AbstractImplicitGrantService extends RedirectionBasedGrant sb.append("&").append(entry.getKey()).append("=").append(HttpUtils.queryEncode(entry.getValue())); } } - if (tokenCanBeReturned && token.getRefreshToken() != null) { + if (token.getRefreshToken() != null) { processRefreshToken(sb, token.getRefreshToken()); } + + return finalizeResponse(sb, state); + } + + protected Response finalizeResponse(StringBuilder sb, OAuthRedirectionState state) { + if (state.getState() != null) { + sb.append("&"); + sb.append(OAuthConstants.STATE).append("=").append(state.getState()); + } if (reportClientId) { - sb.append("&").append(OAuthConstants.CLIENT_ID).append("=").append(client.getClientId()); + sb.append("&").append(OAuthConstants.CLIENT_ID).append("=").append(state.getClientId()); } return Response.seeOther(URI.create(sb.toString())).build(); } - protected boolean canAccessTokenBeReturned(OAuthRedirectionState state, - List<String> requestedScope, - List<String> approvedScope) { - return true; - } + protected void processRefreshToken(StringBuilder sb, String refreshToken) { LOG.warning("Implicit grant tokens MUST not have refresh tokens, refresh token will not be reported"); } @@ -167,13 +145,13 @@ public abstract class AbstractImplicitGrantService extends RedirectionBasedGrant return Response.seeOther(URI.create(sb.toString())).build(); } - private StringBuilder getUriWithFragment(String redirectUri) { + protected StringBuilder getUriWithFragment(String redirectUri) { StringBuilder sb = new StringBuilder(); sb.append(redirectUri); sb.append("#"); return sb; } - + public void setReportClientId(boolean reportClientId) { this.reportClientId = reportClientId; } http://git-wip-us.apache.org/repos/asf/cxf/blob/5239e3a3/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AuthorizationCodeGrantService.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AuthorizationCodeGrantService.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AuthorizationCodeGrantService.java index 138a600..d8191e8 100644 --- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AuthorizationCodeGrantService.java +++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AuthorizationCodeGrantService.java @@ -107,12 +107,7 @@ public class AuthorizationCodeGrantService extends RedirectionBasedGrantService codeReg.setClient(client); codeReg.setRedirectUri(state.getRedirectUri()); codeReg.setRequestedScope(requestedScope); - if (approvedScope == null || approvedScope.isEmpty()) { - // no down-scoping done by a user, all of the requested scopes have been authorized - codeReg.setApprovedScope(requestedScope); - } else { - codeReg.setApprovedScope(approvedScope); - } + codeReg.setApprovedScope(getApprovedScope(requestedScope, approvedScope)); codeReg.setSubject(userSubject); codeReg.setAudience(state.getAudience()); codeReg.setNonce(state.getNonce()); http://git-wip-us.apache.org/repos/asf/cxf/blob/5239e3a3/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/RedirectionBasedGrantService.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/RedirectionBasedGrantService.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/RedirectionBasedGrantService.java index 597f7ea..8c188be 100644 --- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/RedirectionBasedGrantService.java +++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/RedirectionBasedGrantService.java @@ -169,8 +169,11 @@ public abstract class RedirectionBasedGrantService extends AbstractOAuthService } // Request a new grant only if no pre-authorized token is available - ServerAccessToken preAuthorizedToken = getDataProvider().getPreauthorizedToken( - client, requestedScope, userSubject, supportedGrantType); + ServerAccessToken preAuthorizedToken = null; + if (canAccessTokenBeReturned(responseType)) { + preAuthorizedToken = getDataProvider().getPreauthorizedToken(client, requestedScope, userSubject, + supportedGrantType); + } List<OAuthPermission> alreadyAuthorizedPerms = null; boolean preAuthorizationComplete = false; @@ -290,6 +293,15 @@ public abstract class RedirectionBasedGrantService extends AbstractOAuthService } } + protected List<String> getApprovedScope(List<String> requestedScope, List<String> approvedScope) { + if (StringUtils.isEmpty(approvedScope)) { + // no down-scoping done by a user, all of the requested scopes have been authorized + return requestedScope; + } else { + return approvedScope; + } + } + /** * Completes the authorization process */ @@ -371,6 +383,11 @@ public abstract class RedirectionBasedGrantService extends AbstractOAuthService String error) { return createErrorResponse(params.getFirst(OAuthConstants.STATE), redirectUri, error); } + + protected boolean canAccessTokenBeReturned(String responseType) { + return true; + } + protected abstract Response createErrorResponse(String state, String redirectUri, String error); http://git-wip-us.apache.org/repos/asf/cxf/blob/5239e3a3/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/idp/OidcImplicitService.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/idp/OidcImplicitService.java b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/idp/OidcImplicitService.java index b53c352..01ae147 100644 --- a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/idp/OidcImplicitService.java +++ b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/idp/OidcImplicitService.java @@ -29,10 +29,13 @@ import org.apache.cxf.rs.security.oauth2.common.Client; import org.apache.cxf.rs.security.oauth2.common.OAuthError; import org.apache.cxf.rs.security.oauth2.common.OAuthPermission; import org.apache.cxf.rs.security.oauth2.common.OAuthRedirectionState; +import org.apache.cxf.rs.security.oauth2.common.ServerAccessToken; import org.apache.cxf.rs.security.oauth2.common.UserSubject; import org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException; import org.apache.cxf.rs.security.oauth2.services.ImplicitGrantService; import org.apache.cxf.rs.security.oauth2.utils.OAuthConstants; +import org.apache.cxf.rs.security.oidc.common.IdToken; +import org.apache.cxf.rs.security.oidc.utils.OidcUtils; public class OidcImplicitService extends ImplicitGrantService { @@ -47,11 +50,8 @@ public class OidcImplicitService extends ImplicitGrantService { } @Override - protected boolean canAccessTokenBeReturned(OAuthRedirectionState state, - List<String> requestedScope, - List<String> approvedScope) { - return state.getResponseType() != null - && state.getResponseType().contains(ID_TOKEN_AND_AT_RESPONSE_TYPE); + protected boolean canAccessTokenBeReturned(String responseType) { + return ID_TOKEN_AND_AT_RESPONSE_TYPE.equals(responseType); } @Override @@ -80,4 +80,42 @@ public class OidcImplicitService extends ImplicitGrantService { this.skipAuthorizationWithOidcScope = skipAuthorizationWithOidcScope; } + protected Response createGrant(OAuthRedirectionState state, + Client client, + List<String> requestedScope, + List<String> approvedScope, + UserSubject userSubject, + ServerAccessToken preAuthorizedToken) { + + if (canAccessTokenBeReturned(state.getResponseType())) { + return super.createGrant(state, client, requestedScope, approvedScope, userSubject, preAuthorizedToken); + } + // id_token response type processing + + StringBuilder sb = getUriWithFragment(state.getRedirectUri()); + + String idToken = getProcessedIdToken(state, userSubject); + if (idToken != null) { + sb.append(OidcUtils.ID_TOKEN).append("=").append(idToken); + } + if (state.getState() != null) { + sb.append("&"); + sb.append(OAuthConstants.STATE).append("=").append(state.getState()); + } + return finalizeResponse(sb, state); + } + + private String getProcessedIdToken(OAuthRedirectionState state, UserSubject subject) { + if (subject.getProperties().containsKey(OidcUtils.ID_TOKEN)) { + return subject.getProperties().get(OidcUtils.ID_TOKEN); + } else if (subject instanceof OidcUserSubject) { + OidcUserSubject sub = (OidcUserSubject)subject; + IdToken idToken = new IdToken(sub.getIdToken()); + idToken.setNonce(state.getNonce()); + return null; //super.processJwt(new JwtToken(idToken)); + } else { + return null; + } + } + }