From 59e2a33e4a238ec40997ad0a28d53cb6fa926991 Mon Sep 17 00:00:00 2001 From: ayyoob Date: Sat, 19 Nov 2016 11:02:48 +0530 Subject: [PATCH] exposed device access authorisation as a service --- .../mgt/jaxrs/beans/AuthorizationRequest.java | 45 +++++++++ ...DeviceAccessAuthorizationAdminService.java | 91 +++++++++++++++++++ ...ceAccessAuthorizationAdminServiceImpl.java | 85 +++++++++++++++++ .../DeviceAccessAuthorizationServiceImpl.java | 3 +- .../app/modules/oauth/token-handler-utils.js | 18 +++- .../app/modules/oauth/token-handlers.js | 64 ++++++------- .../jwt/client/extension/JWTClient.java | 3 + 7 files changed, 275 insertions(+), 34 deletions(-) create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/beans/AuthorizationRequest.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceAccessAuthorizationAdminService.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceAccessAuthorizationAdminServiceImpl.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/beans/AuthorizationRequest.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/beans/AuthorizationRequest.java new file mode 100644 index 0000000000..3a63938b8b --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/beans/AuthorizationRequest.java @@ -0,0 +1,45 @@ +package org.wso2.carbon.device.mgt.jaxrs.beans; + +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; + +import java.util.List; + +public class AuthorizationRequest { + + String tenantDomain; + String username; + List deviceIdentifiers; + List permissions; + + public String getTenantDomain() { + return tenantDomain; + } + + public void setTenantDomain(String tenantDomain) { + this.tenantDomain = tenantDomain; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public List getDeviceIdentifiers() { + return deviceIdentifiers; + } + + public void setDeviceIdentifiers(List deviceIdentifiers) { + this.deviceIdentifiers = deviceIdentifiers; + } + + public List getPermissions() { + return permissions; + } + + public void setPermissions(List permissions) { + this.permissions = permissions; + } +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceAccessAuthorizationAdminService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceAccessAuthorizationAdminService.java new file mode 100644 index 0000000000..a779b73e75 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceAccessAuthorizationAdminService.java @@ -0,0 +1,91 @@ +/* + * 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.jaxrs.service.api.admin; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import io.swagger.annotations.ResponseHeader; +import org.wso2.carbon.apimgt.annotations.api.API; +import org.wso2.carbon.apimgt.annotations.api.Permission; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.common.authorization.DeviceAuthorizationResult; +import org.wso2.carbon.device.mgt.common.operation.mgt.Activity; +import org.wso2.carbon.device.mgt.jaxrs.beans.AuthorizationRequest; +import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse; + +import javax.validation.constraints.Size; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +@API(name = "DeviceAuthorizationAdmin", version = "1.0.0", context = "/api/device-mgt/v1.0/admin/authorization", + tags = {"device_management"}) +@Path("/admin/authorization") +@Api(value = "Device Authorization Administrative Service", description = "This an API intended to be used by " + + "'internal' components to log in as an admin user and validate whether the user/device are trusted entity." + + "Further, this is strictly restricted to admin users only ") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +/** + * This interface provided the definition of the device - user access verification service. + */ +public interface DeviceAccessAuthorizationAdminService { + + @POST + @ApiOperation( + consumes = MediaType.APPLICATION_JSON, + produces = MediaType.APPLICATION_JSON, + httpMethod = "POST", + value = "Check for device access authorization\n", + notes = "This is an internal API that can be used to check for authorization.", + response = DeviceAuthorizationResult.class, + tags = "Authorization Administrative Service") + @ApiResponses(value = { + @ApiResponse( + code = 200, + message = "OK. \n Authorized device list will be delivered to the requested services", + response = DeviceAuthorizationResult.class), + @ApiResponse( + code = 400, + message = "Bad Request. \n Invalid request or validation error.", + response = ErrorResponse.class), + @ApiResponse( + code = 404, + message = "Not Found. \n The specified resource does not exist."), + @ApiResponse( + code = 415, + message = "Unsupported media type. \n The entity of the request was in a not supported format."), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n Server error occurred while checking the authorization" + + " for a specified set of devices.", + response = ErrorResponse.class) + }) + @Permission(name = "Check the access authorization of the device", permission = "/device-mgt/device/authorize") + Response isAuthorized(AuthorizationRequest authorizationRequest); +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceAccessAuthorizationAdminServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceAccessAuthorizationAdminServiceImpl.java new file mode 100644 index 0000000000..6dd10edf14 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceAccessAuthorizationAdminServiceImpl.java @@ -0,0 +1,85 @@ +/* + * 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.jaxrs.service.impl.admin; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.base.MultitenantConstants; +import org.wso2.carbon.context.CarbonContext; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationException; +import org.wso2.carbon.device.mgt.common.authorization.DeviceAuthorizationResult; +import org.wso2.carbon.device.mgt.jaxrs.beans.AuthorizationRequest; +import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse; +import org.wso2.carbon.device.mgt.jaxrs.service.api.admin.DeviceAccessAuthorizationAdminService; +import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +@Path("/admin/authorization") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class DeviceAccessAuthorizationAdminServiceImpl implements DeviceAccessAuthorizationAdminService { + + private static final Log log = LogFactory.getLog(DeviceAccessAuthorizationAdminServiceImpl.class); + + @POST + @Override + public Response isAuthorized(AuthorizationRequest authorizationRequest) { + try { + int currentTenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); + if (MultitenantConstants.SUPER_TENANT_ID != currentTenantId) { + return Response.status(Response.Status.UNAUTHORIZED).entity( + new ErrorResponse.ErrorResponseBuilder().setMessage( + "Current logged in user is not authorized to perform this operation").build()).build(); + } + if (authorizationRequest.getTenantDomain() == null || authorizationRequest.getTenantDomain().isEmpty()) { + authorizationRequest.setTenantDomain( + PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain()); + } + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain( + authorizationRequest.getTenantDomain(), true); + String[] permissionArr = null; + if (authorizationRequest.getPermissions() != null && authorizationRequest.getPermissions().size() > 0) { + permissionArr = new String[authorizationRequest.getPermissions().size()]; + permissionArr = authorizationRequest.getPermissions().toArray(permissionArr); + } + DeviceAuthorizationResult deviceAuthorizationResult = + DeviceMgtAPIUtils.getDeviceAccessAuthorizationService().isUserAuthorized( + authorizationRequest.getDeviceIdentifiers(), authorizationRequest.getUsername() + , permissionArr); + + return Response.status(Response.Status.OK).entity(deviceAuthorizationResult).build(); + } catch (DeviceAccessAuthorizationException e) { + String msg = "Error occurred at server side while fetching authorization information."; + log.error(msg, e); + return Response.serverError().entity( + new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build(); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/authorization/DeviceAccessAuthorizationServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/authorization/DeviceAccessAuthorizationServiceImpl.java index 0703d4d39d..dbd2facc7d 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/authorization/DeviceAccessAuthorizationServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/authorization/DeviceAccessAuthorizationServiceImpl.java @@ -134,7 +134,8 @@ public class DeviceAccessAuthorizationServiceImpl implements DeviceAccessAuthori } else { try { if (groupPermissions == null || groupPermissions.length == 0) { - return null; + deviceAuthorizationResult.setUnauthorizedDevices(deviceIdentifiers); + return deviceAuthorizationResult; } //check for group permissions boolean isAuthorized = true; diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/oauth/token-handler-utils.js b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/oauth/token-handler-utils.js index f31e72622c..27fc42bd90 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/oauth/token-handler-utils.js +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/oauth/token-handler-utils.js @@ -109,7 +109,7 @@ var utils = function () { var xhr = new XMLHttpRequest(); xhr.open("POST", requestURL, false); xhr.setRequestHeader("Content-Type", "application/json"); - xhr.setRequestHeader("Authorization", "Bearer " + jwtToken); + xhr.setRequestHeader("Authorization", "X-JWT-Assertion " + jwtToken); xhr.send(); if (xhr["status"] == 201 && xhr["responseText"]) { @@ -291,5 +291,21 @@ var utils = function () { } }; + publicMethods["getJwtToken"] = function (username) { + if (!username) { + log.error("{/app/modules/oauth/token-handler-utils.js} Error in retrieving new jwt token"); + return null; + } else { + var JWTClientManagerServicePackagePath = + "org.wso2.carbon.identity.jwt.client.extension.service.JWTClientManagerService"; + //noinspection JSUnresolvedFunction, JSUnresolvedVariable + var JWTClientManagerService = carbon.server.osgiService(JWTClientManagerServicePackagePath); + //noinspection JSUnresolvedFunction + var jwtClient = JWTClientManagerService.getJWTClient(); + // returning access token by JWT grant type + return jwtClient.getJwtToken(username); + } + }; + return publicMethods; }(); diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/oauth/token-handlers.js b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/oauth/token-handlers.js index 9fb3198e05..a9cb2b870c 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/oauth/token-handlers.js +++ b/components/device-mgt/org.wso2.carbon.device.mgt.ui/src/main/resources/jaggeryapps/devicemgt/app/modules/oauth/token-handlers.js @@ -136,43 +136,43 @@ var handlers = function () { "client credentials to session context. No username of logged in user is found as " + "input - setUpEncodedTenantBasedClientAppCredentials(x)"); } else { - var dynamicClientAppCredentials = tokenUtil.getDynamicClientAppCredentials(); - if (!dynamicClientAppCredentials) { - throw new Error("{/app/modules/oauth/token-handlers.js} Could not set up encoded tenant based " + + if (devicemgtProps["apimgt-gateway"]) { + var jwtToken = tokenUtil.getJwtToken(username); + if (!jwtToken) { + throw new Error("{/app/modules/oauth/token-handlers.js} Could not set up encoded tenant based " + "client credentials to session context as the server is unable to obtain " + - "dynamic client credentials - setUpEncodedTenantBasedClientAppCredentials(x)"); - } else { - if (devicemgtProps["apimgt-gateway"]) { - var jwtToken = tokenUtil.getAccessTokenByJWTGrantType(dynamicClientAppCredentials); - if (!jwtToken) { - throw new Error("{/app/modules/oauth/token-handlers.js} Could not set up encoded tenant based " + - "client credentials to session context as the server is unable to obtain " + - "a jwt token - setUpEncodedTenantBasedClientAppCredentials(x)"); + "a jwt token - setUpEncodedTenantBasedClientAppCredentials(x)"); + } else { + var tenantBasedClientAppCredentials = tokenUtil. + getTenantBasedClientAppCredentials(username, jwtToken); + if (!tenantBasedClientAppCredentials) { + throw new Error("{/app/modules/oauth/token-handlers.js} Could not set up encoded tenant " + + "based client credentials to session context as the server is unable " + + "to obtain such credentials - setUpEncodedTenantBasedClientAppCredentials(x)"); } else { - var tenantBasedClientAppCredentials = tokenUtil. - getTenantBasedClientAppCredentials(username, jwtToken); - if (!tenantBasedClientAppCredentials) { - throw new Error("{/app/modules/oauth/token-handlers.js} Could not set up encoded tenant " + - "based client credentials to session context as the server is unable " + - "to obtain such credentials - setUpEncodedTenantBasedClientAppCredentials(x)"); - } else { - var encodedTenantBasedClientAppCredentials = - tokenUtil.encode(tenantBasedClientAppCredentials["clientId"] + ":" + - tenantBasedClientAppCredentials["clientSecret"]); - // setting up encoded tenant based client credentials to session context. - session.put(constants["ENCODED_TENANT_BASED_CLIENT_APP_CREDENTIALS"], - encodedTenantBasedClientAppCredentials); - } + var encodedTenantBasedClientAppCredentials = + tokenUtil.encode(tenantBasedClientAppCredentials["clientId"] + ":" + + tenantBasedClientAppCredentials["clientSecret"]); + // setting up encoded tenant based client credentials to session context. + session.put(constants["ENCODED_TENANT_BASED_CLIENT_APP_CREDENTIALS"], + encodedTenantBasedClientAppCredentials); } - } else { - var encodedTenantBasedClientAppCredentials = - tokenUtil.encode(dynamicClientAppCredentials["clientId"] + ":" + - dynamicClientAppCredentials["clientSecret"]); - // setting up encoded tenant based client credentials to session context. - session.put(constants["ENCODED_TENANT_BASED_CLIENT_APP_CREDENTIALS"], - encodedTenantBasedClientAppCredentials); } + } else { + var dynamicClientAppCredentials = tokenUtil.getDynamicClientAppCredentials(); + if (!dynamicClientAppCredentials) { + throw new Error("{/app/modules/oauth/token-handlers.js} Could not set up encoded tenant based " + + "client credentials to session context as the server is unable to obtain " + + "dynamic client credentials - setUpEncodedTenantBasedClientAppCredentials(x)"); + } + var encodedTenantBasedClientAppCredentials = + tokenUtil.encode(dynamicClientAppCredentials["clientId"] + ":" + + dynamicClientAppCredentials["clientSecret"]); + // setting up encoded tenant based client credentials to session context. + session.put(constants["ENCODED_TENANT_BASED_CLIENT_APP_CREDENTIALS"], + encodedTenantBasedClientAppCredentials); } + } }; diff --git a/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/JWTClient.java b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/JWTClient.java index d117ef1eca..6698b8c12f 100644 --- a/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/JWTClient.java +++ b/components/identity-extensions/org.wso2.carbon.identity.jwt.client.extension/src/main/java/org/wso2/carbon/identity/jwt/client/extension/JWTClient.java @@ -156,6 +156,9 @@ public class JWTClient { return new String(Base64.encodeBase64((consumerKey + ":" + consumerSecret).getBytes())); } + public String getJwtToken(String username) throws JWTClientException { + return JWTClientUtil.generateSignedJWTAssertion(username, jwtConfig, isDefaultJWTClient); + } }