Beispiel #1
0
            /// <summary>
            /// Lock the current user, so that same user can't log into another terminal until log off from the current terminal.
            /// </summary>
            /// <param name="request">The data service request.</param>
            /// <returns>The data service response.</returns>
            private SingleEntityDataServiceResponse <bool> LockUserAtLogOn(LockUserAtLogOnDataRequest request)
            {
                const bool AllowMultipleTerminalSessions = false;

                bool isAccessAllowed;
                EmployeeL2CacheDataStoreAccessor cacheAccessor = GetCacheAccessor(request.RequestContext);

                if (!cacheAccessor.LockUserAtLogOn(request.TerminalId, request.StaffId, out isAccessAllowed))
                {
                    CreateEmployeeSessionDataResponse response = this.CreateEmployeeSession(
                        request.RequestContext,
                        AllowMultipleTerminalSessions,
                        request.ChannelId,
                        request.TerminalId,
                        request.StaffId,
                        request.DataAreaId);

                    // access is allowed if there is no previous existing session
                    isAccessAllowed = string.IsNullOrWhiteSpace(response.ExistingSessionTerminalId);

                    if (isAccessAllowed)
                    {
                        // only cache if user is allowed
                        // if user is blocked, we want to always keep performing the check to avoid
                        // blocking the user during the cache expiration period
                        cacheAccessor.CacheLockUserAtLogOn(request.TerminalId, request.StaffId, isAccessAllowed);
                    }
                }

                return(new SingleEntityDataServiceResponse <bool>(isAccessAllowed));
            }
            /// <summary>
            /// Logon the user on local store.
            /// </summary>
            /// <param name="request">The device activation request.</param>
            /// <param name="channelConfiguration">The channel configuration.</param>
            /// <returns>The device activation response.</returns>
            private static Employee EmployeeLogOnStore(StaffLogOnRealtimeRequest request, ChannelConfiguration channelConfiguration)
            {
                if (request == null)
                {
                    throw new ArgumentNullException("request");
                }

                Employee employee = null, localEmployee = null;
                string   passwordHash = string.Empty;
                string   staffId      = request.StaffId;

                if (request.ChannelId.HasValue && request.RequestContext.GetPrincipal().ChannelId == request.ChannelId.Value)
                {
                    // Get employee salt and password hash algorithm.
                    GetEmployeePasswordCryptoInfoDataRequest employeePasswordCryptoInfoRequest = new GetEmployeePasswordCryptoInfoDataRequest(request.ChannelId.GetValueOrDefault(), staffId);
                    var    passwordCryptoInfo = request.RequestContext.Execute <SingleEntityDataServiceResponse <EmployeePasswordCryptoInfo> >(employeePasswordCryptoInfoRequest).Entity;
                    string salt = passwordCryptoInfo.PasswordSalt ?? string.Empty;
                    string passwordHashAlgorithm = passwordCryptoInfo.PasswordHashAlgorithm;

                    if (!string.IsNullOrEmpty(request.StaffPassword))
                    {
                        if (string.IsNullOrEmpty(passwordHashAlgorithm))
                        {
                            // get hash algorithm from the transaction service profile.
                            var getTransactionServiceProfileDataRequest         = new GetTransactionServiceProfileDataRequest();
                            TransactionServiceProfile transactionServiceProfile = request.RequestContext.Execute <SingleEntityDataServiceResponse <TransactionServiceProfile> >(
                                getTransactionServiceProfileDataRequest).Entity;
                            passwordHashAlgorithm = transactionServiceProfile.StaffPasswordHash;
                        }

                        HashDataServiceRequest hashDataServiceRequest = new HashDataServiceRequest(request.StaffPassword, passwordHashAlgorithm, staffId, salt);
                        passwordHash = request.RequestContext.Execute <HashDataServiceResponse>(hashDataServiceRequest).Data;
                    }

                    // Logon to the store
                    EmployeeLogOnStoreDataRequest dataRequest = new EmployeeLogOnStoreDataRequest(
                        request.ChannelId.Value,
                        staffId,
                        passwordHash,
                        new ColumnSet());

                    localEmployee = request.RequestContext.Execute <SingleEntityDataServiceResponse <Employee> >(dataRequest).Entity;
                    if (localEmployee == null || localEmployee.Permissions == null)
                    {
                        throw new UserAuthenticationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_AuthenticationFailed);
                    }

                    // Return new object for the logged-on employee with only the required fields to ensure not returning any sensitive data.
                    employee               = new Employee();
                    employee.Permissions   = new EmployeePermissions();
                    employee.Name          = localEmployee.Name;
                    employee.StaffId       = localEmployee.StaffId;
                    employee.NameOnReceipt = localEmployee.NameOnReceipt;
                    employee.Permissions   = localEmployee.Permissions;
                    employee.Images        = localEmployee.Images;
                    employee.PasswordLastChangedDateTime = localEmployee.PasswordLastChangedDateTime;

                    // Lock the user if multiple logins are not allowed.
                    if (!employee.Permissions.AllowMultipleLogins && channelConfiguration != null)
                    {
                        LockUserAtLogOnDataRequest lockDataRequest = new LockUserAtLogOnDataRequest(
                            request.ChannelId.Value,
                            request.RequestContext.GetTerminal().TerminalId,
                            staffId,
                            channelConfiguration.InventLocationDataAreaId);
                        bool locked = request.RequestContext.Execute <SingleEntityDataServiceResponse <bool> >(lockDataRequest).Entity;
                        if (!locked)
                        {
                            throw new UserAuthenticationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_UserLogonAnotherTerminal);
                        }
                    }
                }
                else
                {
                    RequestContext getEmployeeRequestContext;

                    // Employee record is associated with channel
                    // Decide what context is to be used to retrieve it
                    if (request.RequestContext.GetPrincipal().IsChannelAgnostic)
                    {
                        // If the context is channel agnostic (no channel information), then use current (first published channel in this case)
                        GetChannelIdServiceRequest  getChannelRequest  = new GetChannelIdServiceRequest();
                        GetChannelIdServiceResponse getChannelResponse = request.RequestContext.Execute <GetChannelIdServiceResponse>(getChannelRequest);

                        var anonymousIdentity = new CommerceIdentity()
                        {
                            ChannelId = getChannelResponse.ChannelId
                        };

                        getEmployeeRequestContext = new RequestContext(request.RequestContext.Runtime);
                        getEmployeeRequestContext.SetPrincipal(new CommercePrincipal(anonymousIdentity));
                    }
                    else
                    {
                        // If the request has channel information, then use current context
                        getEmployeeRequestContext = request.RequestContext;
                    }

                    GetEmployeeDataRequest dataRequest = new GetEmployeeDataRequest(staffId, QueryResultSettings.SingleRecord);
                    employee = getEmployeeRequestContext.Execute <SingleEntityDataServiceResponse <Employee> >(dataRequest).Entity;
                    if (employee == null)
                    {
                        string message = string.Format(CultureInfo.InvariantCulture, "The specified employee ({0}) was not found.", staffId);
                        throw new UserAuthenticationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_AuthenticationFailed, message);
                    }

                    ICommercePrincipal principal = request.RequestContext.GetPrincipal();
                    RequestContext     contextForOperationAuthorization;
                    if (principal.IsAnonymous)
                    {
                        // create an authenticated context that can be used for specific operation authorization
                        RequestContext   authenticatedContext = new RequestContext(request.RequestContext.Runtime);
                        CommerceIdentity identity             = new CommerceIdentity(
                            employee,
                            new Device()
                        {
                            DeviceNumber     = principal.DeviceNumber,
                            Token            = principal.DeviceToken,
                            ChannelId        = principal.ChannelId,
                            TerminalRecordId = principal.TerminalId
                        });
                        authenticatedContext.SetPrincipal(new CommercePrincipal(identity));

                        contextForOperationAuthorization = authenticatedContext;
                    }
                    else
                    {
                        contextForOperationAuthorization = request.RequestContext;
                    }

                    GetEmployeePermissionsDataRequest permissionsDataRequest = new GetEmployeePermissionsDataRequest(staffId, new ColumnSet());
                    employee.Permissions = contextForOperationAuthorization.Execute <SingleEntityDataServiceResponse <EmployeePermissions> >(permissionsDataRequest).Entity;
                }

                return(employee);
            }