Add device-group authorization improvements

appm_improvement
Lasantha Dharmakeerthi 8 months ago
commit 5da2ae1f74

@ -0,0 +1,181 @@
/*
* Copyright (c) 2018 - 2024, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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 io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.api;
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.ErrorResponse;
import io.entgra.device.mgt.core.device.mgt.common.authorization.DeviceAuthorizationRequest;
import io.entgra.device.mgt.core.device.mgt.common.authorization.GroupAuthorizationRequest;
import io.entgra.device.mgt.core.device.mgt.common.authorization.GroupAuthorizationResult;
import io.swagger.annotations.*;
import org.apache.axis2.transport.http.HTTPConstants;
import javax.validation.Valid;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@SwaggerDefinition(
info = @Info(
version = "1.0.0",
title = "",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = "name", value = "AccessAuthorizationService"),
@ExtensionProperty(name = "context", value = "/api/device-mgt/v1.0/access"),
})
}
),
tags = {
@Tag(name = "device_management", description = "")
}
)
@Path("/access")
@Api(value = "AccessAuthorizationService", description = "This API carries all device group management related " +
"access authorization")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public interface AccessAuthorizationService {
@POST
@Path("/device")
@ApiOperation(
produces = MediaType.APPLICATION_JSON,
httpMethod = HTTPConstants.HEADER_GET,
value = "check device access authorization",
notes = "Returns device access acutorization info",
tags = "device_management"
)
@ApiResponses(
value = {
@ApiResponse(
code = 201,
message = "Created. \n Device group has successfully been created",
responseHeaders = {
@ResponseHeader(
name = "Content-Location",
description = "The URL of the added group."),
@ResponseHeader(
name = "Content-Type",
description = "The content type of the body"),
@ResponseHeader(
name = "ETag",
description = "Entity Tag of the response resource.\n" +
"Used by caches, or in conditional requests."),
@ResponseHeader(
name = "Last-Modified",
description = "Date and time the resource has been modified the last time" +
".\n" + "Used by caches, or in conditional requests.")
}
),
@ApiResponse(
code = 303,
message = "See Other. \n Source can be retrieved from the URL specified at the Location " +
"header.",
responseHeaders = {
@ResponseHeader(
name = "Content-Location",
description = "The Source URL of the document.")}),
@ApiResponse(
code = 400,
message = "Bad Request. \n Invalid request or validation error.",
response = ErrorResponse.class),
@ApiResponse(
code = 401,
message = "Unauthorized. \n Current logged in user is not authorized for this request",
response = ErrorResponse.class),
@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 access",
response = ErrorResponse.class)
})
Response checkDeviceAccess(
@ApiParam(
name = "deviceAccessRequest",
value = "Define the device access request object with data.",
required = true)
@Valid DeviceAuthorizationRequest deviceAuthorizationRequest);
@POST
@Path("/group")
@ApiOperation(
produces = MediaType.APPLICATION_JSON,
httpMethod = HTTPConstants.HEADER_GET,
value = "check device access authorization",
notes = "Returns device access acutorization info",
tags = "device_management"
)
@ApiResponses(
value = {
@ApiResponse(
code = 201,
message = "Created. \n Device group has successfully been created",
responseHeaders = {
@ResponseHeader(
name = "Content-Location",
description = "The URL of the added group."),
@ResponseHeader(
name = "Content-Type",
description = "The content type of the body"),
@ResponseHeader(
name = "ETag",
description = "Entity Tag of the response resource.\n" +
"Used by caches, or in conditional requests."),
@ResponseHeader(
name = "Last-Modified",
description = "Date and time the resource has been modified the last time" +
".\n" + "Used by caches, or in conditional requests.")
}
),
@ApiResponse(
code = 303,
message = "See Other. \n Source can be retrieved from the URL specified at the Location " +
"header.",
responseHeaders = {
@ResponseHeader(
name = "Content-Location",
description = "The Source URL of the document.")}),
@ApiResponse(
code = 400,
message = "Bad Request. \n Invalid request or validation error.",
response = ErrorResponse.class),
@ApiResponse(
code = 401,
message = "Unauthorized. \n Current logged in user is not authorized for this request",
response = ErrorResponse.class),
@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 access",
response = ErrorResponse.class)
})
Response checkGroupAccess(
@ApiParam(
name = "groupAccessRequest",
value = "Define the group access request object with data.",
required = true)
@Valid GroupAuthorizationRequest request);
}

@ -0,0 +1,95 @@
/*
* Copyright (c) 2018 - 2024, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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 io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.impl;
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.api.AccessAuthorizationService;
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.util.DeviceMgtAPIUtils;
import io.entgra.device.mgt.core.device.mgt.common.DeviceIdentifier;
import io.entgra.device.mgt.core.device.mgt.common.authorization.*;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.List;
public class AccessAuthorizationServiceImpl implements AccessAuthorizationService {
private static final Log log = LogFactory.getLog(AccessAuthorizationServiceImpl.class);
@Override
public Response checkDeviceAccess(DeviceAuthorizationRequest deviceAuthorizationRequest) {
if (StringUtils.isEmpty(deviceAuthorizationRequest.getType())) {
String msg = "device type not specified";
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
}
if (deviceAuthorizationRequest.getDeviceIds().isEmpty()) {
String msg = "device ids not specified";
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
}
if (deviceAuthorizationRequest.getPermissions().isEmpty()) {
String msg = "permissions not specified";
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
}
List<DeviceIdentifier> deviceIdentifiers = new ArrayList<>();
for(String id : deviceAuthorizationRequest.getDeviceIds()) {
DeviceIdentifier identifier = new DeviceIdentifier(id, deviceAuthorizationRequest.getType());
deviceIdentifiers.add(identifier);
}
try {
DeviceAuthorizationResult result = DeviceMgtAPIUtils.getDeviceAccessAuthorizationService()
.isUserAuthorized(deviceIdentifiers, deviceAuthorizationRequest.getUsername(),
deviceAuthorizationRequest.getPermissions().toArray(new String[0]));
return Response.status(Response.Status.OK).entity(result).build();
} catch (DeviceAccessAuthorizationException e) {
String msg = "Error occurred while checking access info";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
}
@Override
public Response checkGroupAccess(GroupAuthorizationRequest request) {
if (request.getGroupIds().isEmpty()) {
String msg = "group ids not specified";
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
}
if (request.getPermissions().isEmpty()) {
String msg = "permissions not specified";
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
}
try {
GroupAuthorizationResult result = DeviceMgtAPIUtils.getGroupAccessAuthorizationService()
.isUserAuthorized(request.getGroupIds(), request.getUsername(),
request.getPermissions().toArray(new String[0]));
return Response.status(Response.Status.OK).entity(result).build();
} catch (GroupAccessAuthorizationException e) {
String msg = "Error occurred while checking access info";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
}
}

@ -21,6 +21,7 @@ import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import io.entgra.device.mgt.core.device.mgt.core.permission.mgt.PermissionManagerServiceImpl;
import org.apache.axis2.AxisFault;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@ -167,7 +168,9 @@ public class DeviceAgentServiceImpl implements DeviceAgentService {
DeviceMgtAPIUtils.getDeviceAccessAuthorizationService();
boolean status;
try {
status = deviceAccessAuthorizationService.isUserAuthorized(new DeviceIdentifier(id, type));
String requiredPermission = PermissionManagerServiceImpl.getInstance().getRequiredPermission();
String[] requiredPermissions = new String[] {requiredPermission};
status = deviceAccessAuthorizationService.isUserAuthorized(new DeviceIdentifier(id, type), requiredPermissions);
} catch (DeviceAccessAuthorizationException e) {
String msg = "Error occurred while modifying enrollment of the Android device that carries the id '" +
id + "'";
@ -229,8 +232,10 @@ public class DeviceAgentServiceImpl implements DeviceAgentService {
String msg = "invalid payload structure";
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
} else {
String requiredPermission = PermissionManagerServiceImpl.getInstance().getRequiredPermission();
String[] requiredPermissions = new String[] {requiredPermission};
boolean authorized = DeviceMgtAPIUtils.getDeviceAccessAuthorizationService().isUserAuthorized
(new DeviceIdentifier(type, deviceId));
(new DeviceIdentifier(type, deviceId), requiredPermissions);
if (!authorized) {
String msg = "Does not have permission to access the device.";
return Response.status(Response.Status.UNAUTHORIZED).entity(msg).build();
@ -329,8 +334,10 @@ public class DeviceAgentServiceImpl implements DeviceAgentService {
String msg = "Invalid payload structure";
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
} else {
String requiredPermission = PermissionManagerServiceImpl.getInstance().getRequiredPermission();
String[] requiredPermissions = new String[] {requiredPermission};
boolean authorized = DeviceMgtAPIUtils.getDeviceAccessAuthorizationService().isUserAuthorized
(new DeviceIdentifier(type, deviceId));
(new DeviceIdentifier(type, deviceId), requiredPermissions);
if (!authorized) {
String msg = "Does not have permission to access the device.";
return Response.status(Response.Status.UNAUTHORIZED).entity(msg).build();

@ -28,6 +28,7 @@ import io.entgra.device.mgt.core.application.mgt.common.services.SubscriptionMan
import io.entgra.device.mgt.core.application.mgt.core.util.HelperUtil;
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.impl.util.DisenrollRequest;
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.util.DeviceMgtUtil;
import io.entgra.device.mgt.core.device.mgt.core.permission.mgt.PermissionManagerServiceImpl;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
@ -580,7 +581,9 @@ public class DeviceManagementServiceImpl implements DeviceManagementService {
String authorizedUser = CarbonContext.getThreadLocalCarbonContext().getUsername();
DeviceIdentifier deviceIdentifier = new DeviceIdentifier(id, type);
// check whether the user is authorized
if (!deviceAccessAuthorizationService.isUserAuthorized(deviceIdentifier, authorizedUser)) {
String requiredPermission = PermissionManagerServiceImpl.getInstance().getRequiredPermission();
String[] requiredPermissions = new String[] {requiredPermission};
if (!deviceAccessAuthorizationService.isUserAuthorized(deviceIdentifier, authorizedUser, requiredPermissions)) {
String msg = "User '" + authorizedUser + "' is not authorized to retrieve the given device id '" + id + "'";
log.error(msg);
return Response.status(Response.Status.UNAUTHORIZED).entity(
@ -716,7 +719,9 @@ public class DeviceManagementServiceImpl implements DeviceManagementService {
}
DeviceIdentifier deviceIdentifier = new DeviceIdentifier(id, device.getType());
// check whether the user is authorized
if (!deviceAccessAuthorizationService.isUserAuthorized(deviceIdentifier, authorizedUser)) {
String requiredPermission = PermissionManagerServiceImpl.getInstance().getRequiredPermission();
String[] requiredPermissions = new String[] {requiredPermission};
if (!deviceAccessAuthorizationService.isUserAuthorized(deviceIdentifier, authorizedUser, requiredPermissions)) {
String message = "User '" + authorizedUser + "' is not authorized to retrieve the given " +
"device id '" + id + "'";
log.error(message);

@ -18,6 +18,7 @@
package io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.impl;
import io.entgra.device.mgt.core.device.mgt.common.PolicyPaginationRequest;
import io.entgra.device.mgt.core.device.mgt.core.permission.mgt.PermissionManagerServiceImpl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.PrivilegedCarbonContext;
@ -85,7 +86,9 @@ public class PolicyManagementServiceImpl implements PolicyManagementService {
PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
String username = threadLocalCarbonContext.getUsername();
try {
if (!deviceAccessAuthorizationService.isUserAuthorized(deviceIdentifier, username)) {
String requiredPermission = PermissionManagerServiceImpl.getInstance().getRequiredPermission();
String[] requiredPermissions = new String[] {requiredPermission};
if (!deviceAccessAuthorizationService.isUserAuthorized(deviceIdentifier, username, requiredPermissions)) {
return Response.status(Response.Status.UNAUTHORIZED).entity(
new ErrorResponse.ErrorResponseBuilder().setMessage
("Current logged in user is not authorized to add policies").build()).build();

@ -172,6 +172,9 @@ public class GroupManagementAdminServiceImpl implements GroupManagementAdminServ
if (group == null) {
return Response.status(Response.Status.BAD_REQUEST).build();
}
if (StringUtils.isEmpty(group.getOwner())) {
group.setOwner(PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername());
}
group.setStatus(DeviceGroupConstants.GroupStatus.ACTIVE);
try {
DeviceMgtAPIUtils.getGroupManagementProviderService().createGroup(group, DEFAULT_ADMIN_ROLE, DEFAULT_ADMIN_PERMISSIONS);

@ -21,7 +21,9 @@ package io.entgra.device.mgt.core.device.mgt.api.jaxrs.util;
import io.entgra.device.mgt.core.apimgt.webapp.publisher.APIPublisherService;
import io.entgra.device.mgt.core.application.mgt.common.services.ApplicationManager;
import io.entgra.device.mgt.core.application.mgt.common.services.SubscriptionManager;
import io.entgra.device.mgt.core.device.mgt.common.authorization.GroupAccessAuthorizationService;
import io.entgra.device.mgt.core.device.mgt.common.metadata.mgt.DeviceStatusManagementService;
import io.entgra.device.mgt.core.device.mgt.core.permission.mgt.PermissionManagerServiceImpl;
import org.apache.axis2.AxisFault;
import org.apache.axis2.client.Options;
import org.apache.axis2.java.security.SSLProtocolSocketFactory;
@ -342,6 +344,17 @@ public class DeviceMgtAPIUtils {
return deviceAccessAuthorizationService;
}
public static GroupAccessAuthorizationService getGroupAccessAuthorizationService() {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
GroupAccessAuthorizationService groupAccessAuthorizationService =
(GroupAccessAuthorizationService) ctx.getOSGiService(GroupAccessAuthorizationService.class, null);
if (groupAccessAuthorizationService == null) {
String msg = "GroupAccessAuthorizationService service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
return groupAccessAuthorizationService;
}
public static GroupManagementProviderService getGroupManagementProviderService() {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
GroupManagementProviderService groupManagementProviderService =
@ -1111,7 +1124,9 @@ public class DeviceMgtAPIUtils {
RequestValidationUtil.validateDeviceIdentifier(deviceType, identifier);
DeviceIdentifier deviceIdentifier = new DeviceIdentifier(identifier, deviceType);
if (!getDeviceAccessAuthorizationService().isUserAuthorized(deviceIdentifier, authorizedUser)) {
String requiredPermission = PermissionManagerServiceImpl.getInstance().getRequiredPermission();
String[] requiredPermissions = new String[] {requiredPermission};
if (!getDeviceAccessAuthorizationService().isUserAuthorized(deviceIdentifier, authorizedUser, requiredPermissions)) {
String msg = "User '" + authorizedUser + "' is not authorized to retrieve the given device id '" +
identifier + "'";
log.error(msg);

@ -285,7 +285,7 @@ public class DeviceAgentServiceTest {
Device testDevice = DeviceMgtAPITestHelper.generateDummyDevice(TEST_DEVICE_TYPE, TEST_DEVICE_IDENTIFIER);
Mockito.when(this.deviceManagementProviderService
.getDevice(Mockito.any(DeviceIdentifier.class), Mockito.any(Boolean.class))).thenReturn(testDevice);
Mockito.when(this.deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class)))
Mockito.when(this.deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class), Mockito.any(String[].class)))
.thenThrow(new DeviceAccessAuthorizationException());
Response response = deviceAgentService.updateDevice(TEST_DEVICE_TYPE, TEST_DEVICE_IDENTIFIER, testDevice);
Assert.assertNotNull(response, "Response should not be null");
@ -305,7 +305,7 @@ public class DeviceAgentServiceTest {
Device testDevice = DeviceMgtAPITestHelper.generateDummyDevice(TEST_DEVICE_TYPE, TEST_DEVICE_IDENTIFIER);
Mockito.when(this.deviceManagementProviderService
.getDevice(Mockito.any(DeviceIdentifier.class), Mockito.any(Boolean.class))).thenReturn(testDevice);
Mockito.when(this.deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class)))
Mockito.when(this.deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class), Mockito.any(String[].class)))
.thenReturn(false);
Response response = deviceAgentService.updateDevice(TEST_DEVICE_TYPE, TEST_DEVICE_IDENTIFIER, testDevice);
Assert.assertNotNull(response, "Response should not be null");
@ -327,7 +327,7 @@ public class DeviceAgentServiceTest {
Device testDevice = DeviceMgtAPITestHelper.generateDummyDevice(TEST_DEVICE_TYPE, TEST_DEVICE_IDENTIFIER);
Mockito.when(this.deviceManagementProviderService
.getDevice(Mockito.any(DeviceIdentifier.class), Mockito.any(Boolean.class))).thenReturn(testDevice);
Mockito.when(this.deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class)))
Mockito.when(this.deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class), Mockito.any(String[].class)))
.thenReturn(true);
Mockito.when(this.deviceManagementProviderService.modifyEnrollment(Mockito.any())).thenReturn(false);
Response response = deviceAgentService.updateDevice(TEST_DEVICE_TYPE, TEST_DEVICE_IDENTIFIER, testDevice);
@ -350,7 +350,7 @@ public class DeviceAgentServiceTest {
Device testDevice = DeviceMgtAPITestHelper.generateDummyDevice(TEST_DEVICE_TYPE, TEST_DEVICE_IDENTIFIER);
Mockito.when(this.deviceManagementProviderService
.getDevice(Mockito.any(DeviceIdentifier.class), Mockito.any(Boolean.class))).thenReturn(testDevice);
Mockito.when(this.deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class)))
Mockito.when(this.deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class), Mockito.any(String[].class)))
.thenReturn(true);
Mockito.when(this.deviceManagementProviderService.modifyEnrollment(Mockito.any()))
.thenThrow(new DeviceManagementException());
@ -372,7 +372,7 @@ public class DeviceAgentServiceTest {
"getAuthenticatedUser")).toReturn(AUTHENTICATED_USER);
Device testDevice = DeviceMgtAPITestHelper.generateDummyDevice(TEST_DEVICE_TYPE, TEST_DEVICE_IDENTIFIER);
Mockito.when(this.deviceManagementProviderService.getDevice(Mockito.any(DeviceIdentifier.class), Mockito.any(Boolean.class))).thenReturn(testDevice);
Mockito.when(this.deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class)))
Mockito.when(this.deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class), Mockito.any(String[].class)))
.thenReturn(true);
Mockito.when(this.deviceManagementProviderService.modifyEnrollment(Mockito.any())).thenReturn((true));
Response response = deviceAgentService.updateDevice(TEST_DEVICE_TYPE, TEST_DEVICE_IDENTIFIER, testDevice);
@ -408,7 +408,7 @@ public class DeviceAgentServiceTest {
.toReturn(this.privilegedCarbonContext);
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class,
"getDeviceAccessAuthorizationService")).toReturn(this.deviceAccessAuthorizationService);
Mockito.when(this.deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class)))
Mockito.when(this.deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class), Mockito.any(String[].class)))
.thenReturn(false);
Mockito.when(this.privilegedCarbonContext.getTenantDomain())
.thenReturn(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME);
@ -432,7 +432,7 @@ public class DeviceAgentServiceTest {
.toReturn(this.privilegedCarbonContext);
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class,
"getDeviceAccessAuthorizationService")).toReturn(this.deviceAccessAuthorizationService);
Mockito.when(this.deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class)))
Mockito.when(this.deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class), Mockito.any(String[].class)))
.thenThrow(new DeviceAccessAuthorizationException());
Mockito.when(this.privilegedCarbonContext.getTenantDomain())
.thenReturn(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME);
@ -457,7 +457,7 @@ public class DeviceAgentServiceTest {
.toReturn(this.privilegedCarbonContext);
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class,
"getDeviceAccessAuthorizationService")).toReturn(this.deviceAccessAuthorizationService);
Mockito.when(this.deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class)))
Mockito.when(this.deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class), Mockito.any(String[].class)))
.thenReturn(true);
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getEventStreamAdminServiceStub"))
.toReturn(this.eventStreamAdminServiceStub);
@ -485,7 +485,7 @@ public class DeviceAgentServiceTest {
.toReturn(this.privilegedCarbonContext);
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class,
"getDeviceAccessAuthorizationService")).toReturn(this.deviceAccessAuthorizationService);
Mockito.when(this.deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class)))
Mockito.when(this.deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class), Mockito.any(String[].class)))
.thenReturn(true);
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getEventStreamAdminServiceStub"))
.toThrow(new AxisFault(""));
@ -511,7 +511,7 @@ public class DeviceAgentServiceTest {
.toReturn(this.privilegedCarbonContext);
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class,
"getDeviceAccessAuthorizationService")).toReturn(this.deviceAccessAuthorizationService);
Mockito.when(this.deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class)))
Mockito.when(this.deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class), Mockito.any(String[].class)))
.thenReturn(true);
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getEventStreamAdminServiceStub"))
.toThrow(new RemoteException());
@ -539,7 +539,7 @@ public class DeviceAgentServiceTest {
.toReturn(this.privilegedCarbonContext);
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class,
"getDeviceAccessAuthorizationService")).toReturn(this.deviceAccessAuthorizationService);
Mockito.when(this.deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class)))
Mockito.when(this.deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class), Mockito.any(String[].class)))
.thenReturn(true);
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getEventStreamAdminServiceStub"))
.toThrow(new JWTClientException());
@ -567,7 +567,7 @@ public class DeviceAgentServiceTest {
.toReturn(this.privilegedCarbonContext);
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class,
"getDeviceAccessAuthorizationService")).toReturn(this.deviceAccessAuthorizationService);
Mockito.when(this.deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class)))
Mockito.when(this.deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class), Mockito.any(String[].class)))
.thenReturn(true);
PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getEventStreamAdminServiceStub"))
.toThrow(new UserStoreException());

@ -215,7 +215,7 @@ public class DeviceManagementServiceImplTest {
Mockito.when(carbonContext.getTenantId()).thenReturn(-1234);
Mockito.when(carbonContext.getUsername()).thenReturn(DEFAULT_USERNAME);
Mockito.when(deviceAccessAuthorizationService.isUserAuthorized(Mockito.any(DeviceIdentifier.class),
Mockito.anyString())).thenReturn(true);
Mockito.anyString(), Mockito.any(String[].class))).thenReturn(true);
Response response = this.deviceManagementService
.getDeviceByID(TEST_DEVICE_IDENTIFIER, ifModifiedSince,true);

@ -28,15 +28,6 @@ import java.util.List;
* accessing the device information and performing MDM operations on devices.
*/
public interface DeviceAccessAuthorizationService {
/**
* This method will check whether the currently logged-in user has the access to the device identified by the given
* DeviceIdentifier.
*
* @param deviceIdentifier - DeviceIdentifier of the device to be checked.
* @return Boolean authorization result.
* @throws DeviceAccessAuthorizationException if something goes wrong when checking the authorization.
*/
boolean isUserAuthorized(DeviceIdentifier deviceIdentifier) throws DeviceAccessAuthorizationException;
/**
* This method will check whether the currently logged-in user has the access to the device identified by the given
@ -50,18 +41,6 @@ public interface DeviceAccessAuthorizationService {
boolean isUserAuthorized(DeviceIdentifier deviceIdentifier, String[] groupPermissions)
throws DeviceAccessAuthorizationException;
/**
* This method will check whether the currently logged-in user has the access to the devices identified by the given
* DeviceIdentifier list.
*
* @param deviceIdentifiers - List of DeviceIdentifiers to be checked for authorization.
* @return DeviceAuthorizationResult - Authorization result object including the list of authorized devices and
* unauthorized devices.
* @throws DeviceAccessAuthorizationException if something goes wrong when checking the authorization.
*/
DeviceAuthorizationResult isUserAuthorized(List<DeviceIdentifier> deviceIdentifiers) throws
DeviceAccessAuthorizationException;
/**
* This method will check whether the currently logged-in user has the access to the devices identified by the given
* DeviceIdentifier list.
@ -103,18 +82,6 @@ public interface DeviceAccessAuthorizationService {
String[] groupPermissions) throws
DeviceAccessAuthorizationException;
/**
* This method will check whether the given user has the access to the device identified by the given
* DeviceIdentifier.
*
* @param deviceIdentifier - DeviceIdentifier of the device to be checked.
* @param username - Username of the user to be checked for authorization.
* @return Boolean authorization result.
* @throws DeviceAccessAuthorizationException if something goes wrong when checking the authorization.
*/
boolean isUserAuthorized(DeviceIdentifier deviceIdentifier, String username) throws
DeviceAccessAuthorizationException;
/**
* This method will check whether the authenticated user has the admin permissions.
*
@ -122,17 +89,4 @@ public interface DeviceAccessAuthorizationService {
* @throws DeviceAccessAuthorizationException if something goes wrong when checking the authorization.
*/
boolean isDeviceAdminUser() throws DeviceAccessAuthorizationException;
/**
* This method will check whether the given user has the access to the devices identified by the given
* DeviceIdentifier list.
*
* @param deviceIdentifiers - List of DeviceIdentifiers to be checked for authorization.
* @param username - Username of the user to be checked for authorization.
* @return DeviceAuthorizationResult - Authorization result object including the list of authorized devices and
* unauthorized devices.
* @throws DeviceAccessAuthorizationException if something goes wrong when checking the authorization.
*/
DeviceAuthorizationResult isUserAuthorized(List<DeviceIdentifier> deviceIdentifiers, String username) throws
DeviceAccessAuthorizationException;
}

@ -0,0 +1,68 @@
/*
* Copyright (c) 2018 - 2024, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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 io.entgra.device.mgt.core.device.mgt.common.authorization;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
@ApiModel(value = "DeviceAuthorizationRequest", description = "")
public class DeviceAuthorizationRequest {
@ApiModelProperty(name = "type", value = "device type")
private String type;
@ApiModelProperty(name = "deviceIds", value = "list of device ids")
private List<String> deviceIds;
@ApiModelProperty(name = "username", value = "user who is accessing the device")
private String username;
@ApiModelProperty(name = "permissions", value = "list of permissions")
private List<String> permissions;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List<String> getDeviceIds() {
return deviceIds;
}
public void setDeviceIds(List<String> deviceIds) {
this.deviceIds = deviceIds;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public List<String> getPermissions() {
return permissions;
}
public void setPermissions(List<String> permissions) {
this.permissions = permissions;
}
}

@ -0,0 +1,61 @@
/*
* Copyright (c) 2018 - 2024, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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 io.entgra.device.mgt.core.device.mgt.common.authorization;
/**
* Custom exception class which wraps exceptions occurred inside GroupAccessAuthorization service.
*/
public class GroupAccessAuthorizationException extends Exception {
private static final long serialVersionUID = -3151279331929070297L;
private String errorMessage;
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public GroupAccessAuthorizationException(String msg, Exception nestedEx) {
super(msg, nestedEx);
setErrorMessage(msg);
}
public GroupAccessAuthorizationException(String message, Throwable cause) {
super(message, cause);
setErrorMessage(message);
}
public GroupAccessAuthorizationException(String msg) {
super(msg);
setErrorMessage(msg);
}
public GroupAccessAuthorizationException() {
super();
}
public GroupAccessAuthorizationException(Throwable cause) {
super(cause);
}
}

@ -0,0 +1,33 @@
/*
* Copyright (c) 2018 - 2024, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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 io.entgra.device.mgt.core.device.mgt.common.authorization;
import java.util.List;
public interface GroupAccessAuthorizationService {
public boolean isUserAuthorized(int groupId, String username, String[] groupPermissions)
throws GroupAccessAuthorizationException;
public boolean isUserAuthorized(int groupId, String[] groupPermissions)
throws GroupAccessAuthorizationException;
public GroupAuthorizationResult isUserAuthorized(List<Integer> groupIds, String username, String[] groupPermission)
throws GroupAccessAuthorizationException;
}

@ -0,0 +1,58 @@
/*
* Copyright (c) 2018 - 2024, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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 io.entgra.device.mgt.core.device.mgt.common.authorization;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
@ApiModel(value = "GroupAuthorizationRequest", description = "")
public class GroupAuthorizationRequest {
@ApiModelProperty(name = "groupIds", value = "list of group Ids")
private List<Integer> groupIds;
@ApiModelProperty(name = "username", value = "user who is accessing the device")
private String username;
@ApiModelProperty(name = "permissions", value = "list of permissions")
private List<String> permissions;
public List<Integer> getGroupIds() {
return groupIds;
}
public void setGroupIds(List<Integer> groupIds) {
this.groupIds = groupIds;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public List<String> getPermissions() {
return permissions;
}
public void setPermissions(List<String> permissions) {
this.permissions = permissions;
}
}

@ -0,0 +1,56 @@
/*
* Copyright (c) 2018 - 2024, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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 io.entgra.device.mgt.core.device.mgt.common.authorization;
import java.util.ArrayList;
import java.util.List;
/**
* Represents a GroupAuthorizationResult including a list of authorized groups and a list of unauthorized groups.
*/
public class GroupAuthorizationResult {
private List<Integer> authorizedGroupIds = new ArrayList<>();
private List<Integer> unauthorizedGroupIds= new ArrayList<>();
public List<Integer> getAuthorizedGroupIds() {
return authorizedGroupIds;
}
public void setAuthorizedGroupIds(List<Integer> authorizedGroupIds) {
this.authorizedGroupIds = authorizedGroupIds;
}
public List<Integer> getUnauthorizedGroupIds() {
return unauthorizedGroupIds;
}
public void setUnauthorizedGroupIds(List<Integer> unauthorizedGroupIds) {
this.unauthorizedGroupIds = unauthorizedGroupIds;
}
public void addAuthorizedGroupId(int groupId) {
this.authorizedGroupIds.add(groupId);
}
public void addUnauthorizedGroupId(int groupId) {
this.unauthorizedGroupIds.add(groupId);
}
}

@ -63,41 +63,55 @@ public class DeviceAccessAuthorizationServiceImpl implements DeviceAccessAuthori
return !DeviceManagementDataHolder.getInstance().requireDeviceAuthorization(deviceIdentifier.getType());
}
//check for admin and ownership permissions
if (isAdmin(username, tenantId) || isDeviceOwner(deviceIdentifier, username)) {
if (isDeviceAdminUser(username, tenantId) || isDeviceOwner(deviceIdentifier, username)) {
return true;
}
//check for group permissions
if (groupPermissions == null || groupPermissions.length == 0) {
return false;
} else {
// if group permissions specified, check whether that permission is available in shared role
try {
return isSharedViaGroup(deviceIdentifier, username);
} catch (GroupManagementException | UserStoreException e) {
boolean isAuthorized = true;
for (String groupPermission : groupPermissions) {
if (!isAuthorizedViaSharedGroup(deviceIdentifier, username, groupPermission)) {
//if at least one failed, authorizations fails and break the loop
isAuthorized = false;
break;
}
}
return isAuthorized;
} catch (DeviceAccessAuthorizationException e) {
throw new DeviceAccessAuthorizationException("Unable to authorize the access to device : " +
deviceIdentifier.getId() + " for the user : " +
username, e);
}
}
}
private boolean isSharedViaGroup(DeviceIdentifier deviceIdentifier, String username)
throws GroupManagementException, UserStoreException {
private boolean isAuthorizedViaSharedGroup(DeviceIdentifier deviceIdentifier, String username, String groupPermission)
throws DeviceAccessAuthorizationException {
try {
List<DeviceGroup> groupsWithDevice = DeviceManagementDataHolder.getInstance()
.getGroupManagementProviderService().getGroups(deviceIdentifier, false);
String[] userRoles = DeviceManagementDataHolder.getInstance().getRealmService()
.getTenantUserRealm(getTenantId()).getUserStoreManager().getRoleListOfUser(username);
UserRealm userRealm = DeviceManagementDataHolder.getInstance().getRealmService()
.getTenantUserRealm(getTenantId());
String[] userRoles = userRealm.getUserStoreManager().getRoleListOfUser(username);
for (DeviceGroup deviceGroup : groupsWithDevice) {
List<String> sharingRoles = DeviceManagementDataHolder.getInstance()
.getGroupManagementProviderService().getRoles(deviceGroup.getGroupId());
for (String role : userRoles) {
if (sharingRoles.contains(role)) {
if (sharingRoles.contains(role) && userRealm.getAuthorizationManager().
isRoleAuthorized(role, groupPermission, CarbonConstants.UI_PERMISSION_ACTION)) {
return true;
}
}
}
return false;
} catch (GroupManagementException | UserStoreException e) {
throw new DeviceAccessAuthorizationException("unable to authorized via shared role, " + groupPermission);
}
@Override
public boolean isUserAuthorized(DeviceIdentifier deviceIdentifier, String username)
throws DeviceAccessAuthorizationException {
return isUserAuthorized(deviceIdentifier, username, null);
}
@Override
@ -106,18 +120,13 @@ public class DeviceAccessAuthorizationServiceImpl implements DeviceAccessAuthori
return isUserAuthorized(deviceIdentifier, this.getUserName(), groupPermissions);
}
@Override
public boolean isUserAuthorized(DeviceIdentifier deviceIdentifier) throws DeviceAccessAuthorizationException {
return isUserAuthorized(deviceIdentifier, this.getUserName(), null);
}
@Override
public boolean isDeviceAdminUser() throws DeviceAccessAuthorizationException {
String username = this.getUserName();
int tenantId = this.getTenantId();
try {
return isAdminUser(username, tenantId);
} catch (UserStoreException e) {
return isDeviceAdminUser(username, tenantId);
} catch (DeviceAccessAuthorizationException e) {
throw new DeviceAccessAuthorizationException("Unable to check the admin permissions of user : " +
username + " in tenant : " + tenantId, e);
}
@ -132,7 +141,7 @@ public class DeviceAccessAuthorizationServiceImpl implements DeviceAccessAuthori
return null;
}
DeviceAuthorizationResult deviceAuthorizationResult = new DeviceAuthorizationResult();
if (isAdmin(username, tenantId)) {
if (isDeviceAdminUser(username, tenantId)) {
deviceAuthorizationResult.setAuthorizedDevices(deviceIdentifiers);
return deviceAuthorizationResult;
}
@ -149,7 +158,7 @@ public class DeviceAccessAuthorizationServiceImpl implements DeviceAccessAuthori
//check for group permissions
boolean isAuthorized = true;
for (String groupPermission : groupPermissions) {
if (!isAuthorizedViaGroup(username, deviceIdentifier, groupPermission)) {
if (!isAuthorizedViaSharedGroup(deviceIdentifier, username, groupPermission)) {
//if at least one failed, authorizations fails and break the loop
isAuthorized = false;
break;
@ -160,7 +169,7 @@ public class DeviceAccessAuthorizationServiceImpl implements DeviceAccessAuthori
} else {
deviceAuthorizationResult.addUnauthorizedDevice(deviceIdentifier);
}
} catch (GroupManagementException e) {
} catch (DeviceAccessAuthorizationException e) {
throw new DeviceAccessAuthorizationException("Unable to authorize the access to device : " +
deviceIdentifier.getId() + " for the user : " +
username, e);
@ -170,55 +179,12 @@ public class DeviceAccessAuthorizationServiceImpl implements DeviceAccessAuthori
return deviceAuthorizationResult;
}
@Override
public DeviceAuthorizationResult isUserAuthorized(List<DeviceIdentifier> deviceIdentifiers, String username)
throws DeviceAccessAuthorizationException {
return isUserAuthorized(deviceIdentifiers, username, null);
}
@Override
public DeviceAuthorizationResult isUserAuthorized(List<DeviceIdentifier> deviceIdentifiers)
throws DeviceAccessAuthorizationException {
return isUserAuthorized(deviceIdentifiers, this.getUserName(), null);
}
@Override
public DeviceAuthorizationResult isUserAuthorized(List<DeviceIdentifier> deviceIdentifiers, String[] groupPermissions)
throws DeviceAccessAuthorizationException {
return isUserAuthorized(deviceIdentifiers, this.getUserName(), groupPermissions);
}
private boolean isAdmin(String username, int tenantId)
throws DeviceAccessAuthorizationException {
try {
//Check for admin users. If the user is an admin user we authorize the access to that device.
return (isAdminUser(username, tenantId));
} catch (UserStoreException e) {
throw new DeviceAccessAuthorizationException("Unable to authorize the access for the user : " +
username, e);
}
}
private boolean isAuthorizedViaGroup(String username, DeviceIdentifier deviceIdentifier, String groupPermission)
throws GroupManagementException {
List<DeviceGroup> authorizedGroups =
DeviceManagementDataHolder.getInstance().getGroupManagementProviderService()
.getGroups(username, groupPermission, false);
List<DeviceGroup> groupsWithDevice =
DeviceManagementDataHolder.getInstance().getGroupManagementProviderService()
.getGroups(deviceIdentifier, false);
for (DeviceGroup group : authorizedGroups) {
Iterator<DeviceGroup> groupsWithDeviceIterator = groupsWithDevice.iterator();
while (groupsWithDeviceIterator.hasNext()) {
DeviceGroup deviceGroup = groupsWithDeviceIterator.next();
if (deviceGroup.getGroupId() == group.getGroupId()) {
return true;
}
}
}
return false;
}
private boolean isDeviceOwner(DeviceIdentifier deviceIdentifier, String username)
throws DeviceAccessAuthorizationException {
//Check for device ownership. If the user is the owner of the device we allow the access.
@ -232,7 +198,8 @@ public class DeviceAccessAuthorizationServiceImpl implements DeviceAccessAuthori
}
}
private boolean isAdminUser(String username, int tenantId) throws UserStoreException {
private boolean isDeviceAdminUser(String username, int tenantId) throws DeviceAccessAuthorizationException {
try {
UserRealm userRealm = DeviceManagementDataHolder.getInstance().getRealmService().getTenantUserRealm(tenantId);
if (userRealm != null && userRealm.getAuthorizationManager() != null) {
return userRealm.getAuthorizationManager()
@ -241,6 +208,10 @@ public class DeviceAccessAuthorizationServiceImpl implements DeviceAccessAuthori
CarbonConstants.UI_PERMISSION_ACTION);
}
return false;
} catch (UserStoreException e) {
throw new DeviceAccessAuthorizationException("Unable to authorize the access for the user : " +
username, e);
}
}
private String getUserName() {

@ -0,0 +1,173 @@
/*
* Copyright (c) 2018 - 2024, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. 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 io.entgra.device.mgt.core.device.mgt.core.authorization;
import io.entgra.device.mgt.core.device.mgt.common.authorization.GroupAccessAuthorizationException;
import io.entgra.device.mgt.core.device.mgt.common.authorization.GroupAccessAuthorizationService;
import io.entgra.device.mgt.core.device.mgt.common.authorization.GroupAuthorizationResult;
import io.entgra.device.mgt.core.device.mgt.common.group.mgt.DeviceGroup;
import io.entgra.device.mgt.core.device.mgt.common.group.mgt.GroupManagementException;
import io.entgra.device.mgt.core.device.mgt.common.permission.mgt.Permission;
import io.entgra.device.mgt.core.device.mgt.common.permission.mgt.PermissionManagementException;
import io.entgra.device.mgt.core.device.mgt.core.internal.DeviceManagementDataHolder;
import io.entgra.device.mgt.core.device.mgt.core.permission.mgt.PermissionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.opensaml.xmlsec.signature.G;
import org.wso2.carbon.CarbonConstants;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.user.api.UserRealm;
import org.wso2.carbon.user.api.UserStoreException;
import javax.persistence.criteria.CriteriaBuilder;
import java.util.List;
public class GroupAccessAuthorizationServiceImpl implements GroupAccessAuthorizationService {
private final static String GROUP_ADMIN_PERMISSION = "/device-mgt/devices/any-group/permitted-actions-under-owning-group";
private final static String GROUP_ADMIN = "Group Management Administrator";
private static Log log = LogFactory.getLog(DeviceAccessAuthorizationServiceImpl.class);
public GroupAccessAuthorizationServiceImpl() {
try {
this.addAdminPermissionToRegistry();
} catch (PermissionManagementException e) {
log.error("Unable to add the group-admin permission to the registry.", e);
}
}
@Override
public boolean isUserAuthorized(int groupId, String username, String[] groupPermissions)
throws GroupAccessAuthorizationException {
int tenantId = this.getTenantId();
if (username == null || username.isEmpty()) {
username = this.getUserName();
}
//check for admin and ownership permissions
if (isGroupAdminUser(username, tenantId) || isGroupOwner(groupId, username)) {
return true;
}
//check for group permissions
if (groupPermissions == null || groupPermissions.length == 0) {
return false;
} else {
// if group permissions specified, check whether that permission is available in any user role of the group owner
try {
UserRealm userRealm = DeviceManagementDataHolder.getInstance().getRealmService()
.getTenantUserRealm(getTenantId());
String[] userRoles = userRealm.getUserStoreManager().getRoleListOfUser(username);
boolean isAuthorized = true;
for (String groupPermission : groupPermissions) {
for (String role : userRoles) {
if (!userRealm.getAuthorizationManager().
isRoleAuthorized(role, groupPermission, CarbonConstants.UI_PERMISSION_ACTION)) {
isAuthorized = false;
break;
}
}
}
return isAuthorized;
} catch (UserStoreException e) {
throw new GroupAccessAuthorizationException("Unable to authorize the access to group : " +
groupId + " for the user : " +
username, e);
}
}
}
@Override
public GroupAuthorizationResult isUserAuthorized(List<Integer> groupIds, String username, String[] groupPermission)
throws GroupAccessAuthorizationException {
GroupAuthorizationResult result = new GroupAuthorizationResult();
for (Integer groupId : groupIds) {
if (isUserAuthorized(groupId, username, groupPermission)) {
result.addAuthorizedGroupId(groupId);
} else {
result.addUnauthorizedGroupId(groupId);
}
}
return result;
}
@Override
public boolean isUserAuthorized(int groupId, String[] groupPermissions)
throws GroupAccessAuthorizationException {
return isUserAuthorized(groupId, this.getUserName(), groupPermissions);
}
private boolean isGroupOwner(int groupId, String username)
throws GroupAccessAuthorizationException {
//Check for group ownership. If the user is the owner of the group we allow the access.
try {
DeviceGroup group = DeviceManagementDataHolder.getInstance().
getGroupManagementProviderService().getGroup(groupId, false);
return username.equals(group.getOwner());
} catch (GroupManagementException e) {
throw new GroupAccessAuthorizationException("Unable to authorize the access to group : " +
groupId + " for the user : " +
username, e);
}
}
private boolean isGroupAdminUser(String username, int tenantId) throws GroupAccessAuthorizationException {
try {
UserRealm userRealm = DeviceManagementDataHolder.getInstance().getRealmService().getTenantUserRealm(tenantId);
if (userRealm != null && userRealm.getAuthorizationManager() != null) {
return userRealm.getAuthorizationManager()
.isUserAuthorized(removeTenantDomain(username),
PermissionUtils.getAbsolutePermissionPath(GROUP_ADMIN_PERMISSION),
CarbonConstants.UI_PERMISSION_ACTION);
}
return false;
} catch (UserStoreException e) {
throw new GroupAccessAuthorizationException("Unable to authorize the access for the user : " +
username, e);
}
}
private String getUserName() {
String username = CarbonContext.getThreadLocalCarbonContext().getUsername();
if (username != null && !username.isEmpty()) {
return removeTenantDomain(username);
}
return null;
}
private String removeTenantDomain(String username) {
String tenantDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain();
if (username.endsWith(tenantDomain)) {
return username.substring(0, username.lastIndexOf("@"));
}
return username;
}
private int getTenantId() {
return CarbonContext.getThreadLocalCarbonContext().getTenantId();
}
private boolean addAdminPermissionToRegistry() throws PermissionManagementException {
Permission permission = new Permission();
permission.setName(GROUP_ADMIN);
permission.setPath(PermissionUtils.getAbsolutePermissionPath(GROUP_ADMIN_PERMISSION));
return PermissionUtils.putPermission(permission);
}
}

@ -18,6 +18,7 @@
package io.entgra.device.mgt.core.device.mgt.core.device.details.mgt.impl;
import io.entgra.device.mgt.core.device.mgt.core.permission.mgt.PermissionManagerServiceImpl;
import io.entgra.device.mgt.core.device.mgt.core.report.mgt.ReportingPublisherManager;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
@ -260,10 +261,12 @@ public class DeviceInformationManagerImpl implements DeviceInformationManager {
String username = CarbonContext.getThreadLocalCarbonContext().getUsername();
if (StringUtils.isEmpty(username)) {
String requiredPermission = PermissionManagerServiceImpl.getInstance().getRequiredPermission();
String[] requiredPermissions = new String[] {requiredPermission};
boolean isUserAuthorized = DeviceManagementDataHolder.getInstance().
getDeviceAccessAuthorizationService().isUserAuthorized(
new DeviceIdentifier(device.getDeviceIdentifier(), device.getType()),
device.getEnrolmentInfo().getOwner()
device.getEnrolmentInfo().getOwner(), requiredPermissions
);
if (isUserAuthorized) {
username = device.getEnrolmentInfo().getOwner();

@ -20,6 +20,7 @@ package io.entgra.device.mgt.core.device.mgt.core.internal;
import io.entgra.device.mgt.core.apimgt.extension.rest.api.APIApplicationServices;
import io.entgra.device.mgt.core.apimgt.extension.rest.api.PublisherRESTAPIServices;
import io.entgra.device.mgt.core.device.mgt.common.authorization.GroupAccessAuthorizationService;
import io.entgra.device.mgt.core.device.mgt.common.metadata.mgt.DeviceStatusManagementService;
import io.entgra.device.mgt.core.server.bootup.heartbeat.beacon.service.HeartBeatManagementService;
import org.wso2.carbon.context.PrivilegedCarbonContext;
@ -78,6 +79,7 @@ public class DeviceManagementDataHolder {
private ConfigurationContextService configurationContextService;
private final HashMap<String, Boolean> requireDeviceAuthorization = new HashMap<>();
private DeviceAccessAuthorizationService deviceAccessAuthorizationService;
private GroupAccessAuthorizationService groupAccessAuthorizationService;
private GroupManagementProviderService groupManagementProviderService;
private TaskService taskService;
private EmailSenderService emailSenderService;
@ -447,4 +449,12 @@ public class DeviceManagementDataHolder {
public void setPublisherRESTAPIServices(PublisherRESTAPIServices publisherRESTAPIServices) {
this.publisherRESTAPIServices = publisherRESTAPIServices;
}
public GroupAccessAuthorizationService getGroupAccessAuthorizationService() {
return groupAccessAuthorizationService;
}
public void setGroupAccessAuthorizationService(GroupAccessAuthorizationService groupAccessAuthorizationService) {
this.groupAccessAuthorizationService = groupAccessAuthorizationService;
}
}

@ -17,7 +17,9 @@
*/
package io.entgra.device.mgt.core.device.mgt.core.internal;
import io.entgra.device.mgt.core.device.mgt.common.authorization.GroupAccessAuthorizationService;
import io.entgra.device.mgt.core.device.mgt.common.metadata.mgt.DeviceStatusManagementService;
import io.entgra.device.mgt.core.device.mgt.core.authorization.GroupAccessAuthorizationServiceImpl;
import io.entgra.device.mgt.core.device.mgt.core.metadata.mgt.DeviceStatusManagementServiceImpl;
import io.entgra.device.mgt.core.server.bootup.heartbeat.beacon.service.HeartBeatManagementService;
import org.apache.commons.logging.Log;
@ -353,6 +355,12 @@ public class DeviceManagementServiceComponent {
bundleContext.registerService(DeviceAccessAuthorizationService.class.getName(),
deviceAccessAuthorizationService, null);
/* Registering GroupAccessAuthorization Service */
GroupAccessAuthorizationService groupAccessAuthorizationService = new GroupAccessAuthorizationServiceImpl();
DeviceManagementDataHolder.getInstance().setGroupAccessAuthorizationService(groupAccessAuthorizationService);
bundleContext.registerService(GroupAccessAuthorizationService.class.getName(),
groupAccessAuthorizationService, null);
/* Registering Geo Service */
GeoLocationProviderService geoService = new GeoLocationProviderServiceImpl();
DeviceManagementDataHolder.getInstance().setGeoLocationProviderService(geoService);

@ -19,6 +19,7 @@
package io.entgra.device.mgt.core.device.mgt.core.operation.mgt;
import com.google.gson.Gson;
import io.entgra.device.mgt.core.device.mgt.core.permission.mgt.PermissionManagerServiceImpl;
import io.entgra.device.mgt.core.device.mgt.extensions.logger.spi.EntgraLogger;
import io.entgra.device.mgt.core.notification.logger.DeviceConnectivityLogContext;
import io.entgra.device.mgt.core.notification.logger.impl.EntgraDeviceConnectivityLoggerImpl;
@ -561,9 +562,11 @@ public class OperationManagerImpl implements OperationManager {
} else {
boolean isAuthorized;
authorizedDeviceList = new ArrayList<>();
String requiredPermission = PermissionManagerServiceImpl.getInstance().getRequiredPermission();
String[] requiredPermissions = new String[] {requiredPermission};
for (DeviceIdentifier devId : deviceIds) {
isAuthorized = DeviceManagementDataHolder.getInstance().getDeviceAccessAuthorizationService().
isUserAuthorized(devId);
isUserAuthorized(devId, requiredPermissions);
if (isAuthorized) {
authorizedDeviceList.add(devId);
} else {
@ -1470,9 +1473,11 @@ public class OperationManagerImpl implements OperationManager {
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
String user = this.getUser();
boolean isUserAuthorized;
String requiredPermission = PermissionManagerServiceImpl.getInstance().getRequiredPermission();
String[] requiredPermissions = new String[] {requiredPermission};
try {
isUserAuthorized = DeviceManagementDataHolder.getInstance()
.getDeviceAccessAuthorizationService().isUserAuthorized(deviceId, user);
.getDeviceAccessAuthorizationService().isUserAuthorized(deviceId, user, requiredPermissions);
} catch (DeviceAccessAuthorizationException e) {
throw new OperationManagementException("Error occurred while checking the device access permissions for '" +
deviceId.getType() + "' device carrying the identifier '" +

@ -32,6 +32,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerService {
private static PermissionManagerServiceImpl registryBasedPermissionManager;
private static APIResourcePermissions apiResourcePermissions;
private ThreadLocal<String> requiredPermission = null;
private PermissionManagerServiceImpl() {
}
@ -64,4 +65,16 @@ public class PermissionManagerServiceImpl implements PermissionManagerService {
public List<Permission> getPermission(String context) throws PermissionManagementException {
return apiResourcePermissions.getPermissions(context);
}
public String getRequiredPermission() {
if (requiredPermission == null) {
requiredPermission = new ThreadLocal<>();
}
return requiredPermission.get();
}
public void setRequiredPermission(String permission) {
requiredPermission = new ThreadLocal<>();
requiredPermission.set(permission);
}
}

@ -32,6 +32,7 @@ import io.entgra.device.mgt.core.device.mgt.core.dao.DeviceManagementDAOFactory;
import io.entgra.device.mgt.core.device.mgt.core.dao.GroupDAO;
import io.entgra.device.mgt.core.device.mgt.core.dao.GroupManagementDAOException;
import io.entgra.device.mgt.core.device.mgt.core.dao.GroupManagementDAOFactory;
import io.entgra.device.mgt.core.device.mgt.core.permission.mgt.PermissionManagerServiceImpl;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@ -593,11 +594,25 @@ public class GroupManagementProviderServiceImpl implements GroupManagementProvid
} else {
List<Integer> allDeviceGroupIdsOfUser = getGroupIds(username);
rootGroups = this.getGroups(allDeviceGroupIdsOfUser, tenantId);
if (requireGroupProps) {
try {
GroupManagementDAOFactory.openConnection();
for (DeviceGroup rootGroup : rootGroups) {
parentPath = DeviceManagerUtil.createParentPath(rootGroup);
childrenGroups = groupDAO.getChildrenGroups(parentPath, tenantId);
createGroupWithChildren(
rootGroup, childrenGroups, requireGroupProps, tenantId, request.getDepth(), 0);
if (requireGroupProps) {
populateGroupProperties(rootGroup, tenantId);
}
}
} catch (SQLException e) {
String msg = "Error occurred while opening a connection to the data source to retrieve all groups "
+ "with hierarchy when username is provided";
log.error(msg, e);
throw new GroupManagementException(msg, e);
} finally {
GroupManagementDAOFactory.closeConnection();
}
}
} catch (GroupManagementDAOException e) {
String msg = "Error occurred while retrieving all groups with hierarchy";

@ -193,7 +193,7 @@ public class DeviceAccessAuthorizationServiceTest {
public void userAuthDevIdUserName() throws Exception {
PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(ADMIN_USER);
for (DeviceIdentifier deviceId : deviceIds) {
Assert.assertTrue(deviceAccessAuthorizationService.isUserAuthorized(deviceId, ADMIN_USER),
Assert.assertTrue(deviceAccessAuthorizationService.isUserAuthorized(deviceId, ADMIN_USER, new String[]{NON_ADMIN_PERMISSION}),
"Device access authorization for admin user failed");
}
}
@ -202,7 +202,7 @@ public class DeviceAccessAuthorizationServiceTest {
public void userAuthDevIdUserNameResult() throws DeviceAccessAuthorizationException {
PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(ADMIN_USER);
DeviceAuthorizationResult deviceAuthorizationResult = deviceAccessAuthorizationService.
isUserAuthorized(deviceIds, ADMIN_USER);
isUserAuthorized(deviceIds, ADMIN_USER, new String[]{NON_ADMIN_PERMISSION});
Assert.assertEquals(deviceAuthorizationResult.getAuthorizedDevices().size(), 5,
"Expected 5 authorized devices for admin user");
Assert.assertEquals(deviceAuthorizationResult.getUnauthorizedDevices().size(), 0,
@ -213,7 +213,7 @@ public class DeviceAccessAuthorizationServiceTest {
public void userAuthDevId() throws Exception {
PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(ADMIN_USER);
for (DeviceIdentifier deviceId : deviceIds) {
Assert.assertTrue(deviceAccessAuthorizationService.isUserAuthorized(deviceId),
Assert.assertTrue(deviceAccessAuthorizationService.isUserAuthorized(deviceId, new String[]{NON_ADMIN_PERMISSION}),
"Authorize user from device identifier failed");
}
}
@ -222,7 +222,7 @@ public class DeviceAccessAuthorizationServiceTest {
public void userAuthDevIdResult() throws Exception {
PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(ADMIN_USER);
DeviceAuthorizationResult deviceAuthorizationResult = deviceAccessAuthorizationService.
isUserAuthorized(deviceIds);
isUserAuthorized(deviceIds, new String[]{NON_ADMIN_PERMISSION});
Assert.assertEquals(deviceAuthorizationResult.getAuthorizedDevices().size(), 5,
"Expected 5 authorized devices for admin user");
Assert.assertEquals(deviceAuthorizationResult.getUnauthorizedDevices().size(), 0,

@ -134,6 +134,7 @@ public class PermissionAuthorizer {
}
if (isUserAuthorized) {
PermissionManagerServiceImpl.getInstance().setRequiredPermission(requiredPermission);
return WebappAuthenticator.Status.SUCCESS;
} else {
return WebappAuthenticator.Status.FAILURE;

Loading…
Cancel
Save