/// <summary> /// Instantiates all permissions. This method is called at run=time. /// </summary> /// <param name="parameterCount">The number of parameters in the method, plus 1 for the <c>this</c> parameter.</param> /// <param name="semantics">The set of semantics for which permissions are initialized.</param> internal void InitializePermissions(int parameterCount, OperationSemantic[] semantics) { _hasPermissionForParameter = new BitArray(parameterCount); _permissions = new OperationPermission <IPermission> [_permissionFactories.Count * semantics.Length]; var i = 0; foreach (var permissionFactory in _permissionFactories) { foreach (var semantic in semantics) { _permissions[i] = new OperationPermission <IPermission>(semantic, permissionFactory.ParameterIndex, permissionFactory.Permission.CreatePermission(semantic)); _hasPermissionForParameter[permissionFactory.ParameterIndex] = true; i++; } } }
/// <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); } } } } }