Repository: cxf Updated Branches: refs/heads/3.0.x-fixes 90f0da4de -> 855250af1
Updates to OAuth2 code request filters and simplifying the big_query demo code (still work in progress) Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/855250af Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/855250af Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/855250af Branch: refs/heads/3.0.x-fixes Commit: 855250af1e321cd51ec3eccb29d3a8401c1fb53f Parents: 90f0da4 Author: Sergey Beryozkin <[email protected]> Authored: Wed May 20 14:35:09 2015 +0100 Committer: Sergey Beryozkin <[email protected]> Committed: Wed May 20 14:39:55 2015 +0100 ---------------------------------------------------------------------- .../oauth2/client/ClientCodeRequestFilter.java | 74 ++++++++++++-------- .../oidc/rp/OidcClientCodeRequestFilter.java | 24 ++++++- .../security/oidc/rp/OidcSecurityContext.java | 52 ++++++++++++++ 3 files changed, 119 insertions(+), 31 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/855250af/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/client/ClientCodeRequestFilter.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/client/ClientCodeRequestFilter.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/client/ClientCodeRequestFilter.java index 2a2d298..97577d1 100644 --- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/client/ClientCodeRequestFilter.java +++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/client/ClientCodeRequestFilter.java @@ -59,16 +59,14 @@ public class ClientCodeRequestFilter implements ContainerRequestFilter { private OAuthClientUtils.Consumer consumer; private ClientCodeStateManager clientStateManager; private ClientTokenContextManager clientTokenContextManager; - private WebClient accessTokenService; + private WebClient accessTokenServiceClient; private boolean decodeRequestParameters; private long expiryThreshold; + private String redirectUri; @Override public void filter(ContainerRequestContext rc) throws IOException { - SecurityContext sc = rc.getSecurityContext(); - if (sc == null || sc.getUserPrincipal() == null) { - throw ExceptionUtils.toNotAuthorizedException(null, null); - } + checkSecurityContextStart(rc.getSecurityContext()); UriInfo ui = rc.getUriInfo(); String absoluteRequestUri = ui.getAbsolutePath().toString(); @@ -82,7 +80,7 @@ public class ClientCodeRequestFilter implements ContainerRequestFilter { } if (!sameUriRedirect && absoluteRequestUri.endsWith(startUri)) { - ClientTokenContext request = getClientTokenContext(); + ClientTokenContext request = getClientTokenContext(rc); if (request != null) { setClientCodeRequest(request); if (completeUri != null) { @@ -90,51 +88,65 @@ public class ClientCodeRequestFilter implements ContainerRequestFilter { } return; } - Response codeResponse = createCodeResponse(rc, sc, ui); + Response codeResponse = createCodeResponse(rc, ui); rc.abortWith(codeResponse); } else if (absoluteRequestUri.endsWith(completeUri)) { - processCodeResponse(rc, sc, ui); + processCodeResponse(rc, ui); + checkSecurityContextEnd(rc.getSecurityContext()); } } - private Response createCodeResponse(ContainerRequestContext rc, SecurityContext sc, UriInfo ui) { - MultivaluedMap<String, String> redirectState = createRedirectState(rc, sc, ui); - String redirectScope = redirectState.getFirst(OAuthConstants.SCOPE); + protected void checkSecurityContextStart(SecurityContext sc) { + checkSecurityContextEnd(sc); + } + private void checkSecurityContextEnd(SecurityContext sc) { + if (sc == null || sc.getUserPrincipal() == null) { + throw ExceptionUtils.toNotAuthorizedException(null, null); + } + } + + private Response createCodeResponse(ContainerRequestContext rc, UriInfo ui) { + MultivaluedMap<String, String> redirectState = createRedirectState(rc, ui); + String theState = redirectState != null ? redirectState.getFirst(OAuthConstants.SCOPE) : null; + String redirectScope = redirectState != null ? redirectState.getFirst(OAuthConstants.SCOPE) : null; String theScope = redirectScope != null ? redirectScope : scopes; URI uri = OAuthClientUtils.getAuthorizationURI(authorizationServiceUri, consumer.getKey(), getAbsoluteRedirectUri(ui).toString(), - redirectState.getFirst(OAuthConstants.STATE), + theState, theScope); return Response.seeOther(uri).build(); } private URI getAbsoluteRedirectUri(UriInfo ui) { - if (completeUri != null) { + if (redirectUri != null) { + return URI.create(redirectUri); + } else if (completeUri != null) { return completeUri.startsWith("http") ? URI.create(completeUri) : ui.getBaseUriBuilder().path(completeUri).build(); } else { return ui.getAbsolutePath(); } } - protected void processCodeResponse(ContainerRequestContext rc, SecurityContext sc, UriInfo ui) { + protected void processCodeResponse(ContainerRequestContext rc, UriInfo ui) { MultivaluedMap<String, String> params = toRequestState(rc, ui); String codeParam = params.getFirst(OAuthConstants.AUTHORIZATION_CODE_VALUE); ClientAccessToken at = null; if (codeParam != null) { AccessTokenGrant grant = new AuthorizationCodeGrant(codeParam, getAbsoluteRedirectUri(ui)); - at = OAuthClientUtils.getAccessToken(accessTokenService, consumer, grant); + at = OAuthClientUtils.getAccessToken(accessTokenServiceClient, consumer, grant); } - ClientTokenContext tokenContext = initializeClientTokenContext(at, params); + ClientTokenContext tokenContext = initializeClientTokenContext(rc, at, params); if (at != null && clientTokenContextManager != null) { clientTokenContextManager.setClientTokenContext(mc, tokenContext); } setClientCodeRequest(tokenContext); } - private ClientTokenContext initializeClientTokenContext(ClientAccessToken at, + protected ClientTokenContext initializeClientTokenContext(ContainerRequestContext rc, + ClientAccessToken at, MultivaluedMap<String, String> params) { - ClientTokenContext tokenContext = createTokenContext(at); + ClientTokenContext tokenContext = createTokenContext(rc, at); ((ClientTokenContextImpl)tokenContext).setToken(at); if (clientStateManager != null) { MultivaluedMap<String, String> state = clientStateManager.fromRedirectState(mc, params); @@ -145,7 +157,7 @@ public class ClientCodeRequestFilter implements ContainerRequestFilter { } - protected ClientTokenContext createTokenContext(ClientAccessToken at) { + protected ClientTokenContext createTokenContext(ContainerRequestContext rc, ClientAccessToken at) { return new ClientTokenContextImpl(); } @@ -153,8 +165,7 @@ public class ClientCodeRequestFilter implements ContainerRequestFilter { JAXRSUtils.getCurrentMessage().setContent(ClientTokenContext.class, request); } - private MultivaluedMap<String, String> createRedirectState(ContainerRequestContext rc, SecurityContext sc, - UriInfo ui) { + private MultivaluedMap<String, String> createRedirectState(ContainerRequestContext rc, UriInfo ui) { if (clientStateManager == null) { return null; } @@ -180,10 +191,10 @@ public class ClientCodeRequestFilter implements ContainerRequestFilter { } sb.append(s); } - setScopeString(sb.toString()); + setScopes(sb.toString()); } - public void setScopeString(String scopesString) { - this.scopes = scopesString; + public void setScopes(String scopes) { + this.scopes = scopes; } public void setStartUri(String relStartUri) { @@ -198,8 +209,8 @@ public class ClientCodeRequestFilter implements ContainerRequestFilter { this.completeUri = completeUri; } - public void setAccessTokenService(WebClient accessTokenService) { - this.accessTokenService = accessTokenService; + public void setAccessTokenServiceClient(WebClient accessTokenServiceClient) { + this.accessTokenServiceClient = accessTokenServiceClient; } public void setClientCodeStateManager(ClientCodeStateManager manager) { @@ -221,7 +232,7 @@ public class ClientCodeRequestFilter implements ContainerRequestFilter { this.decodeRequestParameters = decodeRequestParameters; } - private ClientTokenContext getClientTokenContext() { + protected ClientTokenContext getClientTokenContext(ContainerRequestContext rc) { ClientTokenContext ctx = null; if (clientTokenContextManager != null) { ctx = clientTokenContextManager.getClientTokenContext(mc); @@ -229,7 +240,7 @@ public class ClientCodeRequestFilter implements ContainerRequestFilter { ClientAccessToken newAt = refreshAccessTokenIfExpired(ctx.getToken()); if (newAt != null) { clientTokenContextManager.removeClientTokenContext(mc, ctx); - ClientTokenContext newCtx = initializeClientTokenContext(newAt, ctx.getState()); + ClientTokenContext newCtx = initializeClientTokenContext(rc, newAt, ctx.getState()); clientTokenContextManager.setClientTokenContext(mc, newCtx); ctx = newCtx; } @@ -242,7 +253,7 @@ public class ClientCodeRequestFilter implements ContainerRequestFilter { if (at.getRefreshToken() != null && ((expiryThreshold > 0 && OAuthUtils.isExpired(at.getIssuedAt(), at.getExpiresIn() - expiryThreshold)) || OAuthUtils.isExpired(at.getIssuedAt(), at.getExpiresIn()))) { - return OAuthClientUtils.refreshAccessToken(accessTokenService, consumer, at); + return OAuthClientUtils.refreshAccessToken(accessTokenServiceClient, consumer, at); } return null; } @@ -250,4 +261,9 @@ public class ClientCodeRequestFilter implements ContainerRequestFilter { public void setExpiryThreshold(long expiryThreshold) { this.expiryThreshold = expiryThreshold; } + + public void setRedirectUri(String redirectUri) { + // Can be set to something like "postmessage" in some flows + this.redirectUri = redirectUri; + } } http://git-wip-us.apache.org/repos/asf/cxf/blob/855250af/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcClientCodeRequestFilter.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcClientCodeRequestFilter.java b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcClientCodeRequestFilter.java index aba4d3c..57cc2de 100644 --- a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcClientCodeRequestFilter.java +++ b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcClientCodeRequestFilter.java @@ -18,6 +18,10 @@ */ package org.apache.cxf.rs.security.oidc.rp; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.core.SecurityContext; + +import org.apache.cxf.jaxrs.utils.ExceptionUtils; import org.apache.cxf.rs.security.oauth2.client.ClientCodeRequestFilter; import org.apache.cxf.rs.security.oauth2.client.ClientTokenContext; import org.apache.cxf.rs.security.oauth2.common.ClientAccessToken; @@ -25,16 +29,32 @@ import org.apache.cxf.rs.security.oauth2.common.ClientAccessToken; public class OidcClientCodeRequestFilter extends ClientCodeRequestFilter { private UserInfoClient userInfoClient; + private boolean userInfoRequired = true; @Override - protected ClientTokenContext createTokenContext(ClientAccessToken at) { + protected ClientTokenContext createTokenContext(ContainerRequestContext rc, ClientAccessToken at) { OidcClientTokenContextImpl ctx = new OidcClientTokenContextImpl(); if (at != null) { ctx.setIdToken(userInfoClient.getIdToken(at, getConsumer().getKey())); - ctx.setUserInfo(userInfoClient.getUserInfo(at, ctx.getIdToken())); + if (userInfoRequired) { + ctx.setUserInfo(userInfoClient.getUserInfo(at, ctx.getIdToken())); + } + rc.setSecurityContext(new OidcSecurityContext(ctx)); } + return ctx; } public void setUserInfoClient(UserInfoClient userInfoClient) { this.userInfoClient = userInfoClient; } + public void setUserInfoRequired(boolean userInfoRequired) { + this.userInfoRequired = userInfoRequired; + } + @Override + protected void checkSecurityContextStart(SecurityContext sc) { + // The SSO is managed out of band and the act of validating IdToken + // finalizes the authentication flow + if (sc != null && sc.getUserPrincipal() != null) { + throw ExceptionUtils.toNotAuthorizedException(null, null); + } + } } http://git-wip-us.apache.org/repos/asf/cxf/blob/855250af/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcSecurityContext.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcSecurityContext.java b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcSecurityContext.java new file mode 100644 index 0000000..f8b8045 --- /dev/null +++ b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcSecurityContext.java @@ -0,0 +1,52 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.rs.security.oidc.rp; + +import javax.ws.rs.core.SecurityContext; + +import org.apache.cxf.common.security.SimpleSecurityContext; +import org.apache.cxf.jaxrs.utils.HttpUtils; +import org.apache.cxf.jaxrs.utils.JAXRSUtils; + +public class OidcSecurityContext extends SimpleSecurityContext implements SecurityContext { + private OidcClientTokenContext oidcContext; + public OidcSecurityContext(OidcClientTokenContext oidcContext) { + super(getUserName(oidcContext)); + this.oidcContext = oidcContext; + } + public OidcClientTokenContext getOidcContext() { + return oidcContext; + } + private static String getUserName(OidcClientTokenContext oidcContext) { + if (oidcContext.getUserInfo() != null) { + return oidcContext.getUserInfo().getEmail(); + } else { + return oidcContext.getIdToken().getSubject(); + } + } + @Override + public boolean isSecure() { + String value = HttpUtils.getEndpointAddress(JAXRSUtils.getCurrentMessage()); + return value.startsWith("https://"); + } + @Override + public String getAuthenticationScheme() { + return "OIDC"; + } +}
