From 7ba1dc989a1b6fa052b18134247d4800a8ae1d23 Mon Sep 17 00:00:00 2001 From: Milan Perera Date: Thu, 26 Jan 2017 14:51:30 +0530 Subject: [PATCH] Implemented a scope delegation validator --- .../handlers/ScopeValidationHandler.java | 131 +++++++++++++++ .../OAuthExtensionServiceComponent.java | 34 ++++ .../internal/OAuthExtensionsDataHolder.java | 24 ++- .../ExtendedJDBCScopeValidator.java | 2 +- .../PermissionBasedScopeValidator.java | 159 ++++++++++++++++++ .../validators/RoleBasedScopeValidator.java | 158 +++++++++++++++++ 6 files changed, 506 insertions(+), 2 deletions(-) create mode 100644 components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/handlers/ScopeValidationHandler.java create mode 100644 components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/validators/PermissionBasedScopeValidator.java create mode 100644 components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/validators/RoleBasedScopeValidator.java diff --git a/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/handlers/ScopeValidationHandler.java b/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/handlers/ScopeValidationHandler.java new file mode 100644 index 0000000000..0c3964e9c0 --- /dev/null +++ b/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/handlers/ScopeValidationHandler.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.wso2.carbon.device.mgt.oauth.extensions.handlers; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.oauth.extensions.internal.OAuthExtensionsDataHolder; +import org.wso2.carbon.identity.oauth.cache.CacheEntry; +import org.wso2.carbon.identity.oauth.cache.OAuthCache; +import org.wso2.carbon.identity.oauth.cache.OAuthCacheKey; +import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.dao.TokenMgtDAO; +import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; +import org.wso2.carbon.identity.oauth2.model.ResourceScopeCacheEntry; +import org.wso2.carbon.identity.oauth2.validators.OAuth2ScopeValidator; + +import java.util.Map; + +public class ScopeValidationHandler extends OAuth2ScopeValidator { + + private final static Log log = LogFactory.getLog(ScopeValidationHandler.class); + private Map scopeValidators; + + private final String DEFAULT_PREFIX = "default"; + + public ScopeValidationHandler() { + scopeValidators = OAuthExtensionsDataHolder.getInstance().getScopeValidators(); + } + + public boolean validateScope(AccessTokenDO accessTokenDO, String resource) throws IdentityOAuth2Exception { + + //returns true if scope validators are not defined + if (scopeValidators == null || scopeValidators.isEmpty()) { + if(log.isDebugEnabled()){ + log.debug("OAuth2 scope validators are not loaded"); + } + return true; + } + + String resourceScope = getResourceScope(resource); + + //returns true if scope does not exist for the resource + if (resourceScope == null) { + if(log.isDebugEnabled()){ + log.debug("Resource '" + resource + "' is not protected with a scope"); + } + return true; + } + + String scope[] = resourceScope.split(":"); + String scopePrefix = scope[0]; + + OAuth2ScopeValidator scopeValidator = scopeValidators.get(scopePrefix); + + if (scopeValidator == null) { + if(log.isDebugEnabled()){ + log.debug("OAuth2 scope validator cannot be identified for '" + scopePrefix + "' scope prefix"); + } + + // loading default scope validator if matching validator is not found + scopeValidator = scopeValidators.get(DEFAULT_PREFIX); + if(log.isDebugEnabled()){ + log.debug("Loading default scope validator"); + } + + if (scopeValidator == null) { + if(log.isDebugEnabled()){ + log.debug("Default scope validator is not available"); + } + return true; + } + } + + // validate scope via relevant scope validator that matches with the prefix + return scopeValidator.validateScope(accessTokenDO, resourceScope); + } + + private String getResourceScope(String resource) { + + String resourceScope = null; + boolean cacheHit = false; + // Check the cache, if caching is enabled. + if (OAuthServerConfiguration.getInstance().isCacheEnabled()) { + OAuthCache oauthCache = OAuthCache.getInstance(); + OAuthCacheKey cacheKey = new OAuthCacheKey(resource); + CacheEntry result = oauthCache.getValueFromCache(cacheKey); + + //Cache hit + if (result instanceof ResourceScopeCacheEntry) { + resourceScope = ((ResourceScopeCacheEntry) result).getScope(); + cacheHit = true; + } + } + + TokenMgtDAO tokenMgtDAO = new TokenMgtDAO(); + if (!cacheHit) { + try { + resourceScope = tokenMgtDAO.findScopeOfResource(resource); + } catch (IdentityOAuth2Exception e) { + log.error("Error occurred while retrieving scope for resource '" + resource + "'"); + } + + if (OAuthServerConfiguration.getInstance().isCacheEnabled()) { + OAuthCache oauthCache = OAuthCache.getInstance(); + OAuthCacheKey cacheKey = new OAuthCacheKey(resource); + ResourceScopeCacheEntry cacheEntry = new ResourceScopeCacheEntry(resourceScope); + //Store resourceScope in cache even if it is null (to avoid database calls when accessing resources for + //which scopes haven't been defined). + oauthCache.addToCache(cacheKey, cacheEntry); + } + } + return resourceScope; + } + +} diff --git a/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/internal/OAuthExtensionServiceComponent.java b/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/internal/OAuthExtensionServiceComponent.java index dfcdc2dff2..63b4d051da 100644 --- a/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/internal/OAuthExtensionServiceComponent.java +++ b/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/internal/OAuthExtensionServiceComponent.java @@ -24,7 +24,10 @@ import org.osgi.service.component.ComponentContext; import org.wso2.carbon.apimgt.api.APIManagementException; import org.wso2.carbon.apimgt.impl.APIConstants; import org.wso2.carbon.apimgt.impl.APIManagerConfiguration; +import org.wso2.carbon.device.mgt.oauth.extensions.validators.ExtendedJDBCScopeValidator; import org.wso2.carbon.identity.oauth2.OAuth2TokenValidationService; +import org.wso2.carbon.identity.oauth2.validators.JDBCScopeValidator; +import org.wso2.carbon.identity.oauth2.validators.OAuth2ScopeValidator; import org.wso2.carbon.user.core.service.RealmService; import org.wso2.carbon.utils.CarbonUtils; @@ -46,6 +49,12 @@ import java.util.List; * policy="dynamic" * bind="setOAuth2ValidationService" * unbind="unsetOAuth2ValidationService" + * * @scr.reference name="scope.validator.service" + * interface="org.wso2.carbon.identity.oauth2.validators.OAuth2ScopeValidator" + * cardinality="0..n" + * policy="dynamic" + * bind="addScopeValidator" + * unbind="removeScopeValidator" */ public class OAuthExtensionServiceComponent { @@ -53,6 +62,8 @@ public class OAuthExtensionServiceComponent { private static final String REPOSITORY = "repository"; private static final String CONFIGURATION = "conf"; private static final String APIM_CONF_FILE = "api-manager.xml"; + private static final String PERMISSION_SCOPE_PREFIX = "perm"; + private static final String DEFAULT_PREFIX = "default"; @SuppressWarnings("unused") @@ -87,6 +98,13 @@ public class OAuthExtensionServiceComponent { } OAuthExtensionsDataHolder.getInstance().setWhitelistedScopes(whiteList); + + ExtendedJDBCScopeValidator permissionBasedScopeValidator = new ExtendedJDBCScopeValidator(); + JDBCScopeValidator roleBasedScopeValidator = new JDBCScopeValidator(); + OAuthExtensionsDataHolder.getInstance().addScopeValidator(permissionBasedScopeValidator, + PERMISSION_SCOPE_PREFIX); + OAuthExtensionsDataHolder.getInstance().addScopeValidator(roleBasedScopeValidator, + DEFAULT_PREFIX); } catch (APIManagementException e) { log.error("Error occurred while loading DeviceMgtConfig configurations", e); } @@ -147,5 +165,21 @@ public class OAuthExtensionServiceComponent { OAuthExtensionsDataHolder.getInstance().setoAuth2TokenValidationService(null); } + /** + * Add scope validator to the map. + * @param scopesValidator + */ + protected void addScopeValidator(OAuth2ScopeValidator scopesValidator) { + OAuthExtensionsDataHolder.getInstance().addScopeValidator(scopesValidator, DEFAULT_PREFIX); + } + + /** + * unset scope validator. + * @param scopesValidator + */ + protected void removeScopeValidator(OAuth2ScopeValidator scopesValidator) { + OAuthExtensionsDataHolder.getInstance().removeScopeValidator(); + } + } diff --git a/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/internal/OAuthExtensionsDataHolder.java b/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/internal/OAuthExtensionsDataHolder.java index 4f401b3db5..2c4f25705d 100644 --- a/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/internal/OAuthExtensionsDataHolder.java +++ b/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/internal/OAuthExtensionsDataHolder.java @@ -19,9 +19,12 @@ package org.wso2.carbon.device.mgt.oauth.extensions.internal; import org.wso2.carbon.identity.oauth2.OAuth2TokenValidationService; +import org.wso2.carbon.identity.oauth2.validators.OAuth2ScopeValidator; import org.wso2.carbon.user.core.service.RealmService; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * This holds the OSGi service references required for oauth extensions bundle. @@ -31,10 +34,13 @@ public class OAuthExtensionsDataHolder { private RealmService realmService; private OAuth2TokenValidationService oAuth2TokenValidationService; private List whitelistedScopes; + private Map scopeValidators; private static OAuthExtensionsDataHolder thisInstance = new OAuthExtensionsDataHolder(); - private OAuthExtensionsDataHolder() {} + private OAuthExtensionsDataHolder() { + scopeValidators = new HashMap<>(); + } public static OAuthExtensionsDataHolder getInstance() { return thisInstance; @@ -71,4 +77,20 @@ public class OAuthExtensionsDataHolder { this.whitelistedScopes = whitelistedScopes; } + public Map getScopeValidators() { + return scopeValidators; + } + + public void setScopeValidators(Map scopeValidators) { + this.scopeValidators = scopeValidators; + } + + public void addScopeValidator(OAuth2ScopeValidator oAuth2ScopeValidator, String prefix) { + scopeValidators.put(prefix, oAuth2ScopeValidator); + } + + public void removeScopeValidator() { + scopeValidators = null; + } + } diff --git a/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/validators/ExtendedJDBCScopeValidator.java b/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/validators/ExtendedJDBCScopeValidator.java index 8f5ffa2514..58c975bbec 100644 --- a/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/validators/ExtendedJDBCScopeValidator.java +++ b/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/validators/ExtendedJDBCScopeValidator.java @@ -45,7 +45,7 @@ import java.util.List; import java.util.Set; @SuppressWarnings("unused") -public class ExtendedJDBCScopeValidator extends OAuth2ScopeValidator{ +public class ExtendedJDBCScopeValidator extends OAuth2ScopeValidator { private static final Log log = LogFactory.getLog(ExtendedJDBCScopeValidator.class); private static final String UI_EXECUTE = "ui.execute"; diff --git a/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/validators/PermissionBasedScopeValidator.java b/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/validators/PermissionBasedScopeValidator.java new file mode 100644 index 0000000000..5be19a5a0c --- /dev/null +++ b/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/validators/PermissionBasedScopeValidator.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.wso2.carbon.device.mgt.oauth.extensions.validators; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.base.MultitenantConstants; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.oauth.extensions.internal.OAuthExtensionsDataHolder; +import org.wso2.carbon.identity.application.common.model.User; +import org.wso2.carbon.identity.core.util.IdentityTenantUtil; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.dao.TokenMgtDAO; +import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; +import org.wso2.carbon.identity.oauth2.validators.OAuth2ScopeValidator; +import org.wso2.carbon.user.api.AuthorizationManager; +import org.wso2.carbon.user.api.UserStoreException; +import org.wso2.carbon.user.core.service.RealmService; +import org.wso2.carbon.utils.multitenancy.MultitenantUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; + +@SuppressWarnings("unused") +public class PermissionBasedScopeValidator extends OAuth2ScopeValidator { + + private static final Log log = LogFactory.getLog(PermissionBasedScopeValidator.class); + private static final String UI_EXECUTE = "ui.execute"; + + + @Override + public boolean validateScope(AccessTokenDO accessTokenDO, String resourceScope) throws IdentityOAuth2Exception { + //Get the list of scopes associated with the access token + String[] scopes = accessTokenDO.getScope(); + + //If no scopes are associated with the token + if (scopes == null || scopes.length == 0) { + return true; + } + + TokenMgtDAO tokenMgtDAO = new TokenMgtDAO(); + + List scopeList = new ArrayList<>(Arrays.asList(scopes)); + + //If the access token does not bear the scope required for accessing the Resource. + if(!scopeList.contains(resourceScope)){ + if(log.isDebugEnabled()){ + log.debug("Access token '" + accessTokenDO.getAccessToken() + "' does not bear the scope '" + + resourceScope + "'"); + } + return false; + } + + try { + //Get the permissions associated with the scope, if any + Set permissionsOfScope = tokenMgtDAO.getRolesOfScopeByScopeKey(resourceScope); + + //If the scope doesn't have any permissions associated with it. + if(permissionsOfScope == null || permissionsOfScope.isEmpty()){ + if(log.isDebugEnabled()){ + log.debug("Did not find any roles associated to the scope " + resourceScope); + } + return true; + } + + if(log.isDebugEnabled()){ + StringBuilder logMessage = new StringBuilder("Found permissions of scope '" + resourceScope + "' "); + for(String permission : permissionsOfScope){ + logMessage.append(permission); + logMessage.append(", "); + } + log.debug(logMessage.toString()); + } + + User authorizedUser = accessTokenDO.getAuthzUser(); + RealmService realmService = OAuthExtensionsDataHolder.getInstance().getRealmService(); + + int tenantId = realmService.getTenantManager().getTenantId(authorizedUser.getTenantDomain()); + + if (tenantId == 0 || tenantId == -1) { + tenantId = IdentityTenantUtil.getTenantIdOfUser(authorizedUser.getUserName()); + } + + AuthorizationManager authorizationManager; + String[] userRoles; + boolean tenantFlowStarted = false; + + try{ + //If this is a tenant user + if(tenantId != MultitenantConstants.SUPER_TENANT_ID){ + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain( + realmService.getTenantManager().getDomain(tenantId),true); + tenantFlowStarted = true; + } + + authorizationManager = realmService.getTenantUserRealm(tenantId).getAuthorizationManager(); + + } finally { + if (tenantFlowStarted) { + PrivilegedCarbonContext.endTenantFlow(); + } + } + boolean status = false; + String username = MultitenantUtils.getTenantAwareUsername(authorizedUser.getUserName()); + for (String permission : permissionsOfScope) { + if (authorizationManager != null) { + String userStore = authorizedUser.getUserStoreDomain(); + + if (userStore != null) { + status = authorizationManager + .isUserAuthorized(userStore + "/" + username, permission, UI_EXECUTE); + } else { + status = authorizationManager.isUserAuthorized(username , permission, UI_EXECUTE); + } + if (status) { + break; + } + } + } + + if (status) { + if(log.isDebugEnabled()){ + log.debug("User '" + authorizedUser.getUserName() + "' is authorized"); + } + return true; + } + + if(log.isDebugEnabled()){ + log.debug("No permissions associated for the user " + authorizedUser.getUserName()); + } + return false; + + } catch (UserStoreException e) { + //Log and return since we do not want to stop issuing the token in case of scope validation failures. + log.error("Error when getting the tenant's UserStoreManager or when getting roles of user ", e); + return false; + } + } + +} diff --git a/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/validators/RoleBasedScopeValidator.java b/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/validators/RoleBasedScopeValidator.java new file mode 100644 index 0000000000..593d9d0c89 --- /dev/null +++ b/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/validators/RoleBasedScopeValidator.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2013, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.wso2.carbon.device.mgt.oauth.extensions.validators; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.base.MultitenantConstants; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.oauth.extensions.internal.OAuthExtensionsDataHolder; +import org.wso2.carbon.identity.application.common.model.User; +import org.wso2.carbon.identity.base.IdentityConstants; +import org.wso2.carbon.identity.core.util.IdentityTenantUtil; +import org.wso2.carbon.identity.core.util.IdentityUtil; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.dao.TokenMgtDAO; +import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; +import org.wso2.carbon.identity.oauth2.validators.OAuth2ScopeValidator; +import org.wso2.carbon.user.api.UserStoreException; +import org.wso2.carbon.user.api.UserStoreManager; +import org.wso2.carbon.user.core.service.RealmService; +import org.wso2.carbon.utils.multitenancy.MultitenantUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; + + +/** + * The JDBC Scope Validation implementation. This validates the Resource's scope (stored in IDN_OAUTH2_RESOURCE_SCOPE) + * against the Access Token's scopes. + */ +public class RoleBasedScopeValidator extends OAuth2ScopeValidator { + + Log log = LogFactory.getLog(RoleBasedScopeValidator.class); + + @Override + public boolean validateScope(AccessTokenDO accessTokenDO, String resourceScope) throws IdentityOAuth2Exception { + + //Get the list of scopes associated with the access token + String[] scopes = accessTokenDO.getScope(); + + //If no scopes are associated with the token + if (scopes == null || scopes.length == 0) { + return true; + } + + TokenMgtDAO tokenMgtDAO = new TokenMgtDAO(); + + List scopeList = new ArrayList<>(Arrays.asList(scopes)); + + //If the access token does not bear the scope required for accessing the Resource. + if(!scopeList.contains(resourceScope)){ + if(log.isDebugEnabled() && IdentityUtil.isTokenLoggable(IdentityConstants.IdentityTokens.ACCESS_TOKEN)){ + log.debug("Access token '" + accessTokenDO.getAccessToken() + "' does not bear the scope '" + + resourceScope + "'"); + } + return false; + } + + try { + //Get the roles associated with the scope, if any + Set rolesOfScope = tokenMgtDAO.getRolesOfScopeByScopeKey(resourceScope); + + //If the scope doesn't have any roles associated with it. + if(rolesOfScope == null || rolesOfScope.isEmpty()){ + if(log.isDebugEnabled()){ + log.debug("Did not find any roles associated to the scope " + resourceScope); + } + return true; + } + + if(log.isDebugEnabled()){ + StringBuilder logMessage = new StringBuilder("Found roles of scope '" + resourceScope + "' "); + for(String role : rolesOfScope){ + logMessage.append(role); + logMessage.append(", "); + } + log.debug(logMessage.toString()); + } + + User authzUser = accessTokenDO.getAuthzUser(); + RealmService realmService = OAuthExtensionsDataHolder.getInstance().getRealmService(); + + int tenantId = realmService.getTenantManager(). + getTenantId(authzUser.getTenantDomain()); + + if (tenantId == 0 || tenantId == -1) { + tenantId = IdentityTenantUtil.getTenantIdOfUser(authzUser.getUserName()); + } + + UserStoreManager userStoreManager; + String[] userRoles; + boolean tenantFlowStarted = false; + + try{ + //If this is a tenant user + if(tenantId != MultitenantConstants.SUPER_TENANT_ID){ + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain( + realmService.getTenantManager().getDomain(tenantId),true); + tenantFlowStarted = true; + } + + userStoreManager = realmService.getTenantUserRealm(tenantId).getUserStoreManager(); + userRoles = userStoreManager.getRoleListOfUser( + MultitenantUtils.getTenantAwareUsername(authzUser.getUserName())); + } finally { + if (tenantFlowStarted) { + PrivilegedCarbonContext.endTenantFlow(); + } + } + + if(userRoles != null && userRoles.length > 0){ + if(log.isDebugEnabled()){ + StringBuilder logMessage = new StringBuilder("Found roles of user "); + logMessage.append(authzUser.getUserName()); + logMessage.append(" "); + for(String role : userRoles){ + logMessage.append(role); + logMessage.append(", "); + } + log.debug(logMessage.toString()); + } + //Check if the user still has a valid role for this scope. + rolesOfScope.retainAll(Arrays.asList(userRoles)); + return !rolesOfScope.isEmpty(); + } + else{ + if(log.isDebugEnabled()){ + log.debug("No roles associated for the user " + authzUser.getUserName()); + } + return false; + } + + } catch (UserStoreException e) { + //Log and return since we do not want to stop issuing the token in case of scope validation failures. + log.error("Error when getting the tenant's UserStoreManager or when getting roles of user ", e); + return false; + } + } +}