cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From serg...@apache.org
Subject cxf git commit: Some modifications to support implicit OIDC flows
Date Thu, 05 Nov 2015 17:24:16 GMT
Repository: cxf
Updated Branches:
  refs/heads/master 6d7d8eb39 -> 295091064


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/29509106
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/29509106
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/29509106

Branch: refs/heads/master
Commit: 295091064b8459e6e05a38b974a76d56c0bb9f3a
Parents: 6d7d8eb
Author: Sergey Beryozkin <sberyozkin@gmail.com>
Authored: Thu Nov 5 17:21:32 2015 +0000
Committer: Sergey Beryozkin <sberyozkin@gmail.com>
Committed: Thu Nov 5 17:23:59 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/29509106/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/29509106/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/29509106/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/29509106/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/29509106/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/29509106/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/29509106/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/29509106/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;
+    }
+    
+}


Mime
View raw message