/// <summary> /// Initializes the request context. /// </summary> /// <param name="request">The request.</param> /// <param name="context">The request context.</param> private static void InitializeRequestContext(Request request, RequestContext context) { ThrowIf.Null(context, "context"); ThrowIf.Null(request, "request"); if (context.IsInitialized) { return; } context.SetInitialized(); PopulateRequestContext(context); // We only want to authorize once per context initialization // Since principal cannot be changed on the context, any calls performed using same context // will be under the same user's principal ICommercePrincipal principal = context.GetPrincipal(); if (principal != null && principal.IsInRole(CommerceRoles.Employee)) { // Some requests must not be verified for an already opened session because they are required to // establish a session on the first place bool enforceSessionOpened = request.NeedSessionOpened; // Authorizes the staff request context.Runtime.Execute <StaffAuthorizationServiceResponse>(new StaffAuthorizationServiceRequest(enforceSessionOpened), context, skipRequestTriggers: true); } }
/// <summary> /// Method to check if the principal has manager permission. /// </summary> /// <param name="principal">Commerce Principal.</param> /// <returns>True or False.</returns> private static bool IsManager(ICommercePrincipal principal) { if (principal == null) { throw new UserAuthorizationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_AuthorizationFailed, @"Invalid principal."); } return(principal.IsInRole(ManagerPrivilege)); }
/// <summary> /// Method to check if the principal has a shift. /// </summary> /// <param name="principal">Commerce Principal.</param> public static void CheckAccessHasShift(ICommercePrincipal principal) { if (principal == null) { throw new UserAuthorizationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_AuthorizationFailed, @"Invalid principal."); } // Access check not enabled for storefront operations. if (principal.IsInRole(CommerceRoles.Storefront)) { return; } if (principal.ShiftId == 0) { throw new UserAuthorizationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_NonDrawerOperationsOnly, "Shift is not open."); } }
/// <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); } } } } }