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 2013/06/04 14:01:56 UTC

svn commit: r1489394 - in /cxf/branches/2.7.x-fixes: ./ rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/ rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/ rt/rs/security...

Author: sergeyb
Date: Tue Jun  4 12:01:55 2013
New Revision: 1489394

URL: http://svn.apache.org/r1489394
Log:
Merged revisions 1489392 via svnmerge from 
https://svn.apache.org/repos/asf/cxf/trunk

........
  r1489392 | sergeyb | 2013-06-04 12:57:46 +0100 (Tue, 04 Jun 2013) | 1 line
  
  [CXF-5055] OOB Response support, Client scopes registration
........

Added:
    cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/OOBAuthorizationResponse.java
      - copied unchanged from r1489392, cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/OOBAuthorizationResponse.java
    cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OAuthContextProvider.java
      - copied unchanged from r1489392, cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OAuthContextProvider.java
    cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OOBResponseDeliverer.java
      - copied unchanged from r1489392, cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OOBResponseDeliverer.java
    cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/MessageDigestGenerator.java
      - copied unchanged from r1489392, cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/MessageDigestGenerator.java
    cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtilsTest.java
      - copied unchanged from r1489392, cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtilsTest.java
Removed:
    cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/MD5SequenceGenerator.java
Modified:
    cxf/branches/2.7.x-fixes/   (props changed)
    cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/Client.java
    cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/AbstractGrantHandler.java
    cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/refresh/RefreshTokenGrantHandler.java
    cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AccessTokenService.java
    cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AuthorizationCodeGrantService.java
    cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/ImplicitGrantService.java
    cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/RedirectionBasedGrantService.java
    cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java

Propchange: cxf/branches/2.7.x-fixes/
------------------------------------------------------------------------------
  Merged /cxf/trunk:r1489392

Propchange: cxf/branches/2.7.x-fixes/
------------------------------------------------------------------------------
Binary property 'svnmerge-integrated' - no diff available.

Modified: cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/Client.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/Client.java?rev=1489394&r1=1489393&r2=1489394&view=diff
==============================================================================
--- cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/Client.java (original)
+++ cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/common/Client.java Tue Jun  4 12:01:55 2013
@@ -39,6 +39,8 @@ public class Client {
     
     private boolean isConfidential;
     private List<String> allowedGrantTypes = new LinkedList<String>();
+    private List<String> registeredScopes = new LinkedList<String>();
+    
     private List<Property> properties = new LinkedList<Property>();
     private UserSubject subject;
         
@@ -230,4 +232,25 @@ public class Client {
     public void setProperties(List<Property> properties) {
         this.properties = properties;
     }
+
+    /**
+     * Get the list of registered scopes
+     * @return scopes
+     */
+    public List<String> getRegisteredScopes() {
+        return registeredScopes;
+    }
+
+    /**
+     * Set the list of registered scopes. 
+     * Registering the scopes will allow the clients not to include the scopes
+     * and delegate to the runtime to enforce that the current request scopes are
+     * a subset of the pre-registered scopes.
+     * 
+     * Client Registration service is expected to reject unknown scopes. 
+     * @param registeredScopes the scopes
+     */
+    public void setRegisteredScopes(List<String> registeredScopes) {
+        this.registeredScopes = registeredScopes;
+    }
 }

Modified: cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/AbstractGrantHandler.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/AbstractGrantHandler.java?rev=1489394&r1=1489393&r2=1489394&view=diff
==============================================================================
--- cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/AbstractGrantHandler.java (original)
+++ cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/AbstractGrantHandler.java Tue Jun  4 12:01:55 2013
@@ -24,6 +24,7 @@ import java.util.List;
 
 import org.apache.cxf.rs.security.oauth2.common.AccessTokenRegistration;
 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.ServerAccessToken;
 import org.apache.cxf.rs.security.oauth2.common.UserSubject;
 import org.apache.cxf.rs.security.oauth2.provider.AccessTokenGrantHandler;
@@ -40,7 +41,8 @@ public abstract class AbstractGrantHandl
     
     private String supportedGrant;
     private OAuthDataProvider dataProvider;
-    private boolean isClientConfidential;    
+    private boolean isClientConfidential;
+    private boolean partialMatchScopeValidation;
     protected AbstractGrantHandler(String grant, boolean isClientConfidential) {
         supportedGrant = grant;
         this.isClientConfidential = isClientConfidential;
@@ -66,6 +68,10 @@ public abstract class AbstractGrantHandl
     protected ServerAccessToken doCreateAccessToken(Client client,
                                                     UserSubject subject,
                                                     List<String> requestedScope) {
+        if (!OAuthUtils.validateScopes(requestedScope, client.getRegisteredScopes(), 
+                                       partialMatchScopeValidation)) {
+            throw new OAuthServiceException(new OAuthError(OAuthConstants.INVALID_SCOPE));     
+        }
         // Check if a pre-authorized  token available
         ServerAccessToken token = dataProvider.getPreauthorizedToken(
                                      client, requestedScope, subject, supportedGrant);
@@ -82,4 +88,8 @@ public abstract class AbstractGrantHandl
         
         return dataProvider.createAccessToken(reg);
     }
+    
+    public void setPartialMatchScopeValidation(boolean partialMatchScopeValidation) {
+        this.partialMatchScopeValidation = partialMatchScopeValidation;
+    }
 }

Modified: cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/refresh/RefreshTokenGrantHandler.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/refresh/RefreshTokenGrantHandler.java?rev=1489394&r1=1489393&r2=1489394&view=diff
==============================================================================
--- cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/refresh/RefreshTokenGrantHandler.java (original)
+++ cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/refresh/RefreshTokenGrantHandler.java Tue Jun  4 12:01:55 2013
@@ -34,6 +34,7 @@ import org.apache.cxf.rs.security.oauth2
 public class RefreshTokenGrantHandler implements AccessTokenGrantHandler {
 
     private OAuthDataProvider dataProvider;
+    private boolean partialMatchScopeValidation;
     
     public void setDataProvider(OAuthDataProvider dataProvider) {
         this.dataProvider = dataProvider;
@@ -49,8 +50,14 @@ public class RefreshTokenGrantHandler im
             throw new OAuthServiceException(OAuthConstants.UNAUTHORIZED_CLIENT);    
         }
         String refreshToken = params.getFirst(OAuthConstants.REFRESH_TOKEN);
-        List<String> requestedScopes = OAuthUtils.parseScope(params.getFirst(OAuthConstants.SCOPE));
+        List<String> requestedScopes = OAuthUtils.getRequestedScopes(client,
+                                            params.getFirst(OAuthConstants.SCOPE),
+                                            partialMatchScopeValidation);
         
         return dataProvider.refreshAccessToken(client, refreshToken, requestedScopes);
     }
+
+    public void setPartialMatchScopeValidation(boolean partialMatchScopeValidation) {
+        this.partialMatchScopeValidation = partialMatchScopeValidation;
+    }
 }

Modified: cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AccessTokenService.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AccessTokenService.java?rev=1489394&r1=1489393&r2=1489394&view=diff
==============================================================================
--- cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AccessTokenService.java (original)
+++ cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AccessTokenService.java Tue Jun  4 12:01:55 2013
@@ -53,6 +53,7 @@ import org.apache.cxf.rs.security.oauth2
 public class AccessTokenService extends AbstractOAuthService {
     private List<AccessTokenGrantHandler> grantHandlers = Collections.emptyList();
     private boolean writeCustomErrors;
+    private boolean canSupportPublicClients;
     
     public void setWriteCustomErrors(boolean write) {
         writeCustomErrors = write;
@@ -170,7 +171,15 @@ public class AccessTokenService extends 
     // Get the Client and check the id and secret
     private Client getAndValidateClient(String clientId, String clientSecret) {
         Client client = getClient(clientId);
-        if (clientSecret == null || !client.getClientId().equals(clientId) 
+        if (canSupportPublicClients 
+            && !client.isConfidential() 
+            && client.getClientSecret() == null 
+            && client.getRedirectUris().isEmpty()
+            && clientSecret == null) {
+            return client;
+        }
+        if (clientSecret == null || client.getClientSecret() == null 
+            || !client.getClientId().equals(clientId) 
             || !client.getClientSecret().equals(clientSecret)) {
             throw new NotAuthorizedException(Response.status(401).build());
         }
@@ -230,4 +239,8 @@ public class AccessTokenService extends 
         return client;
         
     }
+    
+    public void setCanSupportPublicClients(boolean support) {
+        this.canSupportPublicClients = support;
+    }
 }

Modified: cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AuthorizationCodeGrantService.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AuthorizationCodeGrantService.java?rev=1489394&r1=1489393&r2=1489394&view=diff
==============================================================================
--- cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AuthorizationCodeGrantService.java (original)
+++ cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AuthorizationCodeGrantService.java Tue Jun  4 12:01:55 2013
@@ -22,17 +22,20 @@ package org.apache.cxf.rs.security.oauth
 import java.util.List;
 
 import javax.ws.rs.Path;
+import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
 
 import org.apache.cxf.rs.security.oauth2.common.Client;
+import org.apache.cxf.rs.security.oauth2.common.OOBAuthorizationResponse;
 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.grants.code.AuthorizationCodeDataProvider;
 import org.apache.cxf.rs.security.oauth2.grants.code.AuthorizationCodeRegistration;
 import org.apache.cxf.rs.security.oauth2.grants.code.ServerAuthorizationCodeGrant;
 import org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException;
+import org.apache.cxf.rs.security.oauth2.provider.OOBResponseDeliverer;
 import org.apache.cxf.rs.security.oauth2.utils.OAuthConstants;
 
 
@@ -45,8 +48,11 @@ import org.apache.cxf.rs.security.oauth2
  */
 @Path("/authorize")
 public class AuthorizationCodeGrantService extends RedirectionBasedGrantService {
+    private boolean canSupportPublicClients;
+    private OOBResponseDeliverer oobDeliverer;
+    
     public AuthorizationCodeGrantService() {
-        super(OAuthConstants.CODE_RESPONSE_TYPE, OAuthConstants.AUTHORIZATION_CODE_GRANT, true);
+        super(OAuthConstants.CODE_RESPONSE_TYPE, OAuthConstants.AUTHORIZATION_CODE_GRANT);
     }
     
     protected Response createGrant(MultivaluedMap<String, String> params,
@@ -73,18 +79,39 @@ public class AuthorizationCodeGrantServi
             return createErrorResponse(params, redirectUri, OAuthConstants.ACCESS_DENIED);
         }
         
-        // return the code by appending it as a query parameter to the redirect URI
-        UriBuilder ub = getRedirectUriBuilder(params.getFirst(OAuthConstants.STATE), redirectUri);
-        ub.queryParam(OAuthConstants.AUTHORIZATION_CODE_VALUE, grant.getCode());
-        return Response.seeOther(ub.build()).build();
+        if (!client.isConfidential()) {
+            OOBAuthorizationResponse oobResponse = new OOBAuthorizationResponse();
+            oobResponse.setClientId(client.getClientId());
+            oobResponse.setAuthorizationCode(grant.getCode());
+            oobResponse.setUserId(userSubject.getLogin());
+            oobResponse.setLifetime(grant.getLifetime());
+            return deliverOOBResponse(oobResponse);
+        } else {
+            // return the code by appending it as a query parameter to the redirect URI
+            UriBuilder ub = getRedirectUriBuilder(params.getFirst(OAuthConstants.STATE), redirectUri);
+            ub.queryParam(OAuthConstants.AUTHORIZATION_CODE_VALUE, grant.getCode());
+            return Response.seeOther(ub.build()).build();
+        }
+    }
+    
+    protected Response deliverOOBResponse(OOBAuthorizationResponse response) {
+        if (oobDeliverer != null) {    
+            return oobDeliverer.deliver(response);
+        } else {
+            return Response.ok(response).type(MediaType.TEXT_HTML).build();
+        }
     }
     
     protected Response createErrorResponse(MultivaluedMap<String, String> params,
                                            String redirectUri,
                                            String error) {
-        UriBuilder ub = getRedirectUriBuilder(params.getFirst(OAuthConstants.STATE), redirectUri);
-        ub.queryParam(OAuthConstants.ERROR_KEY, error);
-        return Response.seeOther(ub.build()).build();
+        if (redirectUri == null) {
+            return Response.status(401).entity(error).build();
+        } else {
+            UriBuilder ub = getRedirectUriBuilder(params.getFirst(OAuthConstants.STATE), redirectUri);
+            ub.queryParam(OAuthConstants.ERROR_KEY, error);
+            return Response.seeOther(ub.build()).build();
+        }
     }
     
     protected UriBuilder getRedirectUriBuilder(String state, String redirectUri) {
@@ -94,6 +121,23 @@ public class AuthorizationCodeGrantServi
         }
         return ub;
     }
+
+    @Override
+    protected boolean canSupportPublicClient(Client c) {
+        return canSupportPublicClients && !c.isConfidential()
+            && c.getClientSecret() == null && c.getRedirectUris().isEmpty();
+    }
+
+    @Override
+    protected boolean canRedirectUriBeEmpty(Client c) {
+        return canSupportPublicClient(c);
+    }
+    
+    public void setCanSupportPublicClients(boolean support) {
+        this.canSupportPublicClients = support;
+    }
+    
+    
 }
 
 

Modified: cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/ImplicitGrantService.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/ImplicitGrantService.java?rev=1489394&r1=1489393&r2=1489394&view=diff
==============================================================================
--- cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/ImplicitGrantService.java (original)
+++ cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/ImplicitGrantService.java Tue Jun  4 12:01:55 2013
@@ -46,8 +46,11 @@ import org.apache.cxf.rs.security.oauth2
  */
 @Path("/authorize-implicit")
 public class ImplicitGrantService extends RedirectionBasedGrantService {
+    // For a client to validate that this client is a targeted recipient.
+    private boolean reportClientId;
+    
     public ImplicitGrantService() {
-        super(OAuthConstants.TOKEN_RESPONSE_TYPE, OAuthConstants.IMPLICIT_GRANT, false);
+        super(OAuthConstants.TOKEN_RESPONSE_TYPE, OAuthConstants.IMPLICIT_GRANT);
     }
     
     protected Response createGrant(MultivaluedMap<String, String> params,
@@ -81,6 +84,10 @@ public class ImplicitGrantService extend
         sb.append(OAuthConstants.ACCESS_TOKEN).append("=").append(token.getTokenKey());
         sb.append("&")
             .append(OAuthConstants.ACCESS_TOKEN_TYPE).append("=").append(token.getTokenType());
+        if (reportClientId) {
+            sb.append("&")
+                .append(OAuthConstants.CLIENT_ID).append("=").append(client.getClientId());
+        }
         if (isWriteOptionalParameters()) {
             sb.append("&").append(OAuthConstants.ACCESS_TOKEN_EXPIRES_IN)
                 .append("=").append(token.getExpiresIn());
@@ -118,6 +125,20 @@ public class ImplicitGrantService extend
         }
         return sb;
     }
+
+    public void setReportClientId(boolean reportClientId) {
+        this.reportClientId = reportClientId;
+    }
+
+    @Override
+    protected boolean canSupportPublicClient(Client c) {
+        return true;
+    }
+    
+    @Override
+    protected boolean canRedirectUriBeEmpty(Client c) {
+        return false;
+    }
     
 }
 

Modified: cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/RedirectionBasedGrantService.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/RedirectionBasedGrantService.java?rev=1489394&r1=1489393&r2=1489394&view=diff
==============================================================================
--- cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/RedirectionBasedGrantService.java (original)
+++ cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/RedirectionBasedGrantService.java Tue Jun  4 12:01:55 2013
@@ -57,17 +57,15 @@ import org.apache.cxf.security.SecurityC
 public abstract class RedirectionBasedGrantService extends AbstractOAuthService {
     private String supportedResponseType;
     private String supportedGrantType;
-    private boolean isClientConfidential;
+    private boolean partialMatchScopeValidation;
     private SessionAuthenticityTokenProvider sessionAuthenticityTokenProvider;
     private SubjectCreator subjectCreator;
     private ResourceOwnerNameProvider resourceOwnerNameProvider;
     
     protected RedirectionBasedGrantService(String supportedResponseType,
-                                           String supportedGrantType,
-                                           boolean isConfidential) {
+                                           String supportedGrantType) {
         this.supportedResponseType = supportedResponseType;
         this.supportedGrantType = supportedGrantType;
-        this.isClientConfidential = isConfidential;
     }
     
     /**
@@ -119,7 +117,7 @@ public abstract class RedirectionBasedGr
         String redirectUri = validateRedirectUri(client, params.getFirst(OAuthConstants.REDIRECT_URI)); 
         
         // Enforce the client confidentiality requirements
-        if (!OAuthUtils.isGrantSupportedForClient(client, isClientConfidential, supportedGrantType)) {
+        if (!OAuthUtils.isGrantSupportedForClient(client, !canSupportPublicClient(client), supportedGrantType)) {
             return createErrorResponse(params, redirectUri, OAuthConstants.UNAUTHORIZED_CLIENT);
         }
         
@@ -128,9 +126,17 @@ public abstract class RedirectionBasedGr
         if (responseType == null || !responseType.equals(supportedResponseType)) {
             return createErrorResponse(params, redirectUri, OAuthConstants.UNSUPPORTED_RESPONSE_TYPE);
         }
-        
         // Get the requested scopes
-        List<String> requestedScope = OAuthUtils.parseScope(params.getFirst(OAuthConstants.SCOPE));
+        List<String> requestedScope = null;
+        
+        try {
+            requestedScope = OAuthUtils.getRequestedScopes(client, 
+                                                           params.getFirst(OAuthConstants.SCOPE), 
+                                                           partialMatchScopeValidation);
+        } catch (OAuthServiceException ex) {
+            return createErrorResponse(params, redirectUri, OAuthConstants.INVALID_SCOPE);
+        }
+        
         
         // Create a UserSubject representing the end user 
         UserSubject userSubject = createUserSubject(sc);
@@ -235,10 +241,11 @@ public abstract class RedirectionBasedGr
                 approvedScope.add(rScope);
             }
         }
-        if (!requestedScope.containsAll(approvedScope)) {
+        if (!requestedScope.containsAll(approvedScope)
+            || !OAuthUtils.validateScopes(requestedScope, client.getRegisteredScopes(), 
+                                         partialMatchScopeValidation)) {
             return createErrorResponse(params, redirectUri, OAuthConstants.INVALID_SCOPE);
         }
-        
         UserSubject userSubject = createUserSubject(securityContext);
         
         // Request a new grant
@@ -309,8 +316,8 @@ public abstract class RedirectionBasedGr
         } else if (uris.size() == 1) {
             redirectUri = uris.get(0);
         }
-        if (redirectUri == null) {
-            reportInvalidRequestError("Client Redirect Uri is invalid");
+        if (redirectUri == null && !canRedirectUriBeEmpty(client)) {
+            reportInvalidRequestError("Client Redirect Uri is invalid");    
         }
         return redirectUri;
     }
@@ -374,4 +381,12 @@ public abstract class RedirectionBasedGr
     public void setResourceOwnerNameProvider(ResourceOwnerNameProvider resourceOwnerNameProvider) {
         this.resourceOwnerNameProvider = resourceOwnerNameProvider;
     }
+
+    public void setPartialMatchScopeValidation(boolean partialMatchScopeValidation) {
+        this.partialMatchScopeValidation = partialMatchScopeValidation;
+    }
+    
+    protected abstract boolean canSupportPublicClient(Client c);
+    
+    protected abstract boolean canRedirectUriBeEmpty(Client c);
 }

Modified: cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java?rev=1489394&r1=1489393&r2=1489394&view=diff
==============================================================================
--- cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java (original)
+++ cxf/branches/2.7.x-fixes/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java Tue Jun  4 12:01:55 2013
@@ -100,9 +100,17 @@ public final class OAuthUtils {
     }
 
     public static String generateRandomTokenKey() throws OAuthServiceException {
+        return generateRandomTokenKey(null);
+    }
+    
+    public static String generateRandomTokenKey(String digestAlgo) throws OAuthServiceException {
         try {
             byte[] bytes = UUID.randomUUID().toString().getBytes("UTF-8");
-            return new MD5SequenceGenerator().generate(bytes);
+            MessageDigestGenerator gen = new MessageDigestGenerator();
+            if (digestAlgo != null) {
+                gen.setAlgorithm(digestAlgo);
+            }
+            return gen.generate(bytes);
         } catch (Exception ex) {
             throw new OAuthServiceException(OAuthConstants.SERVER_ERROR, ex);
         }
@@ -131,4 +139,42 @@ public final class OAuthUtils {
         return false;
     }
     
+    public static List<String> getRequestedScopes(Client client, String scopeParameter, 
+                                                  boolean partialMatchScopeValidation) {
+        List<String> requestScopes = parseScope(scopeParameter);
+        List<String> registeredScopes = client.getRegisteredScopes();
+        if (requestScopes.isEmpty()) {
+            requestScopes.addAll(registeredScopes);
+            return requestScopes;
+        }
+        if (!validateScopes(requestScopes, registeredScopes, partialMatchScopeValidation)) {
+            throw new OAuthServiceException("Unexpected scope");
+        }
+        return requestScopes;
+    }
+    
+    public static boolean validateScopes(List<String> requestScopes, List<String> registeredScopes,
+                                         boolean partialMatchScopeValidation) {
+        if (!registeredScopes.isEmpty()) {
+            // if it is a strict validation then pre-registered scopes have to contains all 
+            // the current request scopes
+            if (!partialMatchScopeValidation) {
+                return registeredScopes.containsAll(requestScopes);
+            } else {
+                for (String requestScope : requestScopes) {
+                    boolean match = false;
+                    for (String registeredScope : registeredScopes) { 
+                        if (requestScope.startsWith(registeredScope)) {
+                            match = true;
+                            break;
+                        }
+                    }
+                    if (!match) {
+                        return false;
+                    }
+                }
+            }
+        }
+        return true;
+    }
 }