From 0c2de7965fdb8136f596039dfea8b4a27bf1fde7 Mon Sep 17 00:00:00 2001 From: ayyoob Date: Mon, 20 Jun 2016 02:33:17 +0530 Subject: [PATCH] Added device scope validation --- .../pom.xml | 12 +++- .../mgt/oauth/extensions/OAuthExtUtils.java | 56 ++++++++++++++++--- .../grant/ExtendedJWTBearerGrantHandler.java | 14 +++++ .../OAuthExtensionServiceComponent.java | 40 +++++++++++++ .../internal/OAuthExtensionsDataHolder.java | 19 +++++++ 5 files changed, 133 insertions(+), 8 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/grant/ExtendedJWTBearerGrantHandler.java diff --git a/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/pom.xml b/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/pom.xml index 1b3f46322c..8023f94fd9 100644 --- a/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/pom.xml +++ b/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/pom.xml @@ -54,6 +54,14 @@ com.googlecode.json-simple.wso2 json-simple + + org.wso2.carbon.identity + org.wso2.carbon.identity.oauth2.grant.jwt + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + @@ -118,7 +126,9 @@ org.wso2.carbon.identity.oauth.config, org.wso2.carbon.identity.oauth2.dao, org.wso2.carbon.utils.multitenancy, - org.wso2.carbon.base + org.wso2.carbon.base, + org.wso2.carbon.identity.oauth2.grant.jwt.*, + org.wso2.carbon.device.mgt.core.* diff --git a/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/OAuthExtUtils.java b/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/OAuthExtUtils.java index 93a6db287c..97d7e5f5cf 100644 --- a/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/OAuthExtUtils.java +++ b/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/OAuthExtUtils.java @@ -24,6 +24,9 @@ import org.wso2.carbon.apimgt.api.APIManagementException; import org.wso2.carbon.apimgt.impl.APIConstants; import org.wso2.carbon.apimgt.impl.dao.ApiMgtDAO; import org.wso2.carbon.apimgt.impl.utils.APIUtil; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; import org.wso2.carbon.device.mgt.oauth.extensions.internal.OAuthExtensionsDataHolder; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; @@ -48,7 +51,7 @@ public class OAuthExtUtils { private static final String UI_EXECUTE = "ui.execute"; private static final String REST_API_SCOPE_CACHE = "REST_API_SCOPE_CACHE"; private static final int START_INDEX = 0; - + private static final String CDMF_SCOPE_SEPERATOR = "/"; /** * This method is used to get the tenant id when given tenant domain. * @@ -59,7 +62,8 @@ public class OAuthExtUtils { int tenantId = 0; if (tenantDomain != null) { try { - TenantManager tenantManager = OAuthExtensionsDataHolder.getInstance().getRealmService().getTenantManager(); + TenantManager tenantManager = + OAuthExtensionsDataHolder.getInstance().getRealmService().getTenantManager(); tenantId = tenantManager.getTenantId(tenantDomain); } catch (UserStoreException e) { String errorMsg = "Error when getting the tenant id from the tenant domain : " + @@ -121,7 +125,7 @@ public class OAuthExtUtils { if (appScopes.isEmpty()) { if (log.isDebugEnabled()) { log.debug("No scopes defined for the Application " + - tokReqMsgCtx.getOauth2AccessTokenReqDTO().getClientId()); + tokReqMsgCtx.getOauth2AccessTokenReqDTO().getClientId()); } String[] allowedScopes = getAllowedScopes(reqScopeList); @@ -162,6 +166,20 @@ public class OAuthExtUtils { return false; } + /** + * Determines if the scope is specified with CDMF device scope prefix. + * + * @param scope - The scope key to check + * @return - 'true' if the scope has the prefix. 'false' if not. + */ + private static boolean isCDMFDeviceSpecificScope(String scope) { + // load white listed scopes + if (scope.startsWith(OAuthExtensionsDataHolder.getInstance().getDeviceScope())) { + return true; + } + return false; + } + /** * Get the set of default scopes. If a requested scope is matches with the patterns specified in the white list, * then such scopes will be issued without further validation. If the scope list is empty, @@ -191,7 +209,7 @@ public class OAuthExtUtils { * * @param tokReqMsgCtx OAuth token request message context. * @param reqScopeList Requested scope list. - * @param appScopes App scopes. + * @param appScopes App scopes. * @return Returns a list of scopes. */ private static List getAuthorizedScopes(OAuthTokenReqMessageContext tokReqMsgCtx, List reqScopeList, @@ -213,7 +231,8 @@ public class OAuthExtUtils { tenantId = IdentityTenantUtil.getTenantIdOfUser(username); } - UserRealm userRealm = OAuthExtensionsDataHolder.getInstance().getRealmService().getTenantUserRealm(tenantId); + UserRealm userRealm = OAuthExtensionsDataHolder.getInstance().getRealmService().getTenantUserRealm( + tenantId); //Iterate the requested scopes list. for (String scope : reqScopeList) { @@ -222,9 +241,11 @@ public class OAuthExtUtils { //Get the set of roles associated with the requested scope. String appPermissions = appScopes.get(scope); - //If the scope has been defined in the context of the App and if permissions have been defined for the scope + //If the scope has been defined in the context of the App and if permissions have been defined for + // the scope if (appPermissions != null && appPermissions.length() != 0) { - List permissions = new ArrayList<>(Arrays.asList(appPermissions.replaceAll(" ", "").split(","))); + List permissions = new ArrayList<>(Arrays.asList(appPermissions.replaceAll(" ", "").split( + ","))); //Check if user has at least one of the permission associated with the scope if (!permissions.isEmpty()) { @@ -254,6 +275,27 @@ public class OAuthExtUtils { else if (appScopes.containsKey(scope) || isWhiteListedScope(scope)) { authorizedScopes.add(scope); } + + //check whether is device specific scope (CDMF) + else if (isCDMFDeviceSpecificScope(scope)) { + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(tenantId, true); + try { + String deviceId[] = scope.split(CDMF_SCOPE_SEPERATOR); + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(deviceId[2], deviceId[1]); + boolean enrolled = OAuthExtensionsDataHolder.getInstance().getDeviceManagementService().isEnrolled( + deviceIdentifier, tokReqMsgCtx.getAuthorizedUser().getUserName()); + if (enrolled) { + authorizedScopes.add(scope); + } + } catch (DeviceManagementException e) { + log.error("Error occurred while checking device scope with CDMF", e); + } catch (ArrayIndexOutOfBoundsException e) { + log.error("Invalid scope format, have to adhere [prefix/devicetype/deviceId]", e); + }finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } } } catch (UserStoreException e) { log.error("Error occurred while initializing user store.", e); diff --git a/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/handlers/grant/ExtendedJWTBearerGrantHandler.java b/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/handlers/grant/ExtendedJWTBearerGrantHandler.java new file mode 100644 index 0000000000..cb7fcdef19 --- /dev/null +++ b/components/identity-extensions/org.wso2.carbon.device.mgt.oauth.extensions/src/main/java/org/wso2/carbon/device/mgt/oauth/extensions/handlers/grant/ExtendedJWTBearerGrantHandler.java @@ -0,0 +1,14 @@ +package org.wso2.carbon.device.mgt.oauth.extensions.handlers.grant; + +import org.wso2.carbon.device.mgt.oauth.extensions.OAuthExtUtils; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.grant.jwt.JWTBearerGrantHandler; +import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; + +public class ExtendedJWTBearerGrantHandler extends JWTBearerGrantHandler { + + @Override + public boolean validateScope(OAuthTokenReqMessageContext tokReqMsgCtx) throws IdentityOAuth2Exception { + return OAuthExtUtils.setScopes(tokReqMsgCtx); + } +} 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 3cdeeb5e8d..350de887a4 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 @@ -25,6 +25,7 @@ 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.common.permission.mgt.PermissionManagerService; +import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; import org.wso2.carbon.identity.oauth2.OAuth2TokenValidationService; import org.wso2.carbon.user.core.service.RealmService; import org.wso2.carbon.utils.CarbonUtils; @@ -53,6 +54,12 @@ import java.util.List; * policy="dynamic" * bind="setPermissionManagerService" * unbind="unsetPermissionManagerService" + * @scr.reference name="org.wso2.carbon.device.manager" + * interface="org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService" + * cardinality="1..1" + * policy="dynamic" + * bind="setDeviceManagementService" + * unbind="unsetDeviceManagementService" */ public class OAuthExtensionServiceComponent { @@ -60,6 +67,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 API_KEY_MANGER_DEVICE_SCOPE = "APIKeyValidator.DeviceScope"; + private static final String CDMF_DEVICE_SCOPE_PREFIX = "cdmf_"; @SuppressWarnings("unused") @@ -94,6 +103,15 @@ public class OAuthExtensionServiceComponent { OAuthExtensionsDataHolder.getInstance().setWhitelistedScopes(whiteList); + // Read device scope(Specific to CDMF) from Configuration. + String deviceScope = configuration.getFirstProperty(API_KEY_MANGER_DEVICE_SCOPE); + + if (deviceScope == null) { + deviceScope = CDMF_DEVICE_SCOPE_PREFIX; + } + + OAuthExtensionsDataHolder.getInstance().setDeviceScope(deviceScope); + } catch (APIManagementException e) { log.error("Error occurred while loading APIM configurations", e); } @@ -178,4 +196,26 @@ public class OAuthExtensionServiceComponent { OAuthExtensionsDataHolder.getInstance().setPermissionManagerService(null); } + /** + * Set DeviceManagementProviderService + * @param deviceManagerService An instance of PermissionManagerService + */ + protected void setDeviceManagementService(DeviceManagementProviderService deviceManagerService) { + if (log.isDebugEnabled()) { + log.debug("Setting Device Management Service"); + } + OAuthExtensionsDataHolder.getInstance().setDeviceManagementService(deviceManagerService); + } + + /** + * unset DeviceManagementProviderService + * @param deviceManagementService An instance of PermissionManagerService + */ + protected void unsetDeviceManagementService(DeviceManagementProviderService deviceManagementService) { + if (log.isDebugEnabled()) { + log.debug("Removing Device Management Service"); + } + OAuthExtensionsDataHolder.getInstance().setDeviceManagementService(null); + } + } 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 f591688001..2f052094d7 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,6 +19,7 @@ package org.wso2.carbon.device.mgt.oauth.extensions.internal; import org.wso2.carbon.device.mgt.common.permission.mgt.PermissionManagerService; +import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; import org.wso2.carbon.identity.oauth2.OAuth2TokenValidationService; import org.wso2.carbon.user.core.service.RealmService; @@ -33,6 +34,8 @@ public class OAuthExtensionsDataHolder { private OAuth2TokenValidationService oAuth2TokenValidationService; private PermissionManagerService permissionManagerService; private List whitelistedScopes; + private String deviceScope; + private DeviceManagementProviderService deviceManagementService; private static OAuthExtensionsDataHolder thisInstance = new OAuthExtensionsDataHolder(); @@ -83,4 +86,20 @@ public class OAuthExtensionsDataHolder { public void setWhitelistedScopes(List whitelistedScopes) { this.whitelistedScopes = whitelistedScopes; } + + public void setDeviceScope(String deviceScope) { + this.deviceScope = deviceScope; + } + + public String getDeviceScope() { + return deviceScope; + } + + public DeviceManagementProviderService getDeviceManagementService() { + return deviceManagementService; + } + + public void setDeviceManagementService(DeviceManagementProviderService deviceManagementService) { + this.deviceManagementService = deviceManagementService; + } }