/// <summary> /// Validates whether the employee has enough permission to execute the requested operation. /// </summary> /// <param name="context">The request context.</param> /// <param name="retailOperation">The retail operation.</param> /// <param name="employee">The employee.</param> private static void ValidateEmployeePermissionForOperation(RequestContext context, RetailOperation retailOperation, Employee employee) { // If the request is for logon with specific operation, check if the employee can execute requested operation. if (retailOperation != RetailOperation.None && !employee.Permissions.HasManagerPrivileges) { if (context.GetPrincipal().IsChannelAgnostic) { throw new UserAuthorizationException( SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_AuthorizationFailed, "Operation are only allowed when CommercePrincipal has a channel defined."); } GetOperationPermissionsDataRequest dataRequest = new GetOperationPermissionsDataRequest( retailOperation, QueryResultSettings.SingleRecord); OperationPermission operationPermission = context.Execute <EntityDataServiceResponse <OperationPermission> >(dataRequest) .PagedEntityCollection.FirstOrDefault(); if (operationPermission == null) { throw new UserAuthorizationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_AuthorizationFailed, "The user does not have permissions to execute the operation requested."); } // Check if principal has all required permissions for the Operation or have manager privilege. foreach (string permission in operationPermission.Permissions) { if (!employee.Permissions.Roles.Contains(permission) && !employee.Permissions.HasManagerPrivileges) { throw new UserAuthorizationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_AuthorizationFailed, "The user does not have permissions to execute the operation requested."); } } } }
/// <summary> /// Gets Operation Permissions for the operation. /// </summary> /// <param name="request">The data service request.</param> /// <returns>The data service response.</returns> private EntityDataServiceResponse <OperationPermission> GetOperationPermissions(GetOperationPermissionsDataRequest request) { EmployeeDataManager dataManager = this.GetDataManagerInstance(request.RequestContext); var result = dataManager.GetOperationPermissions(request.OperationId, request.QueryResultSettings); return(new EntityDataServiceResponse <OperationPermission>(result)); }
/// <summary> /// Checks if the principal has permission to do the operation. If not, throws UserAuthorizationException. /// </summary> /// <param name="principal">The request.</param> /// <param name="operationId">Operation Id.</param> /// <param name="context">Request Context.</param> /// <param name="allowedRoles">Allowed roles.</param> /// <param name="deviceTokenRequired">Device token required.</param> /// <param name="nonDrawerOperationCheckRequired">Is non-drawer mode operation check required.</param> public static void CheckAccess(ICommercePrincipal principal, RetailOperation operationId, RequestContext context, string[] allowedRoles, bool deviceTokenRequired, bool nonDrawerOperationCheckRequired) { if (principal == null) { throw new UserAuthorizationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_AuthorizationFailed, @"Invalid principal."); } if (context == null) { throw new UserAuthorizationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_AuthorizationFailed, @"Invalid context."); } // Access check not enabled for storefront operations. if (principal.IsInRole(CommerceRoles.Storefront)) { return; } // Check device token for Employee role. if (principal.IsInRole(CommerceRoles.Employee) && deviceTokenRequired) { if (string.IsNullOrEmpty(principal.DeviceToken)) { throw new DeviceAuthenticationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_DeviceTokenNotPresent, @"Device token was expected, but not provided."); } } bool isAnonymousUser = principal.IsInRole(CommerceRoles.Anonymous); // Check if the principal is one of the allowed roles. if (allowedRoles != null) { bool allowedRole = false; foreach (string role in allowedRoles) { if (principal.IsInRole(role)) { allowedRole = true; break; } } // If the user is not in the allowed roles, throw unauthorized exception. if (!allowedRole) { if (isAnonymousUser) { // this means that if the user authenticates with the system and retry the request // s(he) might get a different result (user authentication maps to HTTP 401 whereas Authorization maps to HTTP 403) throw new UserAuthenticationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_AuthenticationFailed, @"Assigned role is not allowed to perform this operation."); } else { throw new UserAuthorizationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_AuthorizationFailed, @"Assigned role is not allowed to perform this operation."); } } } // Access check for Anonymous principal. if (isAnonymousUser) { if (operationId != RetailOperation.None) { GetOperationPermissionsDataRequest dataRequest = new GetOperationPermissionsDataRequest(operationId, QueryResultSettings.SingleRecord); OperationPermission operationPermission = context.Execute <EntityDataServiceResponse <OperationPermission> >(dataRequest).PagedEntityCollection.FirstOrDefault(); if (operationPermission == null) { throw new UserAuthenticationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_AuthorizationFailed, @"Access denied for employee to perform this operation."); } if (!operationPermission.AllowAnonymousAccess) { throw new UserAuthenticationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_AuthorizationFailed, @"Access denied to perform this operation."); } } } // Access check for authenticated customer. if (principal.IsInRole(CommerceRoles.Customer)) { if (operationId != RetailOperation.None) { GetOperationPermissionsDataRequest dataRequest = new GetOperationPermissionsDataRequest(operationId, QueryResultSettings.SingleRecord); OperationPermission operationPermission = context.Execute <EntityDataServiceResponse <OperationPermission> >(dataRequest).PagedEntityCollection.FirstOrDefault(); if (operationPermission == null) { throw new UserAuthorizationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_AuthorizationFailed, @"Access denied to perform this operation."); } if (!operationPermission.AllowCustomerAccess) { throw new UserAuthorizationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_AuthorizationFailed, @"Access denied to perform this operation."); } if (!string.IsNullOrWhiteSpace(operationPermission.PermissionsStringV2)) { if (!principal.IsInRole(operationPermission.PermissionsStringV2.ToUpperInvariant())) { throw new UserAuthorizationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_AuthorizationFailed, @"Access denied for employee to perform this operation (permissions)."); } } } } // Access check for Staff principal. if (principal.IsInRole(CommerceRoles.Employee)) { // Validates the non drawer operation permission. if (nonDrawerOperationCheckRequired) { CheckNonDrawerOperationPermission(operationId, context); } // If the principal has Manager privilege, always allow operation. if (IsManager(principal) && principal.ElevatedOperation == (int)RetailOperation.None) { return; } // Only employees users have access to the retail operation specified in the attribute. if (operationId != RetailOperation.None) { GetOperationPermissionsDataRequest dataRequest = new GetOperationPermissionsDataRequest(operationId, QueryResultSettings.SingleRecord); OperationPermission operationPermission = context.Execute <EntityDataServiceResponse <OperationPermission> >(dataRequest).PagedEntityCollection.FirstOrDefault(); if (operationPermission == null) { if (operationId == RetailOperation.ActivateDevice) { throw new UserAuthorizationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_NoDeviceManagementPermission, "Access denied for employee to perform device activation operation."); } throw new UserAuthorizationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_AuthorizationFailed, "Access denied for employee to perform this operation."); } // If CheckUserAccess flag is not enabled, return. if (operationPermission.CheckUserAccess == false) { return; } // Enumerate the permissions for the operation and ensure user have access. foreach (string permission in operationPermission.Permissions) { if (!principal.IsInRole(permission.ToUpperInvariant())) { if (operationId == RetailOperation.ActivateDevice) { throw new UserAuthorizationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_NoDeviceManagementPermission, "Access denied for employee to perform device activation operation."); } if (string.IsNullOrWhiteSpace(principal.OriginalUserId)) { throw new UserAuthorizationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_AuthorizationFailed, "Access denied for employee to perform this operation (permissions)."); } // Checkin for elevated operation only the if the user is not already in role. CheckUserIsElevatedForOperation(principal, operationId); } } } } }