/// <summary> /// Throws if invalid logon configuration. /// </summary> /// <param name="logOnConfiguration">The log on configuration.</param> /// <exception cref="System.InvalidOperationException">Invalid LogOnConfiguration of a request.</exception> private static void ThrowIfInvalidLogonConfiguration(LogOnConfiguration logOnConfiguration) { if (logOnConfiguration != LogOnConfiguration.RealTimeService) { throw new InvalidOperationException("Invalid LogOnConfiguration of a request."); } }
/// <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 work based against RTS or Local Database based on <paramref name="authorizationConfiguration"/>. /// If <paramref name="authorizationConfiguration"/> is <see cref="LogOnConfiguration.RealTimeService"/> then /// business logic is performed using RealTime service. If RealTime is not available and <see cref="Employee"/> is allowed to fallback to local database checks, then /// the delegate <paramref name="localDatabaseAction"/> will be executed. In case <paramref name="authorizationConfiguration"/> is <see cref="LogOnConfiguration.LocalDatabase"/>, /// then authorization is performed solely using local database. /// </summary> /// <param name="authorizationConfiguration">Indicates whether the logic should run, against local database or against the real time service.</param> /// <param name="staffSecurityHelper">The staff security validation helper instance.</param> /// <param name="localDatabaseAction">A delegate for the local execution of the authorization logic.</param> /// <returns>The employee.</returns> private static Employee ExecuteWorkWithLocalFallback(LogOnConfiguration authorizationConfiguration, StaffRealTimeSecurityValidationHelper staffSecurityHelper, Func <Employee> localDatabaseAction) { Employee employee = null; string errorMessage; switch (authorizationConfiguration) { case LogOnConfiguration.RealTimeService: try { employee = staffSecurityHelper.VerifyEmployeeRealTimeService(() => { return(localDatabaseAction()); }); } catch (HeadquarterTransactionServiceException exception) { throw new UserAuthorizationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_HeadquarterTransactionServiceMethodCallFailure, exception, exception.Message) { LocalizedMessage = exception.LocalizedMessage }; } catch (CommerceException exception) { // The error code to be persisted throw new UserAuthorizationException( SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_HeadquarterCommunicationFailure, exception, exception.Message); } catch (Exception exception) { // any exceptions that might happen will cause the authorization to fail throw new UserAuthorizationException(SecurityErrors.Microsoft_Dynamics_Commerce_Runtime_AuthorizationFailed, exception, exception.Message); } break; case LogOnConfiguration.LocalDatabase: employee = localDatabaseAction(); break; default: errorMessage = string.Format( CultureInfo.InvariantCulture, "The authorization configuration value '{0}' is not supported.", authorizationConfiguration); throw new NotSupportedException(errorMessage); } return(employee); }