Merge pull request #426 from ayyoob/IoTS-1.0.0

exposed device access authorisation as a service
revert-70aa11f8
Ruwan 8 years ago committed by GitHub
commit f3b3389a8a

@ -78,10 +78,12 @@
<dependency> <dependency>
<groupId>org.wso2.carbon</groupId> <groupId>org.wso2.carbon</groupId>
<artifactId>org.wso2.carbon.base</artifactId> <artifactId>org.wso2.carbon.base</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.googlecode.json-simple.wso2</groupId> <groupId>com.googlecode.json-simple.wso2</groupId>
<artifactId>json-simple</artifactId> <artifactId>json-simple</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.wso2.carbon</groupId> <groupId>org.wso2.carbon</groupId>
@ -163,7 +165,13 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.wso2.carbon.devicemgt</groupId> <groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.apimgt.annotations</artifactId> <artifactId>org.wso2.carbon.device.mgt.core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.common</artifactId>
<scope>provided</scope>
</dependency> </dependency>
</dependencies> </dependencies>

@ -29,6 +29,7 @@ import org.wso2.carbon.apimgt.application.extension.dto.ApiApplicationKey;
import org.wso2.carbon.apimgt.application.extension.exception.APIManagerException; import org.wso2.carbon.apimgt.application.extension.exception.APIManagerException;
import org.wso2.carbon.base.MultitenantConstants; import org.wso2.carbon.base.MultitenantConstants;
import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.common.DeviceManagementException;
import org.wso2.carbon.user.api.UserStoreException; import org.wso2.carbon.user.api.UserStoreException;
import javax.ws.rs.DELETE; import javax.ws.rs.DELETE;
@ -36,6 +37,8 @@ import javax.ws.rs.POST;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.QueryParam; import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.Arrays;
public class ApiApplicationRegistrationServiceImpl implements ApiApplicationRegistrationService { public class ApiApplicationRegistrationServiceImpl implements ApiApplicationRegistrationService {
@ -62,7 +65,8 @@ public class ApiApplicationRegistrationServiceImpl implements ApiApplicationRegi
PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(username); PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(username);
APIManagementProviderService apiManagementProviderService = APIUtil.getAPIManagementProviderService(); APIManagementProviderService apiManagementProviderService = APIUtil.getAPIManagementProviderService();
ApiApplicationKey apiApplicationKey = apiManagementProviderService.generateAndRetrieveApplicationKeys( ApiApplicationKey apiApplicationKey = apiManagementProviderService.generateAndRetrieveApplicationKeys(
applicationName, ApiApplicationConstants.DEFAULT_TOKEN_TYPE, username, false); applicationName, APIUtil.getAllowedApisTags().toArray(new String[APIUtil.getAllowedApisTags().size()]),
ApiApplicationConstants.DEFAULT_TOKEN_TYPE, username, false);
return Response.status(Response.Status.CREATED).entity(apiApplicationKey.toString()).build(); return Response.status(Response.Status.CREATED).entity(apiApplicationKey.toString()).build();
} catch (APIManagerException e) { } catch (APIManagerException e) {
String msg = "Error occurred while registering an application '" + applicationName + "'"; String msg = "Error occurred while registering an application '" + applicationName + "'";
@ -72,6 +76,10 @@ public class ApiApplicationRegistrationServiceImpl implements ApiApplicationRegi
String msg = "Failed to retrieve the tenant" + tenantDomain + "'"; String msg = "Failed to retrieve the tenant" + tenantDomain + "'";
log.error(msg, e); log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build(); return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
} catch (DeviceManagementException e) {
String msg = "Failed to retrieve the device service";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
} finally { } finally {
PrivilegedCarbonContext.endTenantFlow(); PrivilegedCarbonContext.endTenantFlow();
} }
@ -81,6 +89,13 @@ public class ApiApplicationRegistrationServiceImpl implements ApiApplicationRegi
@POST @POST
public Response register(RegistrationProfile registrationProfile) { public Response register(RegistrationProfile registrationProfile) {
try { try {
if (registrationProfile.getTags() == null || registrationProfile.getTags().length == 0) {
return Response.status(Response.Status.NOT_ACCEPTABLE).entity("Tags should not be empty").build();
}
if (!APIUtil.getAllowedApisTags().containsAll(Arrays.asList(registrationProfile.getTags()))) {
return Response.status(Response.Status.NOT_ACCEPTABLE).entity("APIs(Tags) are not allowed to this user."
).build();
}
String username = APIUtil.getAuthenticatedUser() + "@" + APIUtil.getTenantDomainOftheUser(); String username = APIUtil.getAuthenticatedUser() + "@" + APIUtil.getTenantDomainOftheUser();
APIManagementProviderService apiManagementProviderService = APIUtil.getAPIManagementProviderService(); APIManagementProviderService apiManagementProviderService = APIUtil.getAPIManagementProviderService();
if (registrationProfile.isMappingAnExistingOAuthApp()) { if (registrationProfile.isMappingAnExistingOAuthApp()) {
@ -109,6 +124,10 @@ public class ApiApplicationRegistrationServiceImpl implements ApiApplicationRegi
+ registrationProfile.getApplicationName() + "'"; + registrationProfile.getApplicationName() + "'";
log.error(msg, e); log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("false").build(); return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("false").build();
} catch (DeviceManagementException e) {
String msg = "Failed to retrieve the device service";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
} }
} }

@ -22,14 +22,19 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService; import org.wso2.carbon.apimgt.application.extension.APIManagementProviderService;
import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.common.DeviceManagementException;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.user.core.service.RealmService; import org.wso2.carbon.user.core.service.RealmService;
import java.util.List;
/** /**
* This class provides utility functions used by REST-API. * This class provides utility functions used by REST-API.
*/ */
public class APIUtil { public class APIUtil {
private static Log log = LogFactory.getLog(APIUtil.class); private static Log log = LogFactory.getLog(APIUtil.class);
private static final String DEFAULT_CDMF_API_TAG = "device_management";
public static String getAuthenticatedUser() { public static String getAuthenticatedUser() {
PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext(); PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
@ -70,4 +75,23 @@ public class APIUtil {
} }
return realmService; return realmService;
} }
public static DeviceManagementProviderService getDeviceManagementProviderService() {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
DeviceManagementProviderService deviceManagementProviderService =
(DeviceManagementProviderService) ctx.getOSGiService(DeviceManagementProviderService.class, null);
if (deviceManagementProviderService == null) {
String msg = "Device Management service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
return deviceManagementProviderService;
}
public static List<String> getAllowedApisTags() throws DeviceManagementException {
//Todo get allowed cdmf service tags from config.
List<String> allowedApisTags = getDeviceManagementProviderService().getAvailableDeviceTypes();
allowedApisTags.add(DEFAULT_CDMF_API_TAG);
return allowedApisTags;
}
} }

@ -41,20 +41,6 @@ public interface APIManagementProviderService {
String keyType, String username, boolean isAllowedAllDomains) String keyType, String username, boolean isAllowedAllDomains)
throws APIManagerException; throws APIManagerException;
/**
* Generate and retreive application keys. if the application does exist then
* create it and subscribe to all apis.
*
* @param apiApplicationName name of the application.
* @param keyType of the application.
* @param username to whom the application is created
* @return consumerkey and secrete of the created application.
* @throws APIManagerException
*/
ApiApplicationKey generateAndRetrieveApplicationKeys(String apiApplicationName, String keyType,
String username, boolean isAllowedAllDomains)
throws APIManagerException;
/** /**
* Register existing Oauth application as apim application. * Register existing Oauth application as apim application.
*/ */

@ -43,70 +43,6 @@ public class APIManagementProviderServiceImpl implements APIManagementProviderSe
private static final Log log = LogFactory.getLog(APIManagementProviderServiceImpl.class); private static final Log log = LogFactory.getLog(APIManagementProviderServiceImpl.class);
/**
* {@inheritDoc}
*/
@Override
public ApiApplicationKey generateAndRetrieveApplicationKeys(String apiApplicationName, String keyType,
String username, boolean isAllowedAllDomains)
throws APIManagerException {
try {
APIManagerUtil.loadTenantRegistry();
APIConsumer apiConsumer = APIManagerFactory.getInstance().getAPIConsumer(username);
String groupId = getLoggedInUserGroupId(username, APIManagerUtil.getTenantDomain());
int applicationId = createApplicationAndSubscribeToAllAPIs(apiApplicationName, username);
Application[] applications = apiConsumer.getApplications(apiConsumer.getSubscriber(username), groupId);
Application application = null;
for (Application app : applications) {
if (app.getId() == applicationId) {
application = app;
}
}
if (application == null) {
throw new APIManagerException("Api application creation failed for " + apiApplicationName +
" to the user " + username);
}
APIKey retrievedApiApplicationKey = null;
for (APIKey apiKey : application.getKeys()) {
String applicationKeyType = apiKey.getType();
if (applicationKeyType != null && applicationKeyType.equals(keyType)) {
retrievedApiApplicationKey = apiKey;
break;
}
}
if (retrievedApiApplicationKey != null) {
ApiApplicationKey apiApplicationKey = new ApiApplicationKey();
apiApplicationKey.setConsumerKey(retrievedApiApplicationKey.getConsumerKey());
apiApplicationKey.setConsumerSecret(retrievedApiApplicationKey.getConsumerSecret());
return apiApplicationKey;
}
String[] allowedDomains = new String[1];
if (isAllowedAllDomains) {
allowedDomains[0] = ApiApplicationConstants.ALLOWED_DOMAINS;
} else {
allowedDomains[0] = APIManagerUtil.getTenantDomain();
}
JSONObject jsonObject = new JSONObject();
jsonObject.put(ApiApplicationConstants.JSONSTRING_USERNAME_TAG, username);
String ownerJsonString = jsonObject.toJSONString();
Map<String, Object> keyDetails = apiConsumer.requestApprovalForApplicationRegistration(username,
apiApplicationName,
keyType, "",
allowedDomains,
ApiApplicationConstants.DEFAULT_VALIDITY_PERIOD,
"null", groupId,
ownerJsonString);
ApiApplicationKey apiApplicationKey = new ApiApplicationKey();
apiApplicationKey.setConsumerKey((String) keyDetails.get(APIConstants.FrontEndParameterNames
.CONSUMER_KEY));
apiApplicationKey.setConsumerSecret((String) keyDetails.get(
APIConstants.FrontEndParameterNames.CONSUMER_SECRET));
return apiApplicationKey;
} catch (APIManagementException e) {
throw new APIManagerException("Failed to register a api application : " + apiApplicationName, e);
}
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@ -385,43 +321,6 @@ public class APIManagementProviderServiceImpl implements APIManagementProviderSe
} }
} }
/**
* This method registers an api application and then subscribe the application to the api.
*
* @param username subscription is created for the user.
* @throws APIManagerException
*/
private int createApplicationAndSubscribeToAllAPIs(String apiApplicationName, String username)
throws APIManagerException {
try {
APIConsumer apiConsumer = APIManagerFactory.getInstance().getAPIConsumer(username);
String groupId = getLoggedInUserGroupId(username, APIManagerUtil.getTenantDomain());
int applicationId = createApplication(apiConsumer, apiApplicationName, username, groupId);
String tenantDomain = MultitenantUtils.getTenantDomain(username);
Set<API> userVisibleAPIs = apiConsumer.getAllPublishedAPIs(tenantDomain);
if (!MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
userVisibleAPIs.addAll(apiConsumer.getAllPublishedAPIs(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME));
}
Subscriber subscriber = apiConsumer.getSubscriber(username);
Set<SubscribedAPI> subscribedAPIs = apiConsumer.getSubscribedAPIs(subscriber);
for (API visibleApi : userVisibleAPIs) {
APIIdentifier apiIdentifier = visibleApi.getId();
boolean isSubscribed = false;
for (SubscribedAPI subscribedAPI : subscribedAPIs) {
if (subscribedAPI.getApiId().equals(apiIdentifier)) {
isSubscribed = true;
}
}
if (!isSubscribed) {
addSubscription(apiConsumer, apiIdentifier, applicationId, username);
}
}
return applicationId;
} catch (APIManagementException e) {
throw new APIManagerException("Failed to fetch device apis information for the user " + username, e);
}
}
private String getLoggedInUserGroupId(String username, String tenantDomain) throws APIManagerException { private String getLoggedInUserGroupId(String username, String tenantDomain) throws APIManagerException {
JSONObject loginInfoJsonObj = new JSONObject(); JSONObject loginInfoJsonObj = new JSONObject();
try { try {

@ -34,6 +34,10 @@
<url>http://wso2.org</url> <url>http://wso2.org</url>
<dependencies> <dependencies>
<dependency>
<groupId>commons-lang.wso2</groupId>
<artifactId>commons-lang</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.apache.axis2.wso2</groupId> <groupId>org.apache.axis2.wso2</groupId>
<artifactId>axis2</artifactId> <artifactId>axis2</artifactId>
@ -81,7 +85,7 @@
<Bundle-Version>${carbon.device.mgt.version}</Bundle-Version> <Bundle-Version>${carbon.device.mgt.version}</Bundle-Version>
<Bundle-Description>Device Type Deployer Bundle</Bundle-Description> <Bundle-Description>Device Type Deployer Bundle</Bundle-Description>
<Export-Package> <Export-Package>
!org.wso2.carbon.device.mgt.extensions.push.notification.provider.internal, !org.wso2.carbon.device.mgt.extensions.device.type.deployer.internal,
org.wso2.carbon.device.mgt.extensions.device.type.deployer.* org.wso2.carbon.device.mgt.extensions.device.type.deployer.*
</Export-Package> </Export-Package>
<Import-Package> <Import-Package>
@ -92,7 +96,7 @@
javax.xml.parsers; version="${javax.xml.parsers.import.pkg.version}", javax.xml.parsers; version="${javax.xml.parsers.import.pkg.version}",
org.apache.axis2.context, org.apache.axis2.context,
org.apache.axis2.deployment.*, org.apache.axis2.deployment.*,
org.apache.commons.lang, org.apache.commons.lang;version="${commons-lang.wso2.osgi.version.range}",
org.apache.commons.logging, org.apache.commons.logging,
org.osgi.framework, org.osgi.framework,
org.osgi.service.component, org.osgi.service.component,

@ -0,0 +1,65 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* Licensed 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.beans;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import java.util.List;
@ApiModel(value = "AuthorizationRequest", description = "Authorization details together with deviceIdentifier and permission")
public class AuthorizationRequest {
@ApiModelProperty(name = "tenantDomain", value = "tenant domain.", required = false)
String tenantDomain;
@ApiModelProperty(name = "username", value = "username of the user, to whom the device identifiers needs to be verified", required = true)
String username;
@ApiModelProperty(name = "deviceIdentifiers", value = "list of devices that needs to be verified against the user", required = true)
List<DeviceIdentifier> deviceIdentifiers;
@ApiModelProperty(name = "permission", value = "if null then checks against the owner else it could be grouping permission", required = false)
List<String> 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<DeviceIdentifier> getDeviceIdentifiers() {
return deviceIdentifiers;
}
public void setDeviceIdentifiers(List<DeviceIdentifier> deviceIdentifiers) {
this.deviceIdentifiers = deviceIdentifiers;
}
public List<String> getPermissions() {
return permissions;
}
public void setPermissions(List<String> permissions) {
this.permissions = permissions;
}
}

@ -0,0 +1,79 @@
/*
* 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.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.wso2.carbon.apimgt.annotations.api.Permission;
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 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")
@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)
})
Response isAuthorized(AuthorizationRequest authorizationRequest);
}

@ -0,0 +1,93 @@
/*
* 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) {
int currentTenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
String loggedinUserTenantDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain();
if (authorizationRequest.getTenantDomain() != null) {
if (!loggedinUserTenantDomain.equals(authorizationRequest.getTenantDomain())) {
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();
}
}
} else {
authorizationRequest.setTenantDomain(loggedinUserTenantDomain);
}
if (authorizationRequest.getTenantDomain() == null || authorizationRequest.getTenantDomain().isEmpty()) {
authorizationRequest.setTenantDomain(
PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain());
}
try {
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();
}
}
}

@ -110,6 +110,12 @@
<url>/admin/devices</url> <url>/admin/devices</url>
<method>GET</method> <method>GET</method>
</Permission> </Permission>
<Permission>
<name>Verify device authorization</name>
<path>/device-mgt/devices</path>
<url>/admin/authorization</url>
<method>POST</method>
</Permission>
<Permission> <Permission>
<name>View device types</name> <name>View device types</name>
<path>/device-mgt/devices/Admin-DeviceType-View</path> <path>/device-mgt/devices/Admin-DeviceType-View</path>

@ -27,6 +27,7 @@
<jaxrs:serviceBeans> <jaxrs:serviceBeans>
<ref bean="deviceManagementService"/> <ref bean="deviceManagementService"/>
<ref bean="deviceManagementAdminService"/> <ref bean="deviceManagementAdminService"/>
<ref bean="deviceAccessAuthorizationAdminService"/>
<ref bean="deviceTypeManagementService"/> <ref bean="deviceTypeManagementService"/>
<ref bean="activityProviderService"/> <ref bean="activityProviderService"/>
<ref bean="notificationManagementService"/> <ref bean="notificationManagementService"/>
@ -80,6 +81,7 @@
<bean id="userManagementAdminService" class="org.wso2.carbon.device.mgt.jaxrs.service.impl.admin.UserManagementAdminServiceImpl"/> <bean id="userManagementAdminService" class="org.wso2.carbon.device.mgt.jaxrs.service.impl.admin.UserManagementAdminServiceImpl"/>
<bean id="dashboardServiceBean" class="org.wso2.carbon.device.mgt.jaxrs.service.impl.DashboardImpl"/> <bean id="dashboardServiceBean" class="org.wso2.carbon.device.mgt.jaxrs.service.impl.DashboardImpl"/>
<bean id="deviceTypeManagementAdminService" class="org.wso2.carbon.device.mgt.jaxrs.service.impl.DeviceTypeManagementServiceImpl"/> <bean id="deviceTypeManagementAdminService" class="org.wso2.carbon.device.mgt.jaxrs.service.impl.DeviceTypeManagementServiceImpl"/>
<bean id="deviceAccessAuthorizationAdminService" class="org.wso2.carbon.device.mgt.jaxrs.service.impl.admin.DeviceAccessAuthorizationAdminServiceImpl"/>
<bean id="jsonProvider" class="org.wso2.carbon.device.mgt.jaxrs.common.GsonMessageBodyHandler"/> <bean id="jsonProvider" class="org.wso2.carbon.device.mgt.jaxrs.common.GsonMessageBodyHandler"/>
<!--<bean id="errorHandler" class="org.wso2.carbon.device.mgt.jaxrs.common.ErrorHandler"/>--> <!--<bean id="errorHandler" class="org.wso2.carbon.device.mgt.jaxrs.common.ErrorHandler"/>-->

@ -67,7 +67,7 @@ public class DeviceAccessAuthorizationServiceImpl implements DeviceAccessAuthori
return !DeviceManagementDataHolder.getInstance().requireDeviceAuthorization(deviceIdentifier.getType()); return !DeviceManagementDataHolder.getInstance().requireDeviceAuthorization(deviceIdentifier.getType());
} }
//check for admin and ownership permissions //check for admin and ownership permissions
if (isAdminOrDeviceOwner(username, tenantId, deviceIdentifier)) { if (isAdmin(username, tenantId) || isDeviceOwner(deviceIdentifier, username)) {
return true; return true;
} }
//check for group permissions //check for group permissions
@ -127,14 +127,19 @@ public class DeviceAccessAuthorizationServiceImpl implements DeviceAccessAuthori
return null; return null;
} }
DeviceAuthorizationResult deviceAuthorizationResult = new DeviceAuthorizationResult(); DeviceAuthorizationResult deviceAuthorizationResult = new DeviceAuthorizationResult();
if (isAdmin(username, tenantId)) {
deviceAuthorizationResult.setAuthorizedDevices(deviceIdentifiers);
return deviceAuthorizationResult;
}
for (DeviceIdentifier deviceIdentifier : deviceIdentifiers) { for (DeviceIdentifier deviceIdentifier : deviceIdentifiers) {
//check for admin and ownership permissions //check for admin and ownership permissions
if (isAdminOrDeviceOwner(username, tenantId, deviceIdentifier)) { if (isDeviceOwner(deviceIdentifier, username)) {
deviceAuthorizationResult.addAuthorizedDevice(deviceIdentifier); deviceAuthorizationResult.addAuthorizedDevice(deviceIdentifier);
} else { } else {
try { try {
if (groupPermissions == null || groupPermissions.length == 0) { if (groupPermissions == null || groupPermissions.length == 0) {
return null; deviceAuthorizationResult.setUnauthorizedDevices(deviceIdentifiers);
return deviceAuthorizationResult;
} }
//check for group permissions //check for group permissions
boolean isAuthorized = true; boolean isAuthorized = true;
@ -178,15 +183,13 @@ public class DeviceAccessAuthorizationServiceImpl implements DeviceAccessAuthori
return isUserAuthorized(deviceIdentifiers, this.getUserName(), groupPermissions); return isUserAuthorized(deviceIdentifiers, this.getUserName(), groupPermissions);
} }
private boolean isAdminOrDeviceOwner(String username, int tenantId, DeviceIdentifier deviceIdentifier) private boolean isAdmin(String username, int tenantId)
throws DeviceAccessAuthorizationException { throws DeviceAccessAuthorizationException {
try { try {
//First Check for admin users. If the user is an admin user we authorize the access to that device. //Check for admin users. If the user is an admin user we authorize the access to that device.
//Secondly Check for device ownership. If the user is the owner of the device we allow the access. return (isAdminUser(username, tenantId));
return (isAdminUser(username, tenantId) || isDeviceOwner(deviceIdentifier, username));
} catch (UserStoreException e) { } catch (UserStoreException e) {
throw new DeviceAccessAuthorizationException("Unable to authorize the access to device : " + throw new DeviceAccessAuthorizationException("Unable to authorize the access for the user : " +
deviceIdentifier.getId() + " for the user : " +
username, e); username, e);
} }
} }

@ -62,63 +62,6 @@
<groupId>org.wso2.carbon</groupId> <groupId>org.wso2.carbon</groupId>
<artifactId>org.wso2.carbon.utils</artifactId> <artifactId>org.wso2.carbon.utils</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.wso2.orbit.org.scannotation</groupId>
<artifactId>scannotation</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.osgi</groupId>
<artifactId>org.eclipse.osgi</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.osgi</groupId>
<artifactId>org.eclipse.osgi.services</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.tomcat</groupId>
<artifactId>tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.tomcat</groupId>
<artifactId>tomcat-servlet-api</artifactId>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.axis2.wso2</groupId>
<artifactId>axis2</artifactId>
</dependency>
<dependency>
<groupId>commons-lang.wso2</groupId>
<artifactId>commons-lang</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>org.json.wso2</groupId>
<artifactId>json</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon.analytics-common</groupId>
<artifactId>org.wso2.carbon.event.output.adapter.core</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon.apimgt</groupId>
<artifactId>org.wso2.carbon.apimgt.api</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon.apimgt</groupId>
<artifactId>org.wso2.carbon.apimgt.impl</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>
@ -147,18 +90,10 @@
org.wso2.carbon.registry.core, org.wso2.carbon.registry.core,
org.wso2.carbon.registry.core.exceptions, org.wso2.carbon.registry.core.exceptions,
org.wso2.carbon.registry.core.session, org.wso2.carbon.registry.core.session,
javax.xml.bind, org.wso2.carbon.base,
org.wso2.carbon.utils, javax.xml.bind,
org.apache.commons.logging, org.apache.commons.logging,
org.apache.catalina, org.wso2.carbon.utils
org.apache.catalina.core,
javax.servlet;resolution:=optional,
javax.xml.*;resolution:=optional,
org.apache.commons.lang,
javax.ws.rs;version="0.0.0";resolution:=optional,
org.scannotation,
org.scannotation.archiveiterator,
org.wso2.carbon.base
</Import-Package> </Import-Package>
</instructions> </instructions>
</configuration> </configuration>

@ -1,77 +0,0 @@
/*
* 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.extensions.feature.mgt;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.common.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.DeviceTypeIdentifier;
import org.wso2.carbon.device.mgt.common.Feature;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* This stores the features for device types that are mentioned through the annotations.
*/
public class GenericFeatureManager {
private static final Log log = LogFactory.getLog(GenericFeatureManager.class);
private static Map<DeviceTypeIdentifier, List<Feature>> featureSet = new HashMap<>();
private static GenericFeatureManager instance = new GenericFeatureManager();
private GenericFeatureManager() {
}
public static GenericFeatureManager getInstance() {
return instance;
}
/**
* @param deviceTypeFeatures feature list for each device type.
*/
public void addFeatures(Map<DeviceTypeIdentifier, List<Feature>> deviceTypeFeatures) {
this.featureSet.putAll(deviceTypeFeatures);
}
/**
* @param deviceType
* @param featureName
* @return the extracted feature for the which matches the feature name and device type.
*/
public Feature getFeature(DeviceTypeIdentifier deviceType, String featureName) {
Feature extractedFeature = null;
List<Feature> deviceFeatureList = featureSet.get(deviceType);
for (Feature feature : deviceFeatureList) {
if (feature.getName().equalsIgnoreCase(featureName)) {
extractedFeature = feature;
}
}
return extractedFeature;
}
/**
* @param deviceType returns the features for the device type.
* @return
*/
public List<Feature> getFeatures(DeviceTypeIdentifier deviceType) {
return featureSet.get(deviceType);
}
}

@ -1,29 +0,0 @@
/*
* 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.extensions.feature.mgt.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DeviceType {
String value();
}

@ -1,35 +0,0 @@
/*
* 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.extensions.feature.mgt.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Feature {
String code();
String name();
String description();
}

@ -1,90 +0,0 @@
/*
* 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.extensions.feature.mgt.lifecycle.listener;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.core.StandardContext;
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.common.DeviceTypeIdentifier;
import org.wso2.carbon.device.mgt.common.Feature;
import org.wso2.carbon.device.mgt.extensions.feature.mgt.GenericFeatureManager;
import org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations.DeviceType;
import org.wso2.carbon.device.mgt.extensions.feature.mgt.util.AnnotationProcessor;
import javax.servlet.ServletContext;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
@SuppressWarnings("unused")
public class FeatureManagementLifecycleListener implements LifecycleListener {
private static final String API_CONFIG_DEFAULT_VERSION = "1.0.0";
private static final String PARAM_MANAGED_API_ENABLED = "managed-api-enabled";
private static final String PARAM_SHARED_WITH_ALL_TENANTS = "isSharedWithAllTenants";
private static final String PARAM_PROVIDER_TENANT_DOMAIN = "providerTenantDomain";
private static final Log log = LogFactory.getLog(FeatureManagementLifecycleListener.class);
@Override
public void lifecycleEvent(LifecycleEvent lifecycleEvent) {
if (Lifecycle.AFTER_START_EVENT.equals(lifecycleEvent.getType())) {
StandardContext context = (StandardContext) lifecycleEvent.getLifecycle();
ServletContext servletContext = context.getServletContext();
String param = servletContext.getInitParameter(PARAM_MANAGED_API_ENABLED);
boolean isManagedApi = (param != null && !param.isEmpty()) && Boolean.parseBoolean(param);
if (isManagedApi) {
try {
AnnotationProcessor annotationProcessor = new AnnotationProcessor(context);
Set<String> annotatedAPIClasses = annotationProcessor.scanStandardContext(DeviceType.class.getName());
String tenantDomain = servletContext.getInitParameter(PARAM_PROVIDER_TENANT_DOMAIN);
tenantDomain = (tenantDomain != null && !tenantDomain.isEmpty()) ? tenantDomain :
MultitenantConstants.SUPER_TENANT_DOMAIN_NAME;
try {
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
String sharingValueParam = servletContext.getInitParameter(PARAM_SHARED_WITH_ALL_TENANTS);
boolean isSharedWithAllTenants = Boolean.parseBoolean(sharingValueParam);
Map<DeviceTypeIdentifier, List<Feature>> features = annotationProcessor.extractFeatures(
annotatedAPIClasses, tenantId, isSharedWithAllTenants);
if (features != null && !features.isEmpty()) {
GenericFeatureManager.getInstance().addFeatures(features);
}
} finally {
PrivilegedCarbonContext.endTenantFlow();
}
} catch (IOException e) {
log.error("Error enconterd while discovering annotated classes.", e);
} catch (ClassNotFoundException e) {
log.error("Error while scanning class for annotations.", e);
}
}
}
}
}

@ -1,314 +0,0 @@
/*
* 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.extensions.feature.mgt.util;
import org.apache.catalina.core.StandardContext;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.scannotation.AnnotationDB;
import org.scannotation.WarUrlFinder;
import org.wso2.carbon.device.mgt.common.DeviceTypeIdentifier;
import org.wso2.carbon.device.mgt.common.Feature;
import org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations.DeviceType;
import javax.servlet.ServletContext;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* This has the utility function to extract feature information.
*/
public class AnnotationProcessor {
private static final Log log = LogFactory.getLog(AnnotationProcessor.class);
private static final String PACKAGE_ORG_APACHE = "org.apache";
private static final String PACKAGE_ORG_CODEHAUS = "org.codehaus";
private static final String PACKAGE_ORG_SPRINGFRAMEWORK = "org.springframework";
private static final String STRING_ARR = "string_arr";
private static final String STRING = "string";
private static final String METHOD = "method";
private Class<org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations.Feature>
featureAnnotationClazz;
private ClassLoader classLoader;
private ServletContext servletContext;
public AnnotationProcessor(final StandardContext context) {
servletContext = context.getServletContext();
classLoader = servletContext.getClassLoader();
}
/**
* Scan the context for classes with annotations
*/
public Set<String> scanStandardContext(String className) throws IOException {
ExtendedAnnotationDB db = new ExtendedAnnotationDB();
db.addIgnoredPackages(PACKAGE_ORG_APACHE);
db.addIgnoredPackages(PACKAGE_ORG_CODEHAUS);
db.addIgnoredPackages(PACKAGE_ORG_SPRINGFRAMEWORK);
URL classPath = findWebInfClassesPath(servletContext);
db.scanArchives(classPath);
//Returns a list of classes with given Annotation
return db.getAnnotationIndex().get(className);
}
/**
* Method identifies the URL templates and context by reading the annotations of a class
*/
public Map<DeviceTypeIdentifier, List<Feature>> extractFeatures(Set<String> entityClasses, final int tenantId,
final boolean isSharedWithAllTenants)
throws ClassNotFoundException {
Map<DeviceTypeIdentifier, List<Feature>> features = null;
if (entityClasses != null && !entityClasses.isEmpty()) {
features = new HashMap<>();
for (final String className : entityClasses) {
final Map<DeviceTypeIdentifier, List<Feature>> featureMap =
AccessController.doPrivileged(new PrivilegedAction<Map<DeviceTypeIdentifier, List<Feature>>>() {
public Map<DeviceTypeIdentifier, List<Feature>> run() {
Map<DeviceTypeIdentifier, List<Feature>> featureMap = new HashMap<>();
try {
Class<?> clazz = classLoader.loadClass(className);
Class<DeviceType> deviceTypeClazz = (Class<DeviceType>) classLoader.loadClass(
DeviceType.class.getName());
Annotation deviceTypeAnno = clazz.getAnnotation(deviceTypeClazz);
if (deviceTypeAnno != null) {
Method[] deviceTypeMethod = deviceTypeClazz.getMethods();
String deviceType = invokeMethod(deviceTypeMethod[0], deviceTypeAnno, STRING);
featureAnnotationClazz =
(Class<org.wso2.carbon.device.mgt.extensions.feature.mgt.annotations
.Feature>) classLoader.loadClass(
org.wso2.carbon.device.mgt.extensions.feature.mgt
.annotations.Feature.class.getName());
List<Feature> featureList = getFeatures(clazz.getDeclaredMethods());
DeviceTypeIdentifier deviceTypeIdentifier;
if (isSharedWithAllTenants) {
deviceTypeIdentifier = new DeviceTypeIdentifier(deviceType);
} else {
deviceTypeIdentifier = new DeviceTypeIdentifier(deviceType, tenantId);
}
featureMap.put(deviceTypeIdentifier, featureList);
}
} catch (Throwable e) {
log.error("Failed to load the annotation from the features in the " +
"class " + className, e);
}
return featureMap;
}
});
features.putAll(featureMap);
}
}
return features;
}
private List<Feature> getFeatures(Method[] methodsList) throws Throwable {
List<Feature> featureList = new ArrayList<>();
for (Method currentMethod : methodsList) {
Annotation featureAnnotation = currentMethod.getAnnotation(featureAnnotationClazz);
if (featureAnnotation != null) {
Feature feature = new Feature();
feature = processFeatureAnnotation(feature, currentMethod);
Annotation[] annotations = currentMethod.getDeclaredAnnotations();
Feature.MetadataEntry metadataEntry = new Feature.MetadataEntry();
metadataEntry.setId(-1);
Map<String, Object> apiParams = new HashMap<>();
for (int i = 0; i < annotations.length; i++) {
Annotation currentAnnotation = annotations[i];
processHttpMethodAnnotation(apiParams, currentAnnotation);
if (currentAnnotation.annotationType().getName().equals(Path.class.getName())) {
String uri = getPathAnnotationValue(currentMethod);
apiParams.put("uri", uri);
}
apiParams = processParamAnnotations(apiParams, currentMethod);
}
metadataEntry.setValue(apiParams);
List<Feature.MetadataEntry> metaInfoList = new ArrayList<>();
metaInfoList.add(metadataEntry);
feature.setMetadataEntries(metaInfoList);
featureList.add(feature);
}
}
return featureList;
}
private Map<String, Object> processParamAnnotations(Map<String, Object> apiParams, Method currentMethod)
throws Throwable{
try {
apiParams.put("pathParams", processParamAnnotations(currentMethod, PathParam.class));
apiParams.put("queryParams", processParamAnnotations(currentMethod, QueryParam.class));
apiParams.put("formParams", processParamAnnotations(currentMethod, FormParam.class));
} catch (ClassNotFoundException e) {
log.debug("No Form Param found for class " + featureAnnotationClazz.getName());
}
return apiParams;
}
private List<String> processParamAnnotations(Method currentMethod, Class<?> clazz) throws Throwable{
List<String> params = new ArrayList<>();
try {
Class<?> paramClazz = (Class<?>) classLoader.loadClass(clazz.getName());
Method[] formMethods = paramClazz.getMethods();
//Extract method parameter information and store same as feature meta info
Annotation[][] paramAnnotations = currentMethod.getParameterAnnotations();
Method valueMethod = formMethods[0];
for (int j = 0; j < paramAnnotations.length; j++) {
for (Annotation anno : paramAnnotations[j]) {
if (anno.annotationType().getName().equals(clazz.getName())) {
params.add(invokeMethod(valueMethod, anno, STRING));
}
}
}
} catch (ClassNotFoundException e) {
log.debug("No "+ clazz.getName() +" Param found for class " + featureAnnotationClazz.getName());
}
return params;
}
/**
* Read Method annotations indicating HTTP Methods
*/
private void processHttpMethodAnnotation(Map<String, Object> apiParams, Annotation currentAnnotation) {
//Extracting method with which feature is exposed
if (currentAnnotation.annotationType().getName().equals(GET.class.getName())) {
apiParams.put(METHOD, HttpMethod.GET);
} else if (currentAnnotation.annotationType().getName().equals(POST.class.getName())) {
apiParams.put(METHOD, HttpMethod.POST);
} else if (currentAnnotation.annotationType().getName().equals(OPTIONS.class.getName())) {
apiParams.put(METHOD, HttpMethod.OPTIONS);
} else if (currentAnnotation.annotationType().getName().equals(DELETE.class.getName())) {
apiParams.put(METHOD, HttpMethod.DELETE);
} else if (currentAnnotation.annotationType().getName().equals(PUT.class.getName())) {
apiParams.put(METHOD, HttpMethod.PUT);
}
}
/**
* Read Feature annotation and Identify Features
* @param feature
* @param currentMethod
* @return
* @throws Throwable
*/
private Feature processFeatureAnnotation(Feature feature, Method currentMethod) throws Throwable{
Method[] featureAnnoMethods = featureAnnotationClazz.getMethods();
Annotation featureAnno = currentMethod.getAnnotation(featureAnnotationClazz);
for (int k = 0; k < featureAnnoMethods.length; k++) {
switch (featureAnnoMethods[k].getName()) {
case "name":
feature.setName(invokeMethod(featureAnnoMethods[k], featureAnno, STRING));
break;
case "code":
feature.setCode(invokeMethod(featureAnnoMethods[k], featureAnno, STRING));
break;
case "description":
feature.setDescription(invokeMethod(featureAnnoMethods[k], featureAnno, STRING));
break;
}
}
return feature;
}
/**
* Get value depicted by Path Annotation
* @param currentMethod
* @return
* @throws Throwable
*/
public String getPathAnnotationValue(Method currentMethod) throws Throwable{
String uri = "";
try {
Class<Path> pathClazz = (Class<Path>) classLoader.loadClass(Path.class.getName());
Annotation pathAnnno = currentMethod.getAnnotation(pathClazz);
Method[] pathMethods = pathClazz.getMethods();
Method valueMethod = pathMethods[0];
uri = invokeMethod(valueMethod, pathAnnno, STRING);
} catch (ClassNotFoundException e) {
log.debug("No Path Param found for class " + featureAnnotationClazz.getName());
}
return uri;
}
/**
* When an annotation and method is passed, this method invokes that executes said method against the annotation
*/
private String invokeMethod(Method method, Annotation annotation, String returnType) throws Throwable {
InvocationHandler methodHandler = Proxy.getInvocationHandler(annotation);
switch (returnType) {
case STRING:
return (String) methodHandler.invoke(annotation, method, null);
case STRING_ARR:
return ((String[]) methodHandler.invoke(annotation, method, null))[0];
default:
return null;
}
}
/**
* Find the URL pointing to "/WEB-INF/classes" This method may not work in conjunction with IteratorFactory
* if your servlet container does not extract the /WEB-INF/classes into a real file-based directory
*
* @param servletContext
* @return null if cannot determin /WEB-INF/classes
*/
public static URL findWebInfClassesPath(ServletContext servletContext)
{
String path = servletContext.getRealPath("/WEB-INF/classes");
if (path == null) return null;
File fp = new File(path);
if (fp.exists() == false) return null;
try
{
URI uri = fp.toURI();
return uri.toURL();
}
catch (MalformedURLException e)
{
throw new RuntimeException(e);
}
}
}

@ -1,92 +0,0 @@
/*
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* Licensed 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.extensions.feature.mgt.util;
import org.scannotation.AnnotationDB;
import org.scannotation.archiveiterator.Filter;
import org.scannotation.archiveiterator.StreamIterator;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
public class ExtendedAnnotationDB extends AnnotationDB {
public ExtendedAnnotationDB() {
super();
}
public void scanArchives(URL... urls) throws IOException {
URL[] arr$ = urls;
int len$ = urls.length;
for(int i$ = 0; i$ < len$; ++i$) {
URL url = arr$[i$];
Filter filter = new Filter() {
public boolean accepts(String filename) {
if(filename.endsWith(".class")) {
if(filename.startsWith("/") || filename.startsWith("\\")) {
filename = filename.substring(1);
}
if(!ExtendedAnnotationDB.this.ignoreScan(filename.replace('/', '.'))) {
return true;
}
}
return false;
}
};
StreamIterator it = ExtendedIteratorFactory.create(url, filter);
InputStream stream;
while((stream = it.next()) != null) {
this.scanClass(stream);
}
}
}
private boolean ignoreScan(String intf) {
String[] arr$;
int len$;
int i$;
String ignored;
if(this.scanPackages != null) {
arr$ = this.scanPackages;
len$ = arr$.length;
for(i$ = 0; i$ < len$; ++i$) {
ignored = arr$[i$];
if(intf.startsWith(ignored + ".")) {
return false;
}
}
return true;
} else {
arr$ = this.ignoredPackages;
len$ = arr$.length;
for(i$ = 0; i$ < len$; ++i$) {
ignored = arr$[i$];
if(intf.startsWith(ignored + ".")) {
return true;
}
}
return false;
}
}
}

@ -1,34 +0,0 @@
/*
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* Licensed 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.extensions.feature.mgt.util;
import org.scannotation.archiveiterator.*;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class ExtendedFileProtocolIteratorFactory implements DirectoryIteratorFactory {
private static final String ENCODING_SCHEME = "UTF-8";
@Override
public StreamIterator create(URL url, Filter filter) throws IOException {
File f = new File(java.net.URLDecoder.decode(url.getPath(), ENCODING_SCHEME));
return f.isDirectory()?new FileIterator(f, filter):new JarIterator(url.openStream(), filter);
}
}

@ -1,54 +0,0 @@
/*
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* Licensed 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.extensions.feature.mgt.util;
import org.scannotation.archiveiterator.DirectoryIteratorFactory;
import org.scannotation.archiveiterator.Filter;
import org.scannotation.archiveiterator.JarIterator;
import org.scannotation.archiveiterator.StreamIterator;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;
public class ExtendedIteratorFactory {
private static final ConcurrentHashMap<String, DirectoryIteratorFactory> registry = new ConcurrentHashMap();
public static StreamIterator create(URL url, Filter filter) throws IOException {
String urlString = url.toString();
if(urlString.endsWith("!/")) {
urlString = urlString.substring(4);
urlString = urlString.substring(0, urlString.length() - 2);
url = new URL(urlString);
}
if(!urlString.endsWith("/")) {
return new JarIterator(url.openStream(), filter);
} else {
DirectoryIteratorFactory factory = registry.get(url.getProtocol());
if(factory == null) {
throw new IOException("Unable to scan directory of protocol: " + url.getProtocol());
} else {
return factory.create(url, filter);
}
}
}
static {
registry.put("file", new ExtendedFileProtocolIteratorFactory());
}
}

@ -28,6 +28,7 @@
"tokenServiceURL": "%https.ip%/oauth2/token" "tokenServiceURL": "%https.ip%/oauth2/token"
}, },
"adminUser":"admin@carbon.super", "adminUser":"admin@carbon.super",
"adminUserTenantId":"-1234",
"adminRole":"admin", "adminRole":"admin",
"usernameLength":30, "usernameLength":30,
"pageSize":10, "pageSize":10,

@ -80,14 +80,14 @@ var utils = function () {
return dynamicClientAppCredentials; return dynamicClientAppCredentials;
}; };
publicMethods["getTenantBasedClientAppCredentials"] = function (username, jwtToken) { publicMethods["getTenantBasedClientAppCredentials"] = function (username) {
if (!username || !jwtToken) { if (!username) {
log.error("{/app/modules/oauth/token-handler-utils.js} Error in retrieving tenant " + log.error("{/app/modules/oauth/token-handler-utils.js} Error in retrieving tenant " +
"based client app credentials. No username or jwt token is found " + "based client app credentials. No username " +
"as input - getTenantBasedClientAppCredentials(x, y)"); "as input - getTenantBasedClientAppCredentials(x)");
return null; return null;
} else { } else {
//noinspection JSUnresolvedFunction, JSUnresolvedVariable //noinspection JSUnresolvedFunction, JSUnresolvedVariable
var tenantDomain = carbon.server.tenantDomain({username: username}); var tenantDomain = carbon.server.tenantDomain({username: username});
if (!tenantDomain) { if (!tenantDomain) {
log.error("{/app/modules/oauth/token-handler-utils.js} Error in retrieving tenant " + log.error("{/app/modules/oauth/token-handler-utils.js} Error in retrieving tenant " +
@ -100,6 +100,13 @@ var utils = function () {
if (cachedTenantBasedClientAppCredentials) { if (cachedTenantBasedClientAppCredentials) {
return cachedTenantBasedClientAppCredentials; return cachedTenantBasedClientAppCredentials;
} else { } else {
var adminUsername = deviceMgtProps["adminUser"];
var adminUserTenantId = deviceMgtProps["adminUserTenantId"];
//claims required for jwtAuthenticator.
var claims = {"http://wso2.org/claims/enduserTenantId": adminUserTenantId,
"http://wso2.org/claims/enduser": adminUsername};
var jwtToken = publicMethods.getJwtToken(adminUsername, claims);
// register a tenant based client app at API Manager // register a tenant based client app at API Manager
var applicationName = "webapp_" + tenantDomain; var applicationName = "webapp_" + tenantDomain;
var requestURL = deviceMgtProps["oauthProvider"]["appRegistration"] var requestURL = deviceMgtProps["oauthProvider"]["appRegistration"]
@ -109,7 +116,7 @@ var utils = function () {
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.open("POST", requestURL, false); xhr.open("POST", requestURL, false);
xhr.setRequestHeader("Content-Type", "application/json"); xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Authorization", "Bearer " + jwtToken); xhr.setRequestHeader("X-JWT-Assertion", "" + jwtToken);
xhr.send(); xhr.send();
if (xhr["status"] == 201 && xhr["responseText"]) { if (xhr["status"] == 201 && xhr["responseText"]) {
@ -291,5 +298,26 @@ var utils = function () {
} }
}; };
publicMethods["getJwtToken"] = function (username, claims) {
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
if (claims) {
return jwtClient.getJwtToken(username, claims);
} else {
return jwtClient.getJwtToken(username);
}
}
};
return publicMethods; return publicMethods;
}(); }();

@ -136,43 +136,35 @@ var handlers = function () {
"client credentials to session context. No username of logged in user is found as " + "client credentials to session context. No username of logged in user is found as " +
"input - setUpEncodedTenantBasedClientAppCredentials(x)"); "input - setUpEncodedTenantBasedClientAppCredentials(x)");
} else { } else {
var dynamicClientAppCredentials = tokenUtil.getDynamicClientAppCredentials(); if (devicemgtProps["apimgt-gateway"]) {
if (!dynamicClientAppCredentials) { var tenantBasedClientAppCredentials = tokenUtil.getTenantBasedClientAppCredentials(username);
throw new Error("{/app/modules/oauth/token-handlers.js} Could not set up encoded tenant based " + if (!tenantBasedClientAppCredentials) {
"client credentials to session context as the server is unable to obtain " + throw new Error("{/app/modules/oauth/token-handlers.js} Could not set up encoded tenant " +
"dynamic client credentials - setUpEncodedTenantBasedClientAppCredentials(x)"); "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);
}
} else { } else {
if (devicemgtProps["apimgt-gateway"]) { var dynamicClientAppCredentials = tokenUtil.getDynamicClientAppCredentials();
var jwtToken = tokenUtil.getAccessTokenByJWTGrantType(dynamicClientAppCredentials); if (!dynamicClientAppCredentials) {
if (!jwtToken) { throw new Error("{/app/modules/oauth/token-handlers.js} Could not set up encoded tenant based " +
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 " +
"client credentials to session context as the server is unable to obtain " + "dynamic client credentials - 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 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);
} }
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);
} }
} }
}; };

@ -34,10 +34,6 @@
<url>http://wso2.org</url> <url>http://wso2.org</url>
<dependencies> <dependencies>
<dependency>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.common</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.wso2.carbon.identity</groupId> <groupId>org.wso2.carbon.identity</groupId>
<artifactId>org.wso2.carbon.identity.oauth</artifactId> <artifactId>org.wso2.carbon.identity.oauth</artifactId>
@ -54,18 +50,10 @@
<groupId>org.wso2.carbon.apimgt</groupId> <groupId>org.wso2.carbon.apimgt</groupId>
<artifactId>org.wso2.carbon.apimgt.keymgt</artifactId> <artifactId>org.wso2.carbon.apimgt.keymgt</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.googlecode.json-simple.wso2</groupId> <groupId>com.googlecode.json-simple.wso2</groupId>
<artifactId>json-simple</artifactId> <artifactId>json-simple</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.wso2.carbon.identity</groupId>
<artifactId>org.wso2.carbon.identity.oauth2.grant.jwt</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.core</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>
@ -94,9 +82,7 @@
javax.security.auth.*, javax.security.auth.*,
org.apache.commons.logging, org.apache.commons.logging,
org.osgi.service.component, org.osgi.service.component,
org.wso2.carbon.device.mgt.common.permission.mgt,
org.wso2.carbon.device.mgt.oauth.extensions.*, org.wso2.carbon.device.mgt.oauth.extensions.*,
org.wso2.carbon.device.mgt.*,
org.wso2.carbon.identity.application.common.model, org.wso2.carbon.identity.application.common.model,
org.wso2.carbon.identity.oauth.callback, org.wso2.carbon.identity.oauth.callback,
org.wso2.carbon.identity.oauth2, org.wso2.carbon.identity.oauth2,
@ -123,10 +109,6 @@
org.wso2.carbon.utils.multitenancy, org.wso2.carbon.utils.multitenancy,
org.wso2.carbon.identity.oauth2.grant.jwt.*, org.wso2.carbon.identity.oauth2.grant.jwt.*,
org.wso2.carbon.device.mgt.core.*, org.wso2.carbon.device.mgt.core.*,
javax.xml.bind,
javax.xml.bind.annotation,
javax.xml.parsers;version="${javax.xml.parsers.import.pkg.version}";resolution:=optional,
org.w3c.dom,
org.wso2.carbon.apimgt.keymgt, org.wso2.carbon.apimgt.keymgt,
org.wso2.carbon.apimgt.keymgt.handlers, org.wso2.carbon.apimgt.keymgt.handlers,
com.google.gson, com.google.gson,

@ -1,30 +0,0 @@
package org.wso2.carbon.device.mgt.oauth.extensions;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import java.util.List;
/**
* This class holds the request format for device for grant type.
*/
public class DeviceRequestDTO {
private List<DeviceIdentifier> deviceIdentifiers;
private String scope;
public List<DeviceIdentifier> getDeviceIdentifiers() {
return deviceIdentifiers;
}
public void setDeviceIdentifiers(List<DeviceIdentifier> deviceIdentifiers) {
this.deviceIdentifiers = deviceIdentifiers;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
}

@ -1,13 +0,0 @@
package org.wso2.carbon.device.mgt.oauth.extensions;
/**
* This hold the OAuthConstants related oauth extensions.
*/
public class OAuthConstants {
public static final String DEFAULT_DEVICE_ASSERTION = "device";
public static final String DEFAULT_USERNAME_IDENTIFIER = "username";
public static final String DEFAULT_PASSWORD_IDENTIFIER = "password";
}

@ -18,25 +18,14 @@
package org.wso2.carbon.device.mgt.oauth.extensions; package org.wso2.carbon.device.mgt.oauth.extensions;
import com.google.gson.Gson;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;
import org.wso2.carbon.apimgt.api.APIManagementException; import org.wso2.carbon.apimgt.api.APIManagementException;
import org.wso2.carbon.apimgt.impl.APIConstants; import org.wso2.carbon.apimgt.impl.APIConstants;
import org.wso2.carbon.apimgt.impl.dao.ApiMgtDAO; import org.wso2.carbon.apimgt.impl.dao.ApiMgtDAO;
import org.wso2.carbon.apimgt.impl.utils.APIUtil; import org.wso2.carbon.apimgt.impl.utils.APIUtil;
import org.wso2.carbon.apimgt.keymgt.ScopesIssuer;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationException;
import org.wso2.carbon.device.mgt.common.authorization.DeviceAuthorizationResult;
import org.wso2.carbon.device.mgt.oauth.extensions.config.DeviceMgtScopesConfig;
import org.wso2.carbon.device.mgt.oauth.extensions.config.DeviceMgtScopesConfigurationFailedException;
import org.wso2.carbon.device.mgt.oauth.extensions.internal.OAuthExtensionsDataHolder; import org.wso2.carbon.device.mgt.oauth.extensions.internal.OAuthExtensionsDataHolder;
import org.wso2.carbon.identity.core.util.IdentityTenantUtil; import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
import org.wso2.carbon.identity.oauth2.model.RequestParameter;
import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext;
import org.wso2.carbon.user.api.TenantManager; import org.wso2.carbon.user.api.TenantManager;
import org.wso2.carbon.user.api.UserRealm; import org.wso2.carbon.user.api.UserRealm;
@ -44,9 +33,6 @@ import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.core.service.RealmService; import org.wso2.carbon.user.core.service.RealmService;
import javax.cache.Caching; import javax.cache.Caching;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -126,7 +112,6 @@ public class OAuthExtUtils {
restAPIScopesOfCurrentTenant = APIUtil. restAPIScopesOfCurrentTenant = APIUtil.
getRESTAPIScopesFromConfig(APIUtil.getTenantRESTAPIScopesConfig(tenantDomain)); getRESTAPIScopesFromConfig(APIUtil.getTenantRESTAPIScopesConfig(tenantDomain));
//call load tenant org.wso2.carbon.device.mgt.iot.output.adapter.ui.config for rest API.
//then put cache //then put cache
appScopes.putAll(restAPIScopesOfCurrentTenant); appScopes.putAll(restAPIScopesOfCurrentTenant);
Caching.getCacheManager(APIConstants.API_MANAGER_CACHE_MANAGER) Caching.getCacheManager(APIConstants.API_MANAGER_CACHE_MANAGER)
@ -288,82 +273,4 @@ public class OAuthExtUtils {
return trimmedName.substring(START_INDEX, trimmedName.lastIndexOf('@')); return trimmedName.substring(START_INDEX, trimmedName.lastIndexOf('@'));
} }
public static boolean validateScope(OAuthTokenReqMessageContext tokReqMsgCtx) {
boolean isScopesSet = ScopesIssuer.getInstance().setScopes(tokReqMsgCtx);
if (isScopesSet) {
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(
tokReqMsgCtx.getAuthorizedUser().getTenantDomain(), true);
String username = tokReqMsgCtx.getAuthorizedUser().getUserName();
PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(username);
try {
DeviceRequestDTO deviceRequestDTO = null;
RequestParameter parameters[] = tokReqMsgCtx.getOauth2AccessTokenReqDTO().getRequestParameters();
for (RequestParameter parameter : parameters) {
if (OAuthConstants.DEFAULT_DEVICE_ASSERTION.equals(parameter.getKey())) {
String deviceJson = parameter.getValue()[0];
Gson gson = new Gson();
deviceRequestDTO = gson.fromJson(new String(Base64.decodeBase64(deviceJson)),
DeviceRequestDTO.class);
}
}
if (deviceRequestDTO != null) {
String requestScopes = deviceRequestDTO.getScope();
String scopeNames[] = requestScopes.split(" ");
for (String scopeName : scopeNames) {
List<DeviceIdentifier> deviceIdentifiers = deviceRequestDTO.getDeviceIdentifiers();
DeviceAuthorizationResult deviceAuthorizationResult = OAuthExtensionsDataHolder.getInstance()
.getDeviceAccessAuthorizationService()
.isUserAuthorized(deviceIdentifiers, username, getPermissions(scopeName));
if (deviceAuthorizationResult != null &&
deviceAuthorizationResult.getAuthorizedDevices() != null) {
String scopes[] = tokReqMsgCtx.getScope();
String authorizedScopes[] = new String[scopes.length + deviceAuthorizationResult
.getAuthorizedDevices().size()];
int scopeIndex = 0;
for (String scope : scopes) {
authorizedScopes[scopeIndex] = scope;
scopeIndex++;
}
for (DeviceIdentifier deviceIdentifier : deviceAuthorizationResult.getAuthorizedDevices()) {
authorizedScopes[scopeIndex] =
DEFAULT_SCOPE_TAG + ":" + deviceIdentifier.getType() + ":" +
deviceIdentifier.getId() + ":" + scopeName;
scopeIndex++;
}
tokReqMsgCtx.setScope(authorizedScopes);
}
}
}
} catch (DeviceAccessAuthorizationException e) {
log.error("Error occurred while checking authorization for the user " + username, e);
} finally {
PrivilegedCarbonContext.endTenantFlow();
}
}
return isScopesSet;
}
/**
* retrieve the permission related to given scope.
* @param scopeName requested scope action
* @return set of permission associated with the given scope.
*/
private static String[] getPermissions(String scopeName) {
return DeviceMgtScopesConfig.getInstance().getDeviceMgtScopePermissionMap().get(scopeName);
}
public static Document convertToDocument(File file) throws DeviceMgtScopesConfigurationFailedException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
try {
DocumentBuilder docBuilder = factory.newDocumentBuilder();
return docBuilder.parse(file);
} catch (Exception e) {
throw new DeviceMgtScopesConfigurationFailedException("Error occurred while parsing file, while converting " +
"to a org.w3c.dom.Document", e);
}
}
} }

@ -1,90 +0,0 @@
package org.wso2.carbon.device.mgt.oauth.extensions.config;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for Action complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType name="Action">
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;sequence>
* &lt;element name="Permissions" type="{}Permissions"/>
* &lt;/sequence>
* &lt;attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Action", propOrder = {
"permissions"
})
public class Action {
@XmlElement(name = "Permissions", required = true)
protected Permissions permissions;
@XmlAttribute(name = "name")
protected String name;
/**
* Gets the value of the permissions property.
*
* @return
* possible object is
* {@link Permissions }
*
*/
public Permissions getPermissions() {
return permissions;
}
/**
* Sets the value of the permissions property.
*
* @param value
* allowed object is
* {@link Permissions }
*
*/
public void setPermissions(Permissions value) {
this.permissions = value;
}
/**
* Gets the value of the name property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getName() {
return name;
}
/**
* Sets the value of the name property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setName(String value) {
this.name = value;
}
}

@ -1,67 +0,0 @@
package org.wso2.carbon.device.mgt.oauth.extensions.config;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for DeviceMgtScopes complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType name="DeviceMgtScopes">
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;sequence>
* &lt;element name="Action" type="{}Action" maxOccurs="unbounded" minOccurs="0"/>
* &lt;/sequence>
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlRootElement(name = "DeviceMgtScopes")
public class DeviceMgtScopes {
@XmlElement(name = "Action")
protected List<Action> action;
/**
* Gets the value of the action property.
*
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the action property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getAction().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link Action }
*
*
*/
public List<Action> getAction() {
if (action == null) {
action = new ArrayList<Action>();
}
return this.action;
}
}

@ -1,67 +0,0 @@
package org.wso2.carbon.device.mgt.oauth.extensions.config;
import org.w3c.dom.Document;
import org.wso2.carbon.device.mgt.oauth.extensions.OAuthExtUtils;
import org.wso2.carbon.utils.CarbonUtils;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
/**
* This class represents the configuration that are needed for scopes to permission map.
*/
public class DeviceMgtScopesConfig {
private static DeviceMgtScopesConfig config = new DeviceMgtScopesConfig();
private static Map<String, String[]> actionPermissionMap = new HashMap<>();
private static final String DEVICE_MGT_SCOPES_CONFIG_PATH =
CarbonUtils.getEtcCarbonConfigDirPath() + File.separator + "device-mgt-scopes.xml";
private DeviceMgtScopesConfig() {
}
public static DeviceMgtScopesConfig getInstance() {
return config;
}
public static void init() throws DeviceMgtScopesConfigurationFailedException {
try {
File deviceMgtConfig = new File(DEVICE_MGT_SCOPES_CONFIG_PATH);
Document doc = OAuthExtUtils.convertToDocument(deviceMgtConfig);
/* Un-marshaling DeviceMGtScope configuration */
JAXBContext ctx = JAXBContext.newInstance(DeviceMgtScopes.class);
Unmarshaller unmarshaller = ctx.createUnmarshaller();
//unmarshaller.setSchema(getSchema());
DeviceMgtScopes deviceMgtScopes = (DeviceMgtScopes) unmarshaller.unmarshal(doc);
if (deviceMgtScopes != null) {
for (Action action : deviceMgtScopes.getAction()) {
Permissions permissions = action.getPermissions();
if (permissions != null) {
String permission[] = new String[permissions.getPermission().size()];
int i = 0;
for (String perm : permissions.getPermission()) {
permission[i] = perm;
i++;
}
actionPermissionMap.put(action.getName(), permission);
}
}
}
} catch (JAXBException e) {
throw new DeviceMgtScopesConfigurationFailedException("Error occurred while un-marshalling Device Scope" +
" Config", e);
}
}
public Map<String, String[]> getDeviceMgtScopePermissionMap() {
return actionPermissionMap;
}
}

@ -1,44 +0,0 @@
/*
* 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.config;
public class DeviceMgtScopesConfigurationFailedException extends Exception {
private static final long serialVersionUID = -3151279312929070398L;
public DeviceMgtScopesConfigurationFailedException(String msg, Exception nestedEx) {
super(msg, nestedEx);
}
public DeviceMgtScopesConfigurationFailedException(String message, Throwable cause) {
super(message, cause);
}
public DeviceMgtScopesConfigurationFailedException(String msg) {
super(msg);
}
public DeviceMgtScopesConfigurationFailedException() {
super();
}
public DeviceMgtScopesConfigurationFailedException(Throwable cause) {
super(cause);
}
}

@ -1,78 +0,0 @@
package org.wso2.carbon.device.mgt.oauth.extensions.config;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for Permissions complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType name="Permissions">
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;sequence>
* &lt;element name="Permission" maxOccurs="unbounded" minOccurs="0">
* &lt;simpleType>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}string">
* &lt;enumeration value="/permission/device-mgt/user/groups/device_operation"/>
* &lt;enumeration value="/permission/device-mgt/groups"/>
* &lt;enumeration value="/permission/device-mgt/user/groups"/>
* &lt;enumeration value="/permission/device-mgt/user/groups/device_monitor"/>
* &lt;/restriction>
* &lt;/simpleType>
* &lt;/element>
* &lt;/sequence>
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Permissions", propOrder = {
"permission"
})
public class Permissions {
@XmlElement(name = "Permission")
protected List<String> permission;
/**
* Gets the value of the permission property.
*
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the permission property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getPermission().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link String }
*
*
*/
public List<String> getPermission() {
if (permission == null) {
permission = new ArrayList<String>();
}
return this.permission;
}
}

@ -1,31 +0,0 @@
/*
* 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.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 ExtendedDeviceMgtJWTBearerGrantHandler extends JWTBearerGrantHandler {
@Override
public boolean validateScope(OAuthTokenReqMessageContext tokReqMsgCtx) throws IdentityOAuth2Exception {
return OAuthExtUtils.validateScope(tokReqMsgCtx);
}
}

@ -1,59 +0,0 @@
/*
* 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.grant;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.apimgt.keymgt.handlers.ExtendedPasswordGrantHandler;
import org.wso2.carbon.device.mgt.oauth.extensions.OAuthConstants;
import org.wso2.carbon.device.mgt.oauth.extensions.OAuthExtUtils;
import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception;
import org.wso2.carbon.identity.oauth2.model.RequestParameter;
import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext;
@SuppressWarnings("unused")
public class ExtendedDeviceMgtPasswordGrantHandler extends ExtendedPasswordGrantHandler {
private static Log log = LogFactory.getLog(ExtendedDeviceMgtPasswordGrantHandler.class);
@Override
public boolean validateGrant(OAuthTokenReqMessageContext tokReqMsgCtx) throws IdentityOAuth2Exception {
RequestParameter parameters[] = tokReqMsgCtx.getOauth2AccessTokenReqDTO().getRequestParameters();
for (RequestParameter parameter : parameters) {
switch (parameter.getKey()) {
case OAuthConstants.DEFAULT_USERNAME_IDENTIFIER:
String username = parameter.getValue()[0];
tokReqMsgCtx.getOauth2AccessTokenReqDTO().setResourceOwnerUsername(username);
break;
case OAuthConstants.DEFAULT_PASSWORD_IDENTIFIER:
String password = parameter.getValue()[0];
tokReqMsgCtx.getOauth2AccessTokenReqDTO().setResourceOwnerPassword(password);
break;
}
}
return super.validateGrant(tokReqMsgCtx);
}
@Override
public boolean validateScope(OAuthTokenReqMessageContext tokReqMsgCtx) {
return OAuthExtUtils.validateScope(tokReqMsgCtx);
}
}

@ -24,12 +24,6 @@ import org.osgi.service.component.ComponentContext;
import org.wso2.carbon.apimgt.api.APIManagementException; import org.wso2.carbon.apimgt.api.APIManagementException;
import org.wso2.carbon.apimgt.impl.APIConstants; import org.wso2.carbon.apimgt.impl.APIConstants;
import org.wso2.carbon.apimgt.impl.APIManagerConfiguration; import org.wso2.carbon.apimgt.impl.APIManagerConfiguration;
import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationException;
import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationService;
import org.wso2.carbon.device.mgt.common.permission.mgt.PermissionManagerService;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.device.mgt.oauth.extensions.config.DeviceMgtScopesConfig;
import org.wso2.carbon.device.mgt.oauth.extensions.config.DeviceMgtScopesConfigurationFailedException;
import org.wso2.carbon.identity.oauth2.OAuth2TokenValidationService; import org.wso2.carbon.identity.oauth2.OAuth2TokenValidationService;
import org.wso2.carbon.user.core.service.RealmService; import org.wso2.carbon.user.core.service.RealmService;
import org.wso2.carbon.utils.CarbonUtils; import org.wso2.carbon.utils.CarbonUtils;
@ -52,18 +46,6 @@ import java.util.List;
* policy="dynamic" * policy="dynamic"
* bind="setOAuth2ValidationService" * bind="setOAuth2ValidationService"
* unbind="unsetOAuth2ValidationService" * unbind="unsetOAuth2ValidationService"
* @scr.reference name="permission.manager.service"
* interface="org.wso2.carbon.device.mgt.common.permission.mgt.PermissionManagerService"
* cardinality="1..1"
* policy="dynamic"
* bind="setPermissionManagerService"
* unbind="unsetPermissionManagerService"
* @scr.reference name="org.wso2.carbon.device.authorization"
* interface="org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationService"
* cardinality="1..1"
* policy="dynamic"
* bind="setDeviceAccessAuthorizationService"
* unbind="unsetDeviceAccessAuthorizationService"
*/ */
public class OAuthExtensionServiceComponent { public class OAuthExtensionServiceComponent {
@ -79,7 +61,6 @@ public class OAuthExtensionServiceComponent {
log.debug("Starting OAuthExtensionBundle"); log.debug("Starting OAuthExtensionBundle");
} }
try { try {
DeviceMgtScopesConfig.init();
APIManagerConfiguration configuration = new APIManagerConfiguration(); APIManagerConfiguration configuration = new APIManagerConfiguration();
String filePath = new StringBuilder(). String filePath = new StringBuilder().
@ -108,8 +89,6 @@ public class OAuthExtensionServiceComponent {
OAuthExtensionsDataHolder.getInstance().setWhitelistedScopes(whiteList); OAuthExtensionsDataHolder.getInstance().setWhitelistedScopes(whiteList);
} catch (APIManagementException e) { } catch (APIManagementException e) {
log.error("Error occurred while loading DeviceMgtConfig configurations", e); log.error("Error occurred while loading DeviceMgtConfig configurations", e);
} catch (DeviceMgtScopesConfigurationFailedException e) {
log.error("Failed to initialize device scope configuration.", e);
} }
} }
@ -168,50 +147,5 @@ public class OAuthExtensionServiceComponent {
OAuthExtensionsDataHolder.getInstance().setoAuth2TokenValidationService(null); OAuthExtensionsDataHolder.getInstance().setoAuth2TokenValidationService(null);
} }
/**
* Sets PermissionManagerService Service.
*
* @param permissionManagerService An instance of PermissionManagerService
*/
protected void setPermissionManagerService(PermissionManagerService permissionManagerService) {
if (log.isDebugEnabled()) {
log.debug("Setting PermissionManager Service");
}
OAuthExtensionsDataHolder.getInstance().setPermissionManagerService(permissionManagerService);
}
/**
* Unsets PermissionManagerService Service.
*
* @param permissionManagerService An instance of PermissionManagerService
*/
protected void unsetPermissionManagerService(PermissionManagerService permissionManagerService) {
if (log.isDebugEnabled()) {
log.debug("Unsetting PermissionManager Service");
}
OAuthExtensionsDataHolder.getInstance().setPermissionManagerService(null);
}
/**
* Set DeviceManagementProviderService
* @param deviceAccessAuthorizationService An instance of deviceAccessAuthorizationService
*/
protected void setDeviceAccessAuthorizationService(DeviceAccessAuthorizationService deviceAccessAuthorizationService) {
if (log.isDebugEnabled()) {
log.debug("Setting Device Management Service");
}
OAuthExtensionsDataHolder.getInstance().setDeviceAccessAuthorizationService(deviceAccessAuthorizationService);
}
/**
* unset DeviceManagementProviderService
* @param deviceAccessAuthorizationService An instance of deviceAccessAuthorizationService
*/
protected void unsetDeviceAccessAuthorizationService(DeviceAccessAuthorizationService deviceAccessAuthorizationService) {
if (log.isDebugEnabled()) {
log.debug("Removing Device Management Service");
}
OAuthExtensionsDataHolder.getInstance().setDeviceAccessAuthorizationService(null);
}
} }

@ -18,9 +18,6 @@
package org.wso2.carbon.device.mgt.oauth.extensions.internal; package org.wso2.carbon.device.mgt.oauth.extensions.internal;
import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationService;
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.identity.oauth2.OAuth2TokenValidationService;
import org.wso2.carbon.user.core.service.RealmService; import org.wso2.carbon.user.core.service.RealmService;
@ -33,10 +30,7 @@ public class OAuthExtensionsDataHolder {
private RealmService realmService; private RealmService realmService;
private OAuth2TokenValidationService oAuth2TokenValidationService; private OAuth2TokenValidationService oAuth2TokenValidationService;
private PermissionManagerService permissionManagerService;
private List<String> whitelistedScopes; private List<String> whitelistedScopes;
private String deviceScope;
private DeviceAccessAuthorizationService deviceAccessAuthorizationService;
private static OAuthExtensionsDataHolder thisInstance = new OAuthExtensionsDataHolder(); private static OAuthExtensionsDataHolder thisInstance = new OAuthExtensionsDataHolder();
@ -69,17 +63,6 @@ public class OAuthExtensionsDataHolder {
this.oAuth2TokenValidationService = oAuth2TokenValidationService; this.oAuth2TokenValidationService = oAuth2TokenValidationService;
} }
public void setPermissionManagerService(PermissionManagerService permissionManagerService) {
this.permissionManagerService = permissionManagerService;
}
public PermissionManagerService getPermissionManagerService() {
if (permissionManagerService == null) {
throw new IllegalStateException("PermissionManager service is not initialized properly");
}
return permissionManagerService;
}
public List<String> getWhitelistedScopes() { public List<String> getWhitelistedScopes() {
return whitelistedScopes; return whitelistedScopes;
} }
@ -88,15 +71,4 @@ public class OAuthExtensionsDataHolder {
this.whitelistedScopes = whitelistedScopes; this.whitelistedScopes = whitelistedScopes;
} }
public String getDeviceScope() {
return deviceScope;
}
public DeviceAccessAuthorizationService getDeviceAccessAuthorizationService() {
return deviceAccessAuthorizationService;
}
public void setDeviceAccessAuthorizationService(DeviceAccessAuthorizationService deviceAccessAuthorizationService) {
this.deviceAccessAuthorizationService = deviceAccessAuthorizationService;
}
} }

@ -1,38 +0,0 @@
/*
* 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.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.validators.AbstractValidator;
import org.wso2.carbon.device.mgt.oauth.extensions.OAuthConstants;
import javax.servlet.http.HttpServletRequest;
/**
* Grant validator for JSON Web Tokens
* For JWT Grant to be valid the required parameters are
* grant_type and assertion
*/
public class ExtendedDeviceJWTGrantValidator extends AbstractValidator<HttpServletRequest> {
public ExtendedDeviceJWTGrantValidator() {
requiredParams.add(OAuth.OAUTH_GRANT_TYPE);
requiredParams.add(OAuth.OAUTH_ASSERTION);
}
}

@ -1,37 +0,0 @@
/*
* 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.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.validators.AbstractValidator;
import org.wso2.carbon.device.mgt.oauth.extensions.OAuthConstants;
import javax.servlet.http.HttpServletRequest;
/**
* Grant validator for Device Object with Password Grant type
*/
public class ExtendedDevicePasswordGrantValidator extends AbstractValidator<HttpServletRequest> {
public ExtendedDevicePasswordGrantValidator() {
requiredParams.add(OAuth.OAUTH_USERNAME);
requiredParams.add(OAuth.OAUTH_PASSWORD);
requiredParams.add(OAuthConstants.DEFAULT_DEVICE_ASSERTION);
}
}

@ -1,112 +0,0 @@
/*
* Copyright (c) 2015, 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.device.mgt.common.permission.mgt.Permission;
import org.wso2.carbon.device.mgt.common.permission.mgt.PermissionManagementException;
import org.wso2.carbon.device.mgt.common.permission.mgt.PermissionManagerService;
import org.wso2.carbon.device.mgt.oauth.extensions.OAuthExtUtils;
import org.wso2.carbon.device.mgt.oauth.extensions.internal.OAuthExtensionsDataHolder;
import org.wso2.carbon.identity.application.common.model.User;
import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception;
import org.wso2.carbon.identity.oauth2.model.AccessTokenDO;
import org.wso2.carbon.identity.oauth2.validators.OAuth2ScopeValidator;
import org.wso2.carbon.user.api.UserRealm;
import org.wso2.carbon.user.api.UserStoreException;
import java.util.Properties;
/**
* Custom OAuth2Token Scope validation implementation for DeviceManagement. This will validate the
* user permissions before dispatching the HTTP request to the actual endpoint.
*/
public class PermissionBasedScopeValidator extends OAuth2ScopeValidator {
private static final String URL_PROPERTY = "URL";
private static final String HTTP_METHOD_PROPERTY = "HTTP_METHOD";
public static final class PermissionMethod {
private PermissionMethod() {
throw new AssertionError();
}
public static final String READ = "read";
public static final String WRITE = "write";
public static final String DELETE = "delete";
public static final String ACTION = "action";
public static final String UI_EXECUTE = "ui.execute";
}
private static final Log log = LogFactory.getLog(PermissionBasedScopeValidator.class);
@Override
public boolean validateScope(AccessTokenDO accessTokenDO, String resource)
throws IdentityOAuth2Exception {
boolean status = true;
//Extract the url & http method
int idx = resource.lastIndexOf(':');
String url = resource.substring(0, idx);
String method = resource.substring(++idx, resource.length());
//This is to remove the url params for request path.
int urlParamIndex = url.indexOf('?');
if(urlParamIndex > 0) {
url = url.substring(0, urlParamIndex);
}
Properties properties = new Properties();
properties.put(PermissionBasedScopeValidator.URL_PROPERTY, url.toLowerCase());
properties.put(PermissionBasedScopeValidator.HTTP_METHOD_PROPERTY, method.toUpperCase());
PermissionManagerService permissionManagerService = OAuthExtensionsDataHolder.getInstance().
getPermissionManagerService();
try {
Permission permission = permissionManagerService.getPermission(properties);
User authzUser = accessTokenDO.getAuthzUser();
if ((permission != null) && (authzUser != null)) {
if (permission.getPath() == null) {
if (log.isDebugEnabled()) {
log.debug("Permission is not defined for the resource '" + resource + "'");
}
return true;
}
String username = authzUser.getUserName();
String userStore = authzUser.getUserStoreDomain();
int tenantId = OAuthExtUtils.getTenantId(authzUser.getTenantDomain());
UserRealm userRealm = OAuthExtensionsDataHolder.getInstance().getRealmService().getTenantUserRealm(tenantId);
if (userRealm != null && userRealm.getAuthorizationManager() != null) {
if (userStore != null) {
status = userRealm.getAuthorizationManager()
.isUserAuthorized(userStore + "/" + username, permission.getPath(),
PermissionMethod.UI_EXECUTE);
} else {
status = userRealm.getAuthorizationManager()
.isUserAuthorized(username, permission.getPath(), PermissionMethod.UI_EXECUTE);
}
}
}
} catch (PermissionManagementException e) {
log.error("Error occurred while validating the resource scope for : " + resource +
", Msg = " + e.getMessage(), e);
} catch (UserStoreException e) {
log.error("Error occurred while retrieving user store. " + e.getMessage());
}
return status;
}
}

@ -43,6 +43,7 @@ import java.security.KeyManagementException;
import java.security.KeyStoreException; import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -73,7 +74,9 @@ public class JWTClient {
throw new JWTClientException("JWT is not configured properly for user : " + username); throw new JWTClientException("JWT is not configured properly for user : " + username);
} }
params.add(new BasicNameValuePair(JWTConstants.JWT_PARAM_NAME, assertion)); params.add(new BasicNameValuePair(JWTConstants.JWT_PARAM_NAME, assertion));
params.add(new BasicNameValuePair(JWTConstants.SCOPE_PARAM_NAME, scopes)); if (scopes != null && !scopes.isEmpty()) {
params.add(new BasicNameValuePair(JWTConstants.SCOPE_PARAM_NAME, scopes));
}
return getTokenInfo(params, consumerKey, consumerSecret); return getTokenInfo(params, consumerKey, consumerSecret);
} }
@ -87,7 +90,9 @@ public class JWTClient {
throw new JWTClientException("JWT is not configured properly for user : " + username); throw new JWTClientException("JWT is not configured properly for user : " + username);
} }
params.add(new BasicNameValuePair(JWTConstants.JWT_PARAM_NAME, assertion)); params.add(new BasicNameValuePair(JWTConstants.JWT_PARAM_NAME, assertion));
params.add(new BasicNameValuePair(JWTConstants.SCOPE_PARAM_NAME, scopes)); if (scopes != null && !scopes.isEmpty()) {
params.add(new BasicNameValuePair(JWTConstants.SCOPE_PARAM_NAME, scopes));
}
if (paramsMap != null) { if (paramsMap != null) {
for (String key : paramsMap.keySet()) { for (String key : paramsMap.keySet()) {
params.add(new BasicNameValuePair(key, paramsMap.get(key))); params.add(new BasicNameValuePair(key, paramsMap.get(key)));
@ -156,6 +161,13 @@ public class JWTClient {
return new String(Base64.encodeBase64((consumerKey + ":" + consumerSecret).getBytes())); return new String(Base64.encodeBase64((consumerKey + ":" + consumerSecret).getBytes()));
} }
public String getJwtToken(String username) throws JWTClientException {
return JWTClientUtil.generateSignedJWTAssertion(username, jwtConfig, isDefaultJWTClient);
}
public String getJwtToken(String username, Map<String, String> claims) throws JWTClientException {
return JWTClientUtil.generateSignedJWTAssertion(username, jwtConfig, isDefaultJWTClient, claims);
}
} }

@ -33,6 +33,7 @@ import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy; import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils; import org.apache.http.util.EntityUtils;
import org.apache.solr.common.util.Hash;
import org.wso2.carbon.base.MultitenantConstants; import org.wso2.carbon.base.MultitenantConstants;
import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.core.util.KeyStoreManager; import org.wso2.carbon.core.util.KeyStoreManager;
@ -55,7 +56,9 @@ import java.security.*;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPrivateKey;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Properties; import java.util.Properties;
/** /**
@ -193,8 +196,13 @@ public class JWTClientUtil {
tenantRegistryLoader.loadTenantRegistry(tenantId); tenantRegistryLoader.loadTenantRegistry(tenantId);
} }
public static String generateSignedJWTAssertion(String username, JWTConfig jwtConfig, boolean isDefaultJWTClient) public static String generateSignedJWTAssertion(String username, JWTConfig jwtConfig, boolean isDefaultJWTClient)
throws JWTClientException { throws JWTClientException {
return generateSignedJWTAssertion(username, jwtConfig, isDefaultJWTClient, null);
}
public static String generateSignedJWTAssertion(String username, JWTConfig jwtConfig, boolean isDefaultJWTClient,
Map<String, String> customClaims) throws JWTClientException {
try { try {
String subject = username; String subject = username;
long currentTimeMillis = System.currentTimeMillis(); long currentTimeMillis = System.currentTimeMillis();
@ -222,6 +230,11 @@ public class JWTClientUtil {
claimsSet.setNotBeforeTime(new Date(nbf)); claimsSet.setNotBeforeTime(new Date(nbf));
claimsSet.setJWTID(jti); claimsSet.setJWTID(jti);
claimsSet.setAudience(aud); claimsSet.setAudience(aud);
if (customClaims != null && !customClaims.isEmpty()) {
for (String key : customClaims.keySet()) {
claimsSet.setClaim(key, customClaims.get(key));
}
}
// get Keystore params // get Keystore params
String keyStorePath = jwtConfig.getKeyStorePath(); String keyStorePath = jwtConfig.getKeyStorePath();

@ -21,17 +21,25 @@ package org.wso2.carbon.webapp.authenticator.framework.authenticator;
import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response; import org.apache.catalina.connector.Response;
import org.apache.catalina.util.Base64; import org.apache.catalina.util.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.CharChunk; import org.apache.tomcat.util.buf.CharChunk;
import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.buf.MessageBytes;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.api.UserStoreManager;
import org.wso2.carbon.webapp.authenticator.framework.AuthenticationException;
import org.wso2.carbon.webapp.authenticator.framework.AuthenticatorFrameworkDataHolder;
import org.wso2.carbon.webapp.authenticator.framework.Constants; import org.wso2.carbon.webapp.authenticator.framework.Constants;
import org.wso2.carbon.webapp.authenticator.framework.AuthenticationInfo; import org.wso2.carbon.webapp.authenticator.framework.AuthenticationInfo;
import org.wso2.carbon.webapp.authenticator.framework.Utils.Utils;
import java.util.Properties; import java.util.Properties;
public class BasicAuthAuthenticator implements WebappAuthenticator { public class BasicAuthAuthenticator implements WebappAuthenticator {
private static final String BASIC_AUTH_AUTHENTICATOR = "BasicAuth"; private static final String BASIC_AUTH_AUTHENTICATOR = "BasicAuth";
private static final Log log = LogFactory.getLog(BasicAuthAuthenticator.class);
@Override @Override
public void init() { public void init() {
@ -54,7 +62,27 @@ public class BasicAuthAuthenticator implements WebappAuthenticator {
@Override @Override
public AuthenticationInfo authenticate(Request request, Response response) { public AuthenticationInfo authenticate(Request request, Response response) {
return new AuthenticationInfo(); AuthenticationInfo authenticationInfo = new AuthenticationInfo();
Credentials credentials = getCredentials(request);
try {
int tenantId = Utils.getTenantIdOFUser(credentials.getUsername());
UserStoreManager userStore = AuthenticatorFrameworkDataHolder.getInstance().getRealmService().
getTenantUserRealm(tenantId).getUserStoreManager();
boolean authenticated = userStore.authenticate(credentials.getUsername(), credentials.getPassword());
if (authenticated) {
authenticationInfo.setStatus(Status.CONTINUE);
authenticationInfo.setUsername(credentials.getUsername());
authenticationInfo.setTenantDomain(Utils.getTenantDomain(tenantId));
authenticationInfo.setTenantId(tenantId);
} else {
authenticationInfo.setStatus(Status.FAILURE);
}
} catch (UserStoreException e) {
log.error("Error occurred while authenticating the user." + credentials.getUsername(), e);
} catch (AuthenticationException e) {
log.error("Error occurred while obtaining the tenant Id for user." + credentials.getUsername(), e);
}
return authenticationInfo;
} }
@Override @Override

@ -17,13 +17,13 @@
# #
#issuer of the JWT #issuer of the JWT
iss=CDMF_DEFAULT_IDP iss=iot_default
TokenEndpoint=https://localhost:${carbon.https.port}/oauth2/token TokenEndpoint=https://localhost:${carbon.https.port}/oauth2/token
#audience of JWT claim #audience of JWT claim
#comma seperated values #comma seperated values
aud=JwtIdentityAudience aud=wso2.org/products/iot
#expiration time of JWT (number of minutes from the current time) #expiration time of JWT (number of minutes from the current time)
exp=1000 exp=1000

@ -1,51 +0,0 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
~ 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.
-->
<!--This holds the scopes that are allowed by the device-mgt, The user require below permission to get the required scope-->
<!--These scopes are assigned after validating with device-mgt specific grant types-->
<DeviceMgtScopes>
<Action name="mqtt-publisher">
<Permissions>
<Permission>/permission/device-mgt/user/groups/device_operation</Permission>
<Permission>/permission/device-mgt/admin/groups</Permission>
<Permission>/permission/device-mgt/user/groups</Permission>
</Permissions>
</Action>
<Action name="mqtt-subscriber">
<Permissions>
<Permission>/permission/device-mgt/user/groups/device_monitor</Permission>
<Permission>/permission/device-mgt/admin/groups</Permission>
<Permission>/permission/device-mgt/user/groups</Permission>
</Permissions>
</Action>
<Action name="stats">
<Permissions>
<Permission>/permission/device-mgt/user/groups/device_monitor</Permission>
<Permission>/permission/device-mgt/admin/groups</Permission>
<Permission>/permission/device-mgt/user/groups</Permission>
</Permissions>
</Action>
<Action name="operation">
<Permissions>
<Permission>/permission/device-mgt/user/groups/device_operation</Permission>
<Permission>/permission/device-mgt/admin/groups</Permission>
<Permission>/permission/device-mgt/user/groups</Permission>
</Permissions>
</Action>
</DeviceMgtScopes>

@ -1,2 +1 @@
instructions.configure = \ instructions.configure = \
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.oauth.extensions_${feature.version}/device-mgt-scopes.xml,target:${installFolder}/../../conf/etc/device-mgt-scopes.xml,overwrite:true);\

@ -1830,6 +1830,7 @@
<version.commons.codec>1.4.0.wso2v1</version.commons.codec> <version.commons.codec>1.4.0.wso2v1</version.commons.codec>
<version.commons.io>2.4.0.wso2v1</version.commons.io> <version.commons.io>2.4.0.wso2v1</version.commons.io>
<version.commons.lang>2.6.0.wso2v1</version.commons.lang> <version.commons.lang>2.6.0.wso2v1</version.commons.lang>
<commons-lang.wso2.osgi.version.range>[2.6.0,3.0.0)</commons-lang.wso2.osgi.version.range>
<!-- Carbon API Management --> <!-- Carbon API Management -->
<carbon.api.mgt.version>6.0.5</carbon.api.mgt.version> <carbon.api.mgt.version>6.0.5</carbon.api.mgt.version>

Loading…
Cancel
Save