Skip to content

Commit

Permalink
Default OAuth2 Scope Validator implementation (#2206)
Browse files Browse the repository at this point in the history
Default scope validator for new authorization time
  • Loading branch information
shashimalcse authored Oct 26, 2023
1 parent a1c0d61 commit 57a31ad
Show file tree
Hide file tree
Showing 18 changed files with 1,657 additions and 29 deletions.
10 changes: 10 additions & 0 deletions components/org.wso2.carbon.identity.oauth/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,14 @@
<artifactId>jaxp-ri</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.wso2.carbon.identity.framework</groupId>
<artifactId>org.wso2.carbon.identity.api.resource.mgt</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon.identity.framework</groupId>
<artifactId>org.wso2.carbon.identity.role.v2.mgt.core</artifactId>
</dependency>
</dependencies>

<build>
Expand Down Expand Up @@ -429,6 +437,8 @@
org.wso2.carbon.utils.multitenancy;version="${carbon.kernel.imp.pkg.version.range}",
org.wso2.carbon.identity.multi.attribute.login.mgt.*;
version="${carbon.identity.framework.imp.pkg.version.range}",
org.wso2.carbon.identity.api.resource.mgt; version="${carbon.identity.framework.imp.pkg.version.range}",
org.wso2.carbon.identity.role.v2.mgt.core; version="${carbon.identity.framework.imp.pkg.version.range}"
</Import-Package>
<Export-Package>
!org.wso2.carbon.identity.oauth.internal,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.wso2.carbon.identity.oauth2.dao.TokenManagementDAO;
import org.wso2.carbon.identity.oauth2.token.handlers.response.AccessTokenResponseHandler;
import org.wso2.carbon.identity.oauth2.validators.scope.ScopeValidator;
import org.wso2.carbon.identity.oauth2.validators.validationhandler.ScopeValidationHandler;
import org.wso2.carbon.identity.organization.management.service.OrganizationManager;
import org.wso2.carbon.identity.organization.management.service.OrganizationUserResidentResolverService;
import org.wso2.carbon.identity.role.mgt.core.RoleManagementService;
Expand All @@ -57,6 +58,7 @@ public class OAuthComponentServiceHolder {
private List<TokenBindingMetaDataDTO> tokenBindingMetaDataDTOs = new ArrayList<>();
private OAuthAdminServiceImpl oAuthAdminService;
private List<ScopeValidator> scopeValidators = new ArrayList<>();
private List<ScopeValidationHandler> scopeValidationHandlers = new ArrayList<>();
private Map<Integer, OAuthApplicationMgtListener> oAuthApplicationMgtListeners = new TreeMap<>();
private RoleManagementService roleManagementService;
private OrganizationUserResidentResolverService organizationUserResidentResolverService;
Expand Down Expand Up @@ -105,6 +107,46 @@ public void setScopeValidators(List<ScopeValidator> scopeValidators) {
this.scopeValidators = scopeValidators;
}

/**
* Get the list of scope validation handler implementations available.
*
* @return ScopeValidationHandler returns a list ot scope validation policy handler.
*/
public List<ScopeValidationHandler> getScopeValidationHandlers() {

return scopeValidationHandlers;
}

/**
* Add scope validation handler implementation.
*
* @param scopeValidationHandler Scope validation handler implementation.
*/
public void addScopeValidationHandler(ScopeValidationHandler scopeValidationHandler) {

scopeValidationHandlers.add(scopeValidationHandler);
}

/**
* Remove scope validation policy implementation.
*
* @param scopeValidationHandler Scope validation policy implementation.
*/
public void removeScopeValidationHandler(ScopeValidationHandler scopeValidationHandler) {

scopeValidationHandlers.remove(scopeValidationHandler);
}

/**
* Set a list of scope validation handler implementations.
*
* @param scopeValidationHandlers List of Scope validation handler implementation.
*/
public void setScopeValidatorPolicyHandlers(List<ScopeValidationHandler> scopeValidationHandlers) {

this.scopeValidationHandlers = scopeValidationHandlers;
}

private OAuthComponentServiceHolder() {

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@
import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeReqDTO;
import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeRespDTO;
import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters;
import org.wso2.carbon.identity.oauth2.util.AuthzUtil;
import org.wso2.carbon.identity.oauth2.util.OAuth2Util;
import org.wso2.carbon.identity.oauth2.validators.DefaultOAuth2ScopeValidator;
import org.wso2.carbon.identity.oauth2.validators.JDBCPermissionBasedInternalScopeValidator;
import org.wso2.carbon.identity.oauth2.validators.RoleBasedInternalScopeValidator;
import org.wso2.carbon.utils.CarbonUtils;
Expand Down Expand Up @@ -276,15 +278,23 @@ private void validateRequestedScopes(OAuthAuthzReqMessageContext authzReqMsgCtx,
List<String> requestedAllowedScopes = getAllowedScopesFromRequestedScopes(authzReqMsgCtx);
// Remove the system level allowed scopes from requested scopes for further validation.
removeAllowedScopesFromRequestedScopes(authzReqMsgCtx, requestedAllowedScopes);
// If it is management app, we validate internal scopes in the requested scopes.
String[] authorizedInternalScopes = new String[0];
log.debug("Handling the internal scope validation.");
authorizedInternalScopes = getAuthorizedInternalScopes(authzReqMsgCtx);

// Remove the internal scopes from requested scopes for further validation.
removeInternalScopesFromRequestedScopes(authzReqMsgCtx);
// Adding the authorized internal scopes to tokReqMsgCtx for any special validators to use.
authzReqMsgCtx.setAuthorizedInternalScopes(authorizedInternalScopes);
List<String> authorizedScopes = null;
// Switch the scope validators dynamically based on the authorization runtime.
if (AuthzUtil.isLegacyAuthzRuntime()) {
// If it is management app, we validate internal scopes in the requested scopes.
String[] authorizedInternalScopes = new String[0];
log.debug("Handling the internal scope validation.");
authorizedInternalScopes = getAuthorizedInternalScopes(authzReqMsgCtx);

// Remove the internal scopes from requested scopes for further validation.
removeInternalScopesFromRequestedScopes(authzReqMsgCtx);
// Adding the authorized internal scopes to tokReqMsgCtx for any special validators to use.
authzReqMsgCtx.setAuthorizedInternalScopes(authorizedInternalScopes);
} else {
// Engage new scope validator
authorizedScopes = getAuthorizedScopes(authzReqMsgCtx);
removeAuthorizedScopesFromRequestedScopes(authzReqMsgCtx, authorizedScopes);
}
boolean isDropUnregisteredScopes = OAuthServerConfiguration.getInstance().isDropUnregisteredScopes();
if (isDropUnregisteredScopes) {
if (log.isDebugEnabled()) {
Expand All @@ -296,8 +306,12 @@ private void validateRequestedScopes(OAuthAuthzReqMessageContext authzReqMsgCtx,
boolean isValid = validateScopes(authzReqMsgCtx, authzHandler);
boolean isValidatedScopesContainsInRequestedScopes = isValidatedScopesContainsInRequestedScopes(authzReqMsgCtx);
if (isValid && isValidatedScopesContainsInRequestedScopes) {
// Add authorized internal scopes to the request for sending in the response.
addAuthorizedInternalScopes(authzReqMsgCtx, authzReqMsgCtx.getAuthorizedInternalScopes());
if (AuthzUtil.isLegacyAuthzRuntime()) {
// Add authorized internal scopes to the request for sending in the response.
addAuthorizedInternalScopes(authzReqMsgCtx, authzReqMsgCtx.getAuthorizedInternalScopes());
} else {
addAuthorizedScopes(authzReqMsgCtx, authorizedScopes);
}
// Add scopes that filtered from the allowed scopes list.
addAllowedScopes(authzReqMsgCtx, requestedAllowedScopes.toArray(new String[0]));
} else {
Expand Down Expand Up @@ -359,6 +373,19 @@ private String[] getAuthorizedInternalScopes(OAuthAuthzReqMessageContext authzRe
return authorizedInternalScopes;
}

/**
* get authorized scopes.
*
* @param authzReqMsgCtx authzReqMsgCtx
* @return - authorizedInternalScopes scopes list
*/
private List<String> getAuthorizedScopes(OAuthAuthzReqMessageContext authzReqMsgCtx)
throws IdentityOAuth2Exception {

DefaultOAuth2ScopeValidator scopeValidator = new DefaultOAuth2ScopeValidator();
return scopeValidator.validateScope(authzReqMsgCtx);
}

/**
* Eemove internal scopes from requested scopes.
*
Expand All @@ -379,6 +406,27 @@ private void removeInternalScopesFromRequestedScopes(OAuthAuthzReqMessageContext
authzReqMsgCtx.getAuthorizationReqDTO().setScopes(scopes.toArray(new String[0]));
}

/**
* Remove authorized scopes from requested scopes.
*
* @param authzReqMsgCtx authzReqMsgCtx
* @param authorizedScopes Authorized Scopes
*/
private void removeAuthorizedScopesFromRequestedScopes(OAuthAuthzReqMessageContext authzReqMsgCtx,
List<String> authorizedScopes) {

if (authzReqMsgCtx.getAuthorizationReqDTO().getScopes() == null) {
return;
}
List<String> scopes = new ArrayList<>();
for (String scope : authzReqMsgCtx.getAuthorizationReqDTO().getScopes()) {
if (!authorizedScopes.contains(scope) && !scope.equalsIgnoreCase(SYSTEM_SCOPE)) {
scopes.add(scope);
}
}
authzReqMsgCtx.getAuthorizationReqDTO().setScopes(scopes.toArray(new String[0]));
}

/**
* Remove the system level allowed scopes from requested scopes.
*
Expand Down Expand Up @@ -419,6 +467,14 @@ private void addAuthorizedInternalScopes(OAuthAuthzReqMessageContext authzReqMsg
authzReqMsgCtx.setApprovedScope(scopesToReturn);
}

private void addAuthorizedScopes(OAuthAuthzReqMessageContext authzReqMsgCtx, List<String> authorizedScopes) {

String[] scopes = authzReqMsgCtx.getApprovedScope();
String[] scopesToReturn = (String[]) ArrayUtils.addAll(scopes, authorizedScopes.toArray());
authzReqMsgCtx.setApprovedScope(scopesToReturn);
}


private void addRequestedOIDCScopes(OAuthAuthzReqMessageContext authzReqMsgCtx,
String[] requestedOIDCScopes) {
Set<String> scopesToReturn = new HashSet<>(Arrays.asList(authzReqMsgCtx.getApprovedScope()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.identity.api.resource.mgt.APIResourceManager;
import org.wso2.carbon.identity.application.authentication.framework.ApplicationAuthenticationService;
import org.wso2.carbon.identity.application.authentication.framework.AuthenticationDataPublisher;
import org.wso2.carbon.identity.application.authentication.framework.AuthenticationMethodNameTranslator;
import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants;
import org.wso2.carbon.identity.application.mgt.ApplicationManagementService;
import org.wso2.carbon.identity.application.mgt.AuthorizedAPIManagementService;
import org.wso2.carbon.identity.application.mgt.listener.ApplicationMgtListener;
import org.wso2.carbon.identity.consent.server.configs.mgt.services.ConsentServerConfigsManagementService;
import org.wso2.carbon.identity.core.SAMLSSOServiceProviderManager;
Expand Down Expand Up @@ -80,6 +82,10 @@
import org.wso2.carbon.identity.oauth2.util.OAuth2Util;
import org.wso2.carbon.identity.oauth2.validators.scope.RoleBasedScopeIssuer;
import org.wso2.carbon.identity.oauth2.validators.scope.ScopeValidator;
import org.wso2.carbon.identity.oauth2.validators.validationhandler.ScopeValidationHandler;
import org.wso2.carbon.identity.oauth2.validators.validationhandler.impl.M2MScopeValidationHandler;
import org.wso2.carbon.identity.oauth2.validators.validationhandler.impl.NoPolicyScopeValidationHandler;
import org.wso2.carbon.identity.oauth2.validators.validationhandler.impl.RoleBasedScopeValidationHandler;
import org.wso2.carbon.identity.openidconnect.OpenIDConnectClaimFilter;
import org.wso2.carbon.identity.openidconnect.OpenIDConnectClaimFilterImpl;
import org.wso2.carbon.identity.openidconnect.dao.ScopeClaimMappingDAO;
Expand All @@ -88,6 +94,7 @@
import org.wso2.carbon.identity.organization.management.service.OrganizationManagementInitialize;
import org.wso2.carbon.identity.organization.management.service.OrganizationManager;
import org.wso2.carbon.identity.organization.management.service.OrganizationUserResidentResolverService;
import org.wso2.carbon.identity.role.v2.mgt.core.RoleManagementService;
import org.wso2.carbon.identity.user.store.configuration.listener.UserStoreConfigListener;
import org.wso2.carbon.idp.mgt.IdpManager;
import org.wso2.carbon.registry.core.service.RegistryService;
Expand Down Expand Up @@ -332,6 +339,9 @@ protected void activate(ComponentContext context) {
bundleContext.registerService(OAuth2ScopeService.class.getName(), oAuth2ScopeService, null);
// Registering OAuth2ScopeService under ScopeService interface as the default service.
bundleContext.registerService(ScopeMetadataService.class, oAuth2ScopeService, null);
bundleContext.registerService(ScopeValidationHandler.class, new RoleBasedScopeValidationHandler(), null);
bundleContext.registerService(ScopeValidationHandler.class, new NoPolicyScopeValidationHandler(), null);
bundleContext.registerService(ScopeValidationHandler.class, new M2MScopeValidationHandler(), null);
// Note : DO NOT add any activation related code below this point,
// to make sure the server doesn't start up if any activation failures occur

Expand Down Expand Up @@ -607,6 +617,29 @@ protected void removeScopeValidatorService(ScopeValidator scopeValidator) {
OAuthComponentServiceHolder.getInstance().removeScopeValidator(scopeValidator);
}

@Reference(
name = "scope.validator.handler",
service = ScopeValidationHandler.class,
cardinality = ReferenceCardinality.MULTIPLE,
policy = ReferencePolicy.DYNAMIC,
unbind = "removeScopeValidationHandler"
)
protected void addScopeValidationHandler(ScopeValidationHandler scopeValidationHandler) {

if (log.isDebugEnabled()) {
log.debug("Adding the Scope validation handler Service : " + scopeValidationHandler.getName());
}
OAuthComponentServiceHolder.getInstance().addScopeValidationHandler(scopeValidationHandler);
}

protected void removeScopeValidationHandler(ScopeValidationHandler scopeValidationHandler) {

if (log.isDebugEnabled()) {
log.debug("Removing the Scope validator Service : " + scopeValidationHandler.getName());
}
OAuthComponentServiceHolder.getInstance().removeScopeValidationHandler(scopeValidationHandler);
}

@Reference(
name = "IdentityProviderManager",
service = org.wso2.carbon.idp.mgt.IdpManager.class,
Expand Down Expand Up @@ -1222,4 +1255,85 @@ protected void unsetRealmService(RealmService realmService) {

OAuth2ServiceComponentHolder.getInstance().setRealmService(null);
}

@Reference(
name = "identity.authorized.api.management.component",
service = AuthorizedAPIManagementService.class,
cardinality = ReferenceCardinality.MANDATORY,
policy = ReferencePolicy.DYNAMIC,
unbind = "unsetAuthorizedAPIManagementService"
)
protected void setAuthorizedAPIManagementService(AuthorizedAPIManagementService authorizedAPIManagementService) {

if (log.isDebugEnabled()) {
log.debug("Adding Authorized API Management Service: " + authorizedAPIManagementService.getClass()
.getName());
}
OAuth2ServiceComponentHolder.getInstance()
.setAuthorizedAPIManagementService(authorizedAPIManagementService);
}

protected void unsetAuthorizedAPIManagementService(AuthorizedAPIManagementService authorizedAPIManagementService) {

if (log.isDebugEnabled()) {
log.debug("Removing Authorized API Management Service: " + authorizedAPIManagementService.getClass()
.getName());
}
OAuth2ServiceComponentHolder.getInstance().setAuthorizedAPIManagementService(null);
}

@Reference(
name = "api.resource.mgt.service.component",
service = APIResourceManager.class,
cardinality = ReferenceCardinality.MANDATORY,
policy = ReferencePolicy.DYNAMIC,
unbind = "unsetAPIResourceManagerService"
)
protected void setAPIResourceManagerService(APIResourceManager apiResourceManager) {

if (log.isDebugEnabled()) {
log.debug("Adding API Resource Manager: " + apiResourceManager.getClass().getName());
}
OAuth2ServiceComponentHolder.getInstance().setApiResourceManager(apiResourceManager);
}
protected void unsetAPIResourceManagerService(APIResourceManager apiResourceManager) {

if (log.isDebugEnabled()) {
log.debug("Removing API Resource Manager: " + apiResourceManager.getClass().getName());
}
OAuth2ServiceComponentHolder.getInstance().setApiResourceManager(null);
}

/**
* Set role management service V2 implementation.
*
* @param roleManagementService RoleManagementServiceV2.
*/
@Reference(
name = "org.wso2.carbon.identity.role.v2.mgt.core.RoleManagementService",
service = org.wso2.carbon.identity.role.v2.mgt.core.RoleManagementService.class,
cardinality = ReferenceCardinality.MANDATORY,
policy = ReferencePolicy.DYNAMIC,
unbind = "unsetRoleManagementServiceV2")
protected void setRoleManagementServiceV2(RoleManagementService roleManagementService) {

if (log.isDebugEnabled()) {
log.debug("Adding Role Management Service V2: " + roleManagementService.getClass().getName());
}
OAuth2ServiceComponentHolder.getInstance().setRoleManagementServiceV2(roleManagementService);
}

/**
* Unset role management service V2 implementation.
*
* @param roleManagementService RoleManagementServiceV2
*/
protected void unsetRoleManagementServiceV2(RoleManagementService roleManagementService) {

if (log.isDebugEnabled()) {
log.debug("Removing Role Management Service V2: " + roleManagementService.getClass().getName());
}
OAuth2ServiceComponentHolder.getInstance().setRoleManagementServiceV2(null);
}

}
Loading

0 comments on commit 57a31ad

Please sign in to comment.