Exemplo n.º 1
0
        /// <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);
                            }
                        }
                    }
                }
            }