You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2015/11/05 18:21:53 UTC
cxf git commit: Some modifications to support implicit OIDC flows
Repository: cxf
Updated Branches:
refs/heads/3.1.x-fixes f7f5b3c01 -> 0d2a6ccab
Some modifications to support implicit OIDC flows
Project: http://git-wip-us.apache.org/repos/asf/cxf/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/0d2a6cca
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/0d2a6cca
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/0d2a6cca
Branch: refs/heads/3.1.x-fixes
Commit: 0d2a6ccabc752708484e2b2c44deb5b48e71b76e
Parents: f7f5b3c
Author: Sergey Beryozkin <sb...@gmail.com>
Authored: Thu Nov 5 17:21:32 2015 +0000
Committer: Sergey Beryozkin <sb...@gmail.com>
Committed: Thu Nov 5 17:21:32 2015 +0000
----------------------------------------------------------------------
.../apache/cxf/jaxrs/impl/ResponseImplTest.java | 4 +-
.../cxf/jaxrs/impl/UriBuilderImplTest.java | 7 +++
.../oauth2/provider/DefaultSubjectCreator.java | 34 ++++++++++
.../services/AbstractImplicitGrantService.java | 66 ++++++++++++++------
.../oauth2/services/ImplicitGrantService.java | 5 ++
.../services/RedirectionBasedGrantService.java | 20 +++---
.../rs/security/oauth2/utils/OAuthUtils.java | 9 ++-
.../security/oidc/idp/OidcImplicitService.java | 62 ++++++++++++++++++
8 files changed, 175 insertions(+), 32 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cxf/blob/0d2a6cca/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/ResponseImplTest.java
----------------------------------------------------------------------
diff --git a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/ResponseImplTest.java b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/ResponseImplTest.java
index b750508..d409072 100644
--- a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/ResponseImplTest.java
+++ b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/ResponseImplTest.java
@@ -367,7 +367,7 @@ public class ResponseImplTest extends Assert {
assertFalse(ri.hasLink("prev"));
assertNull(ri.getLink("prev"));
- meta.add(HttpHeaders.LINK, "<http://next>;rel=next");
+ meta.add(HttpHeaders.LINK, "<http://localhost:8080/next;a=b>;rel=next");
meta.add(HttpHeaders.LINK, "<http://prev>;rel=prev");
assertTrue(ri.hasLink("next"));
@@ -381,7 +381,7 @@ public class ResponseImplTest extends Assert {
assertTrue(links.contains(next));
assertTrue(links.contains(prev));
- assertEquals("http://next", next.getUri().toString());
+ assertEquals("http://localhost:8080/next;a=b", next.getUri().toString());
assertEquals("next", next.getRel());
assertEquals("http://prev", prev.getUri().toString());
assertEquals("prev", prev.getRel());
http://git-wip-us.apache.org/repos/asf/cxf/blob/0d2a6cca/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriBuilderImplTest.java
----------------------------------------------------------------------
diff --git a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriBuilderImplTest.java b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriBuilderImplTest.java
index a9ec843..2bf7829 100644
--- a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriBuilderImplTest.java
+++ b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriBuilderImplTest.java
@@ -1547,6 +1547,13 @@ public class UriBuilderImplTest extends Assert {
}
@Test
+ public void testFromUriWithMatrix() {
+ String expected = "http://localhost:8080/name;a=b";
+ URI uri = UriBuilder.fromUri("http://localhost:8080/name;a=b").build();
+ assertEquals(expected, uri.toString());
+ }
+
+ @Test
public void testPathParamSpaceBuildEncoded() {
String expected = "http://localhost:8080/name/%20";
URI uri = UriBuilder.fromUri("http://localhost:8080").path("name/%20").buildFromEncoded();
http://git-wip-us.apache.org/repos/asf/cxf/blob/0d2a6cca/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/DefaultSubjectCreator.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/DefaultSubjectCreator.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/DefaultSubjectCreator.java
new file mode 100644
index 0000000..ae870fb
--- /dev/null
+++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/DefaultSubjectCreator.java
@@ -0,0 +1,34 @@
+/**
+ * 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.oauth2.provider;
+
+import org.apache.cxf.jaxrs.ext.MessageContext;
+import org.apache.cxf.rs.security.oauth2.common.UserSubject;
+import org.apache.cxf.rs.security.oauth2.utils.OAuthUtils;
+import org.apache.cxf.security.SecurityContext;
+
+public class DefaultSubjectCreator implements SubjectCreator {
+
+ @Override
+ public UserSubject createUserSubject(MessageContext mc) throws OAuthServiceException {
+ return OAuthUtils.createSubject(mc,
+ (SecurityContext)mc.get(SecurityContext.class.getName()));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/0d2a6cca/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 63fcfa2..d78feaf 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
@@ -23,6 +23,7 @@ import java.net.URI;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import javax.ws.rs.core.Response;
@@ -48,6 +49,10 @@ public abstract class AbstractImplicitGrantService extends RedirectionBasedGrant
String supportedGrantType) {
super(supportedResponseType, supportedGrantType);
}
+ protected AbstractImplicitGrantService(Set<String> supportedResponseTypes,
+ String supportedGrantType) {
+ super(supportedResponseTypes, supportedGrantType);
+ }
protected Response createGrant(OAuthRedirectionState state,
Client client,
@@ -55,43 +60,63 @@ public abstract class AbstractImplicitGrantService extends RedirectionBasedGrant
List<String> approvedScope,
UserSubject userSubject,
ServerAccessToken preAuthorizedToken) {
+
+ boolean tokenCanBeReturned = preAuthorizedToken != null;
ServerAccessToken token = null;
if (preAuthorizedToken == null) {
- 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);
+ tokenCanBeReturned = canAccessTokenBeReturned(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.setAudience(state.getAudience());
+ token = getDataProvider().createAccessToken(reg);
}
- reg.setAudience(state.getAudience());
- token = getDataProvider().createAccessToken(reg);
} else {
token = preAuthorizedToken;
}
- ClientAccessToken clientToken = OAuthUtils.toClientAccessToken(token, isWriteOptionalParameters());
+ 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();
+ }
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());
+ }
- sb.append(OAuthConstants.ACCESS_TOKEN).append("=").append(clientToken.getTokenKey());
if (state.getState() != null) {
sb.append("&");
sb.append(OAuthConstants.STATE).append("=").append(state.getState());
}
- sb.append("&")
- .append(OAuthConstants.ACCESS_TOKEN_TYPE).append("=").append(clientToken.getTokenType());
if (isWriteOptionalParameters()) {
- sb.append("&").append(OAuthConstants.ACCESS_TOKEN_EXPIRES_IN)
- .append("=").append(clientToken.getExpiresIn());
+ if (tokenCanBeReturned) {
+ 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()));
@@ -100,7 +125,7 @@ public abstract class AbstractImplicitGrantService extends RedirectionBasedGrant
sb.append("&").append(entry.getKey()).append("=").append(HttpUtils.queryEncode(entry.getValue()));
}
}
- if (token.getRefreshToken() != null) {
+ if (tokenCanBeReturned && token.getRefreshToken() != null) {
processRefreshToken(sb, token.getRefreshToken());
}
if (reportClientId) {
@@ -109,6 +134,9 @@ public abstract class AbstractImplicitGrantService extends RedirectionBasedGrant
return Response.seeOther(URI.create(sb.toString())).build();
}
+ protected boolean canAccessTokenBeReturned(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");
}
http://git-wip-us.apache.org/repos/asf/cxf/blob/0d2a6cca/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/ImplicitGrantService.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/ImplicitGrantService.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/ImplicitGrantService.java
index a73e118..d2dcdbf 100644
--- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/ImplicitGrantService.java
+++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/ImplicitGrantService.java
@@ -19,6 +19,8 @@
package org.apache.cxf.rs.security.oauth2.services;
+import java.util.Set;
+
import javax.ws.rs.Path;
import org.apache.cxf.rs.security.oauth2.utils.OAuthConstants;
@@ -39,6 +41,9 @@ public class ImplicitGrantService extends AbstractImplicitGrantService {
public ImplicitGrantService() {
super(OAuthConstants.TOKEN_RESPONSE_TYPE, OAuthConstants.IMPLICIT_GRANT);
}
+ public ImplicitGrantService(Set<String> responseTypes) {
+ super(responseTypes, OAuthConstants.IMPLICIT_GRANT);
+ }
}
http://git-wip-us.apache.org/repos/asf/cxf/blob/0d2a6cca/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 c174429..51ea97e 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
@@ -19,9 +19,11 @@
package org.apache.cxf.rs.security.oauth2.services;
+import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
@@ -53,7 +55,7 @@ import org.apache.cxf.security.SecurityContext;
* The Base Redirection-Based Grant Service
*/
public abstract class RedirectionBasedGrantService extends AbstractOAuthService {
- private String supportedResponseType;
+ private Set<String> supportedResponseTypes;
private String supportedGrantType;
private boolean partialMatchScopeValidation;
private boolean useRegisteredRedirectUriIfPossible = true;
@@ -65,7 +67,11 @@ public abstract class RedirectionBasedGrantService extends AbstractOAuthService
protected RedirectionBasedGrantService(String supportedResponseType,
String supportedGrantType) {
- this.supportedResponseType = supportedResponseType;
+ this(Collections.singleton(supportedResponseType), supportedGrantType);
+ }
+ protected RedirectionBasedGrantService(Set<String> supportedResponseTypes,
+ String supportedGrantType) {
+ this.supportedResponseTypes = supportedResponseTypes;
this.supportedGrantType = supportedGrantType;
}
@@ -131,7 +137,7 @@ public abstract class RedirectionBasedGrantService extends AbstractOAuthService
// Check response_type
String responseType = params.getFirst(OAuthConstants.RESPONSE_TYPE);
- if (responseType == null || !responseType.equals(supportedResponseType)) {
+ if (responseType == null || !supportedResponseTypes.contains(responseType)) {
return createErrorResponse(params, redirectUri, OAuthConstants.UNSUPPORTED_RESPONSE_TYPE);
}
// Get the requested scopes
@@ -324,13 +330,7 @@ public abstract class RedirectionBasedGrantService extends AbstractOAuthService
return subject;
}
}
-
- subject = getMessageContext().getContent(UserSubject.class);
- if (subject != null) {
- return subject;
- } else {
- return OAuthUtils.createSubject(securityContext);
- }
+ return OAuthUtils.createSubject(getMessageContext(), securityContext);
}
protected Response createErrorResponse(MultivaluedMap<String, String> params,
http://git-wip-us.apache.org/repos/asf/cxf/blob/0d2a6cca/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java
index c96de44..ad190df 100644
--- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java
+++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java
@@ -91,7 +91,14 @@ public final class OAuthUtils {
}
return sessionToken;
}
-
+ public static UserSubject createSubject(MessageContext mc, SecurityContext sc) {
+ UserSubject subject = mc.getContent(UserSubject.class);
+ if (subject != null) {
+ return subject;
+ } else {
+ return OAuthUtils.createSubject(sc);
+ }
+ }
public static UserSubject createSubject(SecurityContext securityContext) {
List<String> roleNames = Collections.emptyList();
if (securityContext instanceof LoginSecurityContext) {
http://git-wip-us.apache.org/repos/asf/cxf/blob/0d2a6cca/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
new file mode 100644
index 0000000..c6638e3
--- /dev/null
+++ b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/idp/OidcImplicitService.java
@@ -0,0 +1,62 @@
+/**
+ * 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.idp;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+
+import javax.ws.rs.Path;
+
+import org.apache.cxf.rs.security.oauth2.common.Client;
+import org.apache.cxf.rs.security.oauth2.common.OAuthPermission;
+import org.apache.cxf.rs.security.oauth2.services.ImplicitGrantService;
+
+@Path("/login")
+public class OidcImplicitService extends ImplicitGrantService {
+ private static final String OPEN_ID_CONNECT_SCOPE = "openid";
+ private static final String ID_TOKEN_RESPONSE_TYPE = "id_token";
+ private static final String ID_TOKEN_AND_AT_RESPONSE_TYPE = "id_token token";
+ private boolean skipAuthorizationWithOidcScope;
+
+ public OidcImplicitService() {
+ super(new HashSet<String>(Arrays.asList(ID_TOKEN_RESPONSE_TYPE,
+ ID_TOKEN_AND_AT_RESPONSE_TYPE)));
+ }
+
+ @Override
+ protected boolean canAccessTokenBeReturned(List<String> requestedScope, List<String> approvedScope) {
+ return requestedScope.contains(ID_TOKEN_AND_AT_RESPONSE_TYPE);
+ }
+
+ @Override
+ protected boolean canAuthorizationBeSkipped(Client client,
+ List<String> requestedScope,
+ List<OAuthPermission> permissions) {
+ // No need to challenge the authenticated user with the authorization form
+ // if all the client application redirecting a user needs is to get this user authenticated
+ // with OIDC IDP
+ return requestedScope.size() == 1 && permissions.size() == 1 && skipAuthorizationWithOidcScope
+ && OPEN_ID_CONNECT_SCOPE.equals(requestedScope.get(0));
+ }
+ public void setSkipAuthorizationWithOidcScope(boolean skipAuthorizationWithOidcScope) {
+ this.skipAuthorizationWithOidcScope = skipAuthorizationWithOidcScope;
+ }
+
+}