/// <summary> /// Gets employee authorized to current store. /// </summary> /// <param name="request">The data service request.</param> /// <returns>The data service response.</returns> private SingleEntityDataServiceResponse <Employee> GetAuthorizedEmployee(GetEmployeeAuthorizedOnStoreDataRequest request) { EmployeeDataManager dataManager = this.GetDataManagerInstance(request.RequestContext); Employee employee = dataManager.GetAuthorizedEmployeeOnStore(request.RequestContext.GetPrincipal().ChannelId, request.StaffId); return(new SingleEntityDataServiceResponse <Employee>(employee)); }
/// <summary> /// Associates the current employee and terminal in <paramref name="context"/>. /// </summary> /// <param name="requestContext">The request context.</param> /// <remarks>If employee cannot hold multiple sessions on different terminals <see cref="UserAuthorizationException"/> is thrown.</remarks> private static void CreateStaffSession(RequestContext requestContext) { ICommercePrincipal principal = requestContext.GetPrincipal(); string staffId = principal.UserId; // when no terminal is present, there is no need to enforce single terminal use if (principal.IsTerminalAgnostic) { throw new InvalidOperationException("A new session can only be created when channel and terminal are present in the request context."); } if (string.IsNullOrWhiteSpace(staffId)) { throw new InvalidOperationException("AuthorizeMultipleTerminalUse can only be performed if user is known. Missing UserId from CommercePrincipal."); } if (!principal.IsEmployee) { throw new InvalidOperationException("AuthorizeMultipleTerminalUse can only be performed if user is employee."); } GetEmployeeAuthorizedOnStoreDataRequest employeeDataRequest = new GetEmployeeAuthorizedOnStoreDataRequest(staffId); Employee employee = requestContext.Execute <SingleEntityDataServiceResponse <Employee> >(employeeDataRequest).Entity; // managers are not required to keep track of sessions if (employee.Permissions.HasManagerPrivileges) { return; } // helper does most of the hard lifting regarding fallback logic and real time communication StaffRealTimeSecurityValidationHelper staffSecurityHelper = StaffRealTimeSecurityValidationHelper.Create( requestContext, SecurityVerificationType.Authorization, staffId, principal.ChannelId, principal.TerminalId, password: string.Empty); // executes the common set of steps that performs the session creation flow in either HQ, local DB, or HQ with local DB fallback ExecuteWorkWithLocalFallback( staffSecurityHelper.GetSecurityVerificationConfiguration(), staffSecurityHelper, () => { return(CreateEmployeeSessionLocalDatabase(requestContext, employee)); }); // we always need to create the session on local DB so we can enforce session is open, // so if the configuration is set to use RealTime service, also creates the session on local DB if (staffSecurityHelper.GetSecurityVerificationConfiguration() == LogOnConfiguration.RealTimeService) { CreateEmployeeSessionLocalDatabase(requestContext, employee); } RetailLogger.Log.CrtServicesStaffAuthorizationServiceUserSessionStarted(staffId, requestContext.GetTerminal().TerminalId); }
/// <summary> /// Authorizes the staff using the local database. /// </summary> /// <param name="context">The request context.</param> /// <param name="staffId">The staff identifier to be verified.</param> /// <param name="enforceSessionOpened">A value indicating whether the authorization service will verify and fail if the user does not have a session opened.</param> /// <returns>The employee object.</returns> private static Employee AuthorizeEmployeeLocalDatabase(RequestContext context, string staffId, bool enforceSessionOpened) { if (context.GetPrincipal().IsChannelAgnostic) { throw new InvalidOperationException("Local authorization can only be performed if principal is not channel agnostic."); } // Check if user is blocked GetEmployeeAuthorizedOnStoreDataRequest employeeDataRequest = new GetEmployeeAuthorizedOnStoreDataRequest(staffId); Employee employee = context.Execute <SingleEntityDataServiceResponse <Employee> >(employeeDataRequest).Entity; if (employee == null || employee.Permissions == null) { throw new UserAuthorizationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_LocalLogonFailed, "User could not be authorized. The user is blocked, not exists, or permission is not found."); } if (employee.IsBlocked) { RetailLogger.Log.CrtServicesStaffAuthorizationServiceBlockedUserAccessAttempt(employee.StaffId); throw new UserAuthorizationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_AuthorizationFailed, "The user is not authorized."); } bool isRequestWithElevatedPrivileges = context.GetPrincipal().ElevatedOperation != (int)RetailOperation.None; // session only needs to be enforces if requested by caller (enforceSessionOpened) and request is bound to a terminal // and it is not a manager override // also, session requirement does not apply for managers if (!employee.Permissions.HasManagerPrivileges && enforceSessionOpened && !context.GetPrincipal().IsTerminalAgnostic&& !isRequestWithElevatedPrivileges) { // validates that employee has open session CheckEmployeeHasOpenSessionDataRequest checkEmployeeSessionRequest = new CheckEmployeeHasOpenSessionDataRequest(); bool isStaffSessionOpenOnTerminal = context.Execute <SingleEntityDataServiceResponse <bool> >(checkEmployeeSessionRequest).Entity; if (!isStaffSessionOpenOnTerminal) { throw new UserAuthorizationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_UserSessionNotOpened, "User must open a session before executing this request."); } } return(employee); }