/// <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);
                            }
                        }
                    }
                }
            }