/// <summary>
            /// Authorizes the retail staff.
            /// </summary>
            /// <param name="staffAuthorizationRequest">The retail staff authorization request.</param>
            /// <returns>The service response.</returns>
            private static Response AuthorizeStaff(StaffAuthorizationServiceRequest staffAuthorizationRequest)
            {
                RequestContext     context       = staffAuthorizationRequest.RequestContext;
                ICommercePrincipal principal     = context.GetPrincipal();
                string             staffId       = string.IsNullOrWhiteSpace(staffAuthorizationRequest.StaffId) ? principal.UserId : staffAuthorizationRequest.StaffId;
                long?           channelId        = principal.IsChannelAgnostic ? null : (long?)principal.ChannelId;
                long?           terminalRecordId = principal.IsTerminalAgnostic ? null : (long?)principal.TerminalId;
                RetailOperation operation        = staffAuthorizationRequest.RetailOperation;
                Employee        employee;

                if (string.IsNullOrWhiteSpace(staffId))
                {
                    throw new UserAuthorizationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_AuthorizationFailed, "UserId is missing from principal.");
                }

                if (channelId.HasValue && !principal.IsTerminalAgnostic && !terminalRecordId.HasValue)
                {
                    throw new UserAuthorizationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_AuthorizationFailed, "When channel identififer is provided on principal, terminal record identfier must also be.");
                }

                StaffRealTimeSecurityValidationHelper staffSecurityHelper = StaffRealTimeSecurityValidationHelper.Create(
                    context,
                    SecurityVerificationType.Authorization,
                    staffId,
                    channelId,
                    terminalRecordId,
                    password: string.Empty);

                // we can only check values against database if the principal is bound to a channel
                if (!principal.IsChannelAgnostic)
                {
                    VerifyThatOrgUnitIsPublished(context, channelId.Value);
                }

                // for authorization, we always want to go to local DB, we only go to headquarters if we don't have a channel
                // to access the DB
                LogOnConfiguration logOnConfiguration = principal.IsChannelAgnostic
                    ? LogOnConfiguration.RealTimeService
                    : LogOnConfiguration.LocalDatabase;

                // authorize employee based on configuration
                employee = ExecuteWorkWithLocalFallback(
                    logOnConfiguration,
                    staffSecurityHelper,
                    () =>
                {
                    return(AuthorizeEmployeeLocalDatabase(context, staffSecurityHelper.StaffId, staffAuthorizationRequest.EnforceSessionToBeOpened));
                });

                // Validates whether the staff can perform the requested operation
                ValidateEmployeePermissionForOperation(context, operation, employee);

                return(new StaffAuthorizationServiceResponse(employee));
            }
            /// <summary>
            /// Executes the workflow to get the currently logged in employee.
            /// </summary>
            /// <param name="request">The request.</param>
            /// <returns>The response.</returns>
            protected override GetCurrentEmployeeResponse Process(GetCurrentEmployeeRequest request)
            {
                ThrowIf.Null(request, "request");

                // authorize employee will return employee and all permissions
                var staffRequest = new StaffAuthorizationServiceRequest(
                    request.RequestContext.Runtime.CurrentPrincipal.UserId,
                    RetailOperation.None);
                var response = this.Context.Execute <StaffAuthorizationServiceResponse>(staffRequest);

                // get the full employee object from the database.
                Employee employee = response.Employee;

                if (employee != null && !string.IsNullOrWhiteSpace(employee.StaffId))
                {
                    var employeePermission = employee.Permissions;

                    QueryResultSettings        settings        = new QueryResultSettings(new PagingInfo(top: 1));
                    GetEmployeesServiceRequest employeeRequest = new GetEmployeesServiceRequest(employee.StaffId, settings);
                    var employeeResponse = this.Context.Execute <GetEmployeesServiceResponse>(employeeRequest);

                    if (employeeResponse != null)
                    {
                        employee = employeeResponse.Employees.SingleOrDefault();

                        // Set the employee permission as persisted during staff authorization call.
                        employee.Permissions = employeePermission;
                    }

                    // Set the number of days to password expiry on the employee.
                    int passwordExpiryIntervalInDays          = 0;
                    int passwordExpiryNotificationThreshold   = 0;
                    ChannelConfiguration channelConfiguration = this.Context.GetChannelConfiguration();

                    if (channelConfiguration != null)
                    {
                        passwordExpiryIntervalInDays        = channelConfiguration.PasswordExpiryIntervalInDays;
                        passwordExpiryNotificationThreshold = channelConfiguration.PasswordExpiryNotificationThresholdInDays;
                    }

                    employee.NumberOfDaysToPasswordExpiry = CalculateNumberOfDaysToPasswordExpiry(passwordExpiryIntervalInDays, passwordExpiryNotificationThreshold, employee.PasswordLastChangedDateTime);
                }

                return(new GetCurrentEmployeeResponse(employee));
            }
Exemple #3
0
            /// <summary>
            /// Authenticates and authorizes the user.
            /// </summary>
            /// <param name="request">UserAuthenticationRequest request object.</param>
            /// <param name="device">The device.</param>
            /// <returns>Employee object.</returns>
            internal static Employee AuthenticateAndAuthorizeUser(UserAuthenticationRequest request, Device device)
            {
                // Authenticate
                Employee       employee;
                string         staffId; // in extended authentication cases, this value might be empty
                RequestContext executionContext = request.RequestContext;

                if (device != null && request.RequestContext.GetPrincipal().IsChannelAgnostic)
                {
                    executionContext = CreateRequestContext(string.Empty, device, request.RequestContext.Runtime);
                }

                UserLogOnServiceRequest authenticateServiceRequest = new UserLogOnServiceRequest(
                    request.StaffId,
                    request.Password,
                    request.Credential,
                    request.GrantType,
                    request.AdditionalAuthenticationData);
                UserLogOnServiceResponse response = executionContext.Execute <UserLogOnServiceResponse>(authenticateServiceRequest);

                staffId = response.StaffId;

                // Authorize only if this was for elevate user
                if (request.RetailOperation != RetailOperation.None)
                {
                    var authorizeStaffRequest = new StaffAuthorizationServiceRequest(
                        request.RequestContext.GetPrincipal().UserId,
                        request.RetailOperation);

                    bool currentUserAlreadyAuthorizedForOperation = true;

                    try
                    {
                        executionContext.Execute <StaffAuthorizationServiceResponse>(authorizeStaffRequest);
                    }
                    catch (UserAuthorizationException authorizationException)
                    {
                        if (string.Equals(authorizationException.ErrorResourceId, SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_AuthorizationFailed.ToString(), StringComparison.Ordinal))
                        {
                            currentUserAlreadyAuthorizedForOperation = false;
                        }
                    }

                    if (currentUserAlreadyAuthorizedForOperation)
                    {
                        RetailLogger.Log.CrtWorkflowUserAuthenticationUserAlreadyHasAccessToTheTargetedOperation(request.RequestContext.GetPrincipal().UserId, request.RetailOperation.ToString());
                        throw new UserAuthorizationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_AuthorizationFailed, "The current user is already authorized to perform the targeted operation.");
                    }

                    authorizeStaffRequest = new StaffAuthorizationServiceRequest(
                        staffId,
                        request.RetailOperation);

                    StaffAuthorizationServiceResponse authorizationResponse =
                        executionContext.Execute <StaffAuthorizationServiceResponse>(authorizeStaffRequest);
                    employee = authorizationResponse.Employee;
                }
                else
                {
                    // The employee has already been authenticated above.
                    employee = new Employee()
                    {
                        StaffId = staffId
                    };

                    // if we created a new context, then we need to update it here with the staff id
                    executionContext = CreateRequestContext(staffId, device, request.RequestContext.Runtime);

                    // This is needed for offline scenarios/logon because as opposed to online/RS in CRT there is no user look up when the identity is presented on API calls.
                    GetEmployeePermissionsDataRequest permissionsDataRequest = new GetEmployeePermissionsDataRequest(staffId, new ColumnSet());
                    employee.Permissions = executionContext.Execute <SingleEntityDataServiceResponse <EmployeePermissions> >(permissionsDataRequest).Entity;
                }

                LogAuthenticationRequest(executionContext, employee.StaffId, AuthenticationStatus.Success, AuthenticationOperation.CreateToken);

                return(employee);
            }