예제 #1
0
            private static RequestContext CreateRequestContext(string staffId, Device device, ICommerceRuntime runtime)
            {
                CommerceIdentity identity;

                if (string.IsNullOrWhiteSpace(staffId))
                {
                    identity = new CommerceIdentity(device);
                    identity.Roles.Add(CommerceRoles.Anonymous);
                }
                else
                {
                    var employee = new Employee()
                    {
                        StaffId = staffId
                    };
                    identity = new CommerceIdentity(employee, device);
                }

                CommercePrincipal principal = new CommercePrincipal(identity);
                RequestContext    context   = new RequestContext(runtime);

                context.SetPrincipal(principal);

                return(context);
            }
            /// <summary>
            /// Retrieves the transaction service profile.
            /// </summary>
            /// <param name="context">The request context.</param>
            /// <returns>The transaction service profile.</returns>
            private static TransactionServiceProfile GetTransactionServiceProfile(Microsoft.Dynamics.Commerce.Runtime.RequestContext context)
            {
                GetTransactionServiceProfileDataRequest request = new GetTransactionServiceProfileDataRequest();

                Microsoft.Dynamics.Commerce.Runtime.RequestContext getTransactionServiceProfileRequestContext;

                // Transaction service profile is associated with channel
                // Decide what context is to be used to retrieve it
                if (context.GetPrincipal().IsChannelAgnostic)
                {
                    // If the context is channel agnostic (no channel information), then use any channel available to retrieve the profile
                    GetChannelIdServiceRequest  getChannelRequest  = new GetChannelIdServiceRequest();
                    GetChannelIdServiceResponse getChannelResponse = context.Execute <GetChannelIdServiceResponse>(getChannelRequest);
                    long anyChannelId = getChannelResponse.ChannelId;

                    var anonymousIdentity = new CommerceIdentity()
                    {
                        ChannelId = anyChannelId
                    };

                    getTransactionServiceProfileRequestContext = new Microsoft.Dynamics.Commerce.Runtime.RequestContext(context.Runtime);
                    getTransactionServiceProfileRequestContext.SetPrincipal(new CommercePrincipal(anonymousIdentity));
                }
                else
                {
                    // If the request has channel information, then use current context to retrieve the transaction service profile
                    getTransactionServiceProfileRequestContext = context;
                }

                return(getTransactionServiceProfileRequestContext.Execute <SingleEntityDataServiceResponse <TransactionServiceProfile> >(request).Entity);
            }
예제 #3
0
        /// <summary>
        /// Default constructor
        /// </summary>
        public DAXVersionRealTimeServiceController()
        {
            // Need to set the ChannelId explicitly
            this.CommerceIdentity           = User.Identity as CommerceIdentity;
            this.CommerceIdentity.ChannelId = 5637144662;

            TransactionServiceClient = new TransactionServiceClient(CommerceRuntimeManager.Runtime.CreateRequestContext(new RealtimeRequest()));
        }
            /// <summary>
            /// Gets the employee identity given the external identity.
            /// </summary>
            /// <param name="request">The device activation request.</param>
            /// <returns>The device activation response.</returns>
            private static Response GetEmployeeIdentityByExternalIdentity(GetEmployeeIdentityByExternalIdentityRealtimeRequest request)
            {
                TransactionService.TransactionServiceClient transactionService = new TransactionService.TransactionServiceClient(request.RequestContext);

                Employee employee = transactionService.GetRetailServerStaffByExternalIdentity(request.ExternalIdentityId, request.ExternalIdentitySubId);

                var employeeIdentity = new CommerceIdentity(employee, null);

                return(new GetEmployeeIdentityByExternalIdentityRealtimeResponse(employeeIdentity));
            }
            /// <summary>
            /// Executes the workflow to do user authentication.
            /// </summary>
            /// <param name="request">The request.</param>
            /// <returns>The response.</returns>
            protected override UserAuthenticationResponse Process(UserAuthenticationRequest request)
            {
                ThrowIf.Null(request, "request");
                Device           device = null;
                CommerceIdentity identity;
                Employee         employee;
                string           deviceId = string.IsNullOrWhiteSpace(request.DeviceId)
                    ? request.RequestContext.GetPrincipal().DeviceNumber
                    : request.DeviceId;

                string deviceToken = string.IsNullOrWhiteSpace(request.DeviceToken)
                    ? request.RequestContext.GetPrincipal().DeviceToken
                    : request.DeviceToken;

                try
                {
                    // Authenticate device only when the device token is specified
                    if (!string.IsNullOrWhiteSpace(deviceToken))
                    {
                        device = AuthenticationHelper.AuthenticateDevice(
                            this.Context,
                            deviceToken);
                    }

                    // User logs on.
                    employee = AuthenticationHelper.AuthenticateAndAuthorizeUser(request, device);

                    identity = new CommerceIdentity(employee, device);

                    // If the request is for elevate operation
                    if (request.RetailOperation != RetailOperation.None)
                    {
                        // Add the Elevation properties to the claim.
                        identity.OriginalUserId          = this.Context.GetPrincipal().UserId;
                        identity.ElevatedRetailOperation = request.RetailOperation;

                        // successful manager override for operation with id and operator with id
                        var message = string.Format(
                            "Manager with id '{0}' has approved override for operation with id '{1}' to the operator with id '{2}'.",
                            request.StaffId,
                            identity.ElevatedRetailOperation,
                            identity.OriginalUserId);
                        LogAuditEntry(request.RequestContext, "ElevateUser", message);
                    }

                    return(new UserAuthenticationResponse(employee, device, identity));
                }
                catch (Exception exception)
                {
                    RetailLogger.Log.CrtWorkflowUserAuthenticationRequestHandlerFailure(request.StaffId, deviceId, exception);
                    throw;
                }
            }
            /// <summary>
            /// Initializes a new instance of the <see cref="CommerceRuntimeUserToken"/> class.
            /// </summary>
            /// <param name="initialIdentity">The initial commerce identity.</param>
            /// <param name="newIdentity">The new commerce identity.</param>
            public CommerceRuntimeUserToken(CommerceIdentity initialIdentity, CommerceIdentity newIdentity) : base(CommerceRuntimeTokenSchemeName)
            {
                ThrowIf.Null(newIdentity, "newIdentity");

                if (initialIdentity == null)
                {
                    initialIdentity = new CommerceIdentity();
                }

                CommerceRuntimeManager.UpdateCommerceIdentity(initialIdentity, newIdentity);

                this.commerceRuntimeToken = Newtonsoft.Json.JsonConvert.SerializeObject(initialIdentity);
            }
            /// <summary>
            /// Verifies whether local authorization must be used as a fallback mode in case of error on remote authorization.
            /// </summary>
            /// <returns>A value indicating whether local authorization must be used as a fallback mode in case of error on remote authorization.</returns>
            private bool MustFallbackToLocalAuthorization()
            {
                // we can only fallback to local database if we have a channel id provided
                if (this.CanUseLocalDatabase)
                {
                    EmployeePermissions employeePermissions = null;

                    try
                    {
                        // Create a temporary context with the employee for getting employee permissions.
                        RequestContext tempContext = new RequestContext(this.context.Runtime);
                        var            employee    = new Employee()
                        {
                            StaffId = this.StaffId
                        };
                        ICommercePrincipal principal = this.context.GetPrincipal();
                        CommerceIdentity   identity  = new CommerceIdentity(
                            employee,
                            new Device()
                        {
                            DeviceNumber     = principal.DeviceNumber,
                            Token            = principal.DeviceToken,
                            ChannelId        = principal.ChannelId,
                            TerminalRecordId = principal.TerminalId
                        });
                        tempContext.SetPrincipal(new CommercePrincipal(identity));

                        // Get employee permissions
                        GetEmployeePermissionsDataRequest getEmployeePermissionsDataRequest = new GetEmployeePermissionsDataRequest(
                            this.StaffId,
                            new ColumnSet());

                        employeePermissions = tempContext.Execute <SingleEntityDataServiceResponse <EmployeePermissions> >(
                            getEmployeePermissionsDataRequest).Entity;
                    }
                    catch (Exception exception)
                    {
                        // this method occurs in an error handling scenario
                        // if this fails, we do not want to break the flow
                        // so we just log the exception internally
                        RetailLogger.Instance.CrtServicesStaffAuthorizationServiceGetEmployeePermissionsFailure(exception);
                    }

                    // we can fallback if it is allowed by user permissions
                    return(employeePermissions != null && employeePermissions.ContinueOnTSErrors);
                }

                return(false);
            }
            /// <summary>
            /// Acquires the user token.
            /// </summary>
            /// <param name="userName">Name of the user.</param>
            /// <param name="password">The password of the user.</param>
            /// <param name="commerceAuthenticationParameters">The commerce authentication parameters.</param>
            /// <returns>The user commerce runtime token.</returns>
            internal override Task <UserToken> AcquireToken(string userName, string password, CommerceAuthenticationParameters commerceAuthenticationParameters)
            {
                ThrowIf.Null(commerceAuthenticationParameters, "commerceAuthenticationParameters");

                return(Execute <UserToken>(() =>
                {
                    CommerceRuntimeUserToken commerceUserToken;
                    CommerceIdentity originalIdentity = CommerceRuntimeManager.Identity;
                    ConnectionRequest connectionRequest = this.CreateAcquireTokenRequest(userName, password);
                    connectionRequest.Credential = commerceAuthenticationParameters.Credential;
                    connectionRequest.GrantType = commerceAuthenticationParameters.GrantType;
                    connectionRequest.AdditionalAuthenticationData = commerceAuthenticationParameters;

                    LogonCredentials credentials = null;

                    if (!commerceAuthenticationParameters.RetailOperation.HasValue)
                    {
                        try
                        {
                            CommerceIdentity commerceIdentity = new CommerceIdentity(string.Empty, 0, 0, new string[] { });
                            commerceIdentity.Roles.Add(CommerceRoles.Anonymous);

                            // Set anonymous identity from request.
                            CommerceRuntimeManager.Identity = commerceIdentity;

                            credentials = SecurityManager.Create(CommerceRuntimeManager.Runtime).LogOn(connectionRequest);

                            // Clear the commerce identity.
                            CommerceRuntimeManager.Identity = null;
                        }
                        catch (Exception)
                        {
                            CommerceRuntimeManager.Identity = originalIdentity;
                            throw;
                        }

                        commerceUserToken = new CommerceRuntimeUserToken(credentials.Identity);
                    }
                    else
                    {
                        credentials = SecurityManager.Create(CommerceRuntimeManager.Runtime).ElevateUser(connectionRequest, (RetailOperation)commerceAuthenticationParameters.RetailOperation);
                        commerceUserToken = new CommerceRuntimeUserToken(originalIdentity, credentials.Identity);
                    }

                    return commerceUserToken;
                }));
            }
            /// <summary>
            /// Updates the <paramref name="targetIdentity"/> with the fields from the <paramref name="sourceIdentity"/>.
            /// </summary>
            /// <param name="targetIdentity">The identity object to be updated.</param>
            /// <param name="sourceIdentity">The identity object source for the update.</param>
            internal static void UpdateCommerceIdentity(CommerceIdentity targetIdentity, CommerceIdentity sourceIdentity)
            {
                ThrowIf.Null(targetIdentity, "targetIdentity");
                ThrowIf.Null(sourceIdentity, "sourceIdentity");

                targetIdentity.UserId = sourceIdentity.UserId;

                if (sourceIdentity.UserId != null)
                {
                    targetIdentity.Roles.Add(CommerceRoles.Employee);
                }

                if (!string.IsNullOrWhiteSpace(sourceIdentity.OriginalUserId))
                {
                    targetIdentity.OriginalUserId          = sourceIdentity.OriginalUserId;
                    targetIdentity.ElevatedRetailOperation = sourceIdentity.ElevatedRetailOperation;
                    targetIdentity.UserId = sourceIdentity.UserId;

                    const string ManagerPrivilege = "MANAGERPRIVILEGES";

                    if (sourceIdentity.Roles.Contains(ManagerPrivilege))
                    {
                        targetIdentity.Roles.Add(ManagerPrivilege);
                    }
                }
                else
                {
                    foreach (var role in sourceIdentity.Roles)
                    {
                        targetIdentity.Roles.Add(role);
                    }
                }

                if (!string.IsNullOrWhiteSpace(sourceIdentity.DeviceNumber))
                {
                    targetIdentity.DeviceToken        = sourceIdentity.DeviceToken;
                    targetIdentity.LogOnConfiguration = sourceIdentity.LogOnConfiguration;
                    targetIdentity.TerminalId         = sourceIdentity.TerminalId;
                    targetIdentity.DeviceNumber       = sourceIdentity.DeviceNumber;
                    targetIdentity.ChannelId          = sourceIdentity.ChannelId;
                }
            }
            /// <summary>
            /// Clears the user identity from the <paramref name="currentToken"/> and returns a new <see cref="UserToken"/> without user identity information.
            /// </summary>
            /// <param name="currentToken">The current user token.</param>
            /// <returns>The new user token after user identity is cleared.</returns>
            internal static UserToken RemoveUserIdentityFromToken(UserToken currentToken)
            {
                CommerceIdentity commerceIdentity;

                if (currentToken == null)
                {
                    commerceIdentity = new CommerceIdentity();
                }
                else
                {
                    commerceIdentity = Newtonsoft.Json.JsonConvert.DeserializeObject <CommerceIdentity>(currentToken.Token);
                }

                commerceIdentity.UserId                  = null;
                commerceIdentity.OriginalUserId          = null;
                commerceIdentity.ElevatedRetailOperation = RetailOperation.None;
                commerceIdentity.Roles.Clear();
                commerceIdentity.Roles.Add(CommerceRoles.Anonymous);

                return(new CommerceRuntimeUserToken(commerceIdentity));
            }
예제 #11
0
            /// <summary>
            /// Executes the workflow to do user authentication renewal.
            /// </summary>
            /// <param name="request">The request.</param>
            /// <returns>The response.</returns>
            protected override UserAuthenticationRenewalResponse Process(UserAuthenticationRenewalRequest request)
            {
                ThrowIf.Null(request, "request");
                Device device = null;

                // If device Id is present, authenticate the device to check if the device is active.
                if (!string.IsNullOrWhiteSpace(this.Context.GetPrincipal().DeviceNumber))
                {
                    device = AuthenticationHelper.AuthenticateDevice(this.Context, this.Context.GetPrincipal().DeviceToken);
                }

                // Send authentication renewal request to the service.
                Employee employee = AuthenticationHelper.AuthenticateRenewalUser(this.Context, device);

                CommerceIdentity identity = new CommerceIdentity(employee, device)
                {
                    // Add the LogOn Configuration to the claim.
                    LogOnConfiguration = this.Context.GetPrincipal().LogOnConfiguration
                };

                return(new UserAuthenticationRenewalResponse(employee, device, identity));
            }
 /// <summary>
 /// Initializes a new instance of the <see cref="CommerceRuntimeUserToken"/> class.
 /// </summary>
 /// <param name="commerceIdentity">The commerce identity.</param>
 public CommerceRuntimeUserToken(CommerceIdentity commerceIdentity) : this(null, commerceIdentity)
 {
 }
            /// <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);
            }
 /// <summary>
 /// Default constructor
 /// </summary>
 public PriceInquiryController()
 {
     // Need to set the ChannelId explicitly
     this.CommerceIdentity           = User.Identity as CommerceIdentity;
     this.CommerceIdentity.ChannelId = 5637144662;
 }