/// <summary>
        /// Run the workflow associated with notification reply
        /// </summary>
        void RunReplyWorkflow(IWorkflowRunner runner, Workflow workflow, ReplyRecord reply)
        {
            if (workflow.WorkflowRunAsOwner != true)
            {
                throw new ArgumentException($"The provided workflow is not marked as run as owner. This should never occur. Workflow: ${workflow.Name}");
            }

            var input = new Dictionary <string, object>();

            var inputArg = workflow?.InputArgumentForAction?.As <ResourceArgument>();

            if (inputArg != null)
            {
                if (inputArg.ConformsToType.Id == ReplyRecord.ReplyRecord_Type.Id)
                {
                    input.Add(inputArg.Name, reply);
                }
            }

            // Set the context to the owner and start the workflow.
            var wfOwner     = workflow.SecurityOwner;
            var contextData = new RequestContextData(RequestContext.GetContext());

            contextData.Identity = new ReadiNow.Security.IdentityInfo(wfOwner.Id, wfOwner.Name);

            using (CustomContext.SetContext(contextData))
            {
                runner.RunWorkflowAsync(new WorkflowStartEvent(workflow)
                {
                    Arguments = input
                });
            }
        }
Beispiel #2
0
        /// <summary>
        ///     Executes the filter action asynchronously.
        /// </summary>
        /// <param name="actionContext">The action context.</param>
        /// <param name="cancellationToken">The cancellation token assigned for this task.</param>
        /// <param name="continuation">The delegate function to continue after the action method is invoked.</param>
        /// <returns>
        ///     The newly created task for this operation.
        /// </returns>
        public Task <HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func <Task <HttpResponseMessage> > continuation)
        {
            // Get web context
            string entryPoint = "Failed";

            try
            {
                entryPoint = actionContext.ControllerContext.Controller.GetType( ).Name + "." + actionContext.ActionDescriptor.ActionName;
            }
            catch { }

            using (DatabaseContextInfo.SetContextInfo($"WebApi - {actionContext.ControllerContext.ControllerDescriptor.ControllerName}.{actionContext.ActionDescriptor.ActionName}"))
                using (EntryPointContext.SetEntryPoint(entryPoint))
                {
                    ProcessMonitorWriter.Instance.Write(entryPoint);

                    RequestContext requestContext = RequestContext.GetContext( );
                    if (requestContext != null && requestContext.IsValid)
                    {
                        // Attach timezone
                        string tz = HttpContext.Current.Request.Headers.Get("Tz");
                        if (!string.IsNullOrEmpty(tz))
                        {
                            // Set the timezone in the logical context
                            var contextData = new RequestContextData(requestContext.Identity, requestContext.Tenant, requestContext.Culture, tz);
                            RequestContext.SetContext(contextData);
                        }
                    }

                    // Do the actual API call work
                    return(continuation( ));
                }
        }
Beispiel #3
0
        public void Test_DateTypes(string fieldTypeAlias, string calculation, string fieldValue, string expectValue)
        {
            var curContext = RequestContext.GetContext();
            var newContext = new RequestContextData(curContext.Identity, curContext.Tenant, curContext.Culture, "Australia/Sydney");

            RequestContext.SetContext(newContext);

            try
            {
                DateTime value    = DateTime.ParseExact(fieldValue + ".0000000Z", "o", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
                DateTime expected = DateTime.ParseExact(expectValue + ".0000000Z", "o", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
                Assert.That(value.Kind, Is.EqualTo(DateTimeKind.Utc), "Test sanity check");

                var scenario = CreateScenario(fieldTypeAlias, "[Field]", value);
                var field    = scenario.Item1;
                var inst     = scenario.Item2;

                // Get calculated field
                DateTime result = (DateTime)inst.GetField(field.Id);

                Assert.That(result, Is.EqualTo(expected));
                Assert.That(result.Kind, Is.EqualTo(DateTimeKind.Utc));
            }
            finally
            {
                RequestContext.SetContext(curContext);
            }
        }
        /// <summary>
        /// Authenticates the specified user name and password and returns the set of authorization policies for <see cref="T:System.IdentityModel.Tokens.UserNameSecurityToken"/> security tokens.
        /// </summary>
        /// <param name="userName">The user name associated with the security token.</param>
        /// <param name="password">The password associated with the security token.</param>
        /// <returns>
        /// A <see cref="T:System.Collections.ObjectModel.ReadOnlyCollection`1"/> of type <see cref="T:System.IdentityModel.Policy.IAuthorizationPolicy"/> that contains the set of authorization policies in effect for this application.
        /// </returns>
        /// <exception cref="T:System.ArgumentNullException">
        ///   <paramref name="userName"/> is null.</exception>
        ///
        /// <exception cref="T:System.IdentityModel.Tokens.SecurityTokenValidationException">
        ///   <paramref name="userName"/> and <paramref name="password"/> combination are not valid.</exception>
        protected override ReadOnlyCollection <IAuthorizationPolicy> ValidateUserNamePasswordCore(string userName, string password)
        {
            ReadOnlyCollection <IAuthorizationPolicy> currentPolicies = base.ValidateUserNamePasswordCore(userName, password);

            List <IAuthorizationPolicy> newPolicies = new List <IAuthorizationPolicy>(currentPolicies);

            string tenant = string.Empty;

            // Split the tenant and username fields
            string[] credentials = userName.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
            if (credentials.Length > 1)
            {
                tenant   = credentials[0];
                userName = credentials[1];
            }

            // Validate the user name and password
            RequestContextData contextData = UserAccountCache.GetRequestContext(userName, password, tenant);

            if (contextData == null)
            {
                throw new SecurityTokenValidationException("Invalid username and/or password.");
            }

            // Extend the original context with culture information
            newPolicies.Add(new IdentityTenantAuthorizationPolicy(contextData.Identity, contextData.Tenant));

            return(newPolicies.AsReadOnly());
        }
Beispiel #5
0
        /// <summary>
        /// Impersonate an admin of this tenant and return the context object, which must be disposed.
        /// </summary>
        public IDisposable GetTenantAdminContext( )
        {
            if (TenantAdminIdentityInfo == null)
            {
                using (GetSystemAdminContext( ))
                {
                    Role        role        = Entity.Get <Role>("core:administratorRole");
                    UserAccount userAccount = role.RoleMembers.FirstOrDefault( );
                    if (userAccount == null)
                    {
                        throw new Exception($"Tenant '{TenantName}' has no administrator.");
                    }

                    TenantAdminIdentityInfo = new IdentityInfo(userAccount.Id, userAccount.Name);
                }
            }

            // Set context
            var tenantInfo = new EDC.ReadiNow.Metadata.Tenants.TenantInfo(TenantId);
            RequestContextData contextData = new RequestContextData(TenantAdminIdentityInfo, tenantInfo, CultureHelper.GetUiThreadCulture(CultureType.Neutral));

            RequestContext.SetContext(contextData);

            // Return delegate to revoke context
            return(ContextHelper.Create(RequestContext.FreeContext));
        }
Beispiel #6
0
 public RunState(WorkflowMetadata metaData, WorkflowRun workflowRun, RequestContextData effectiveSecurityContext)
     : base(metaData, workflowRun, effectiveSecurityContext)
 {
     ownerAccountRuntimeArgName     = Entity.GetName(new EntityRef("workflowOwnerAccount").Id);
     triggeringUserRuntimeArgName   = Entity.GetName(new EntityRef("triggeringUserAccount").Id);
     triggeringPersonRuntimeArgName = Entity.GetName(new EntityRef("triggeringPerson").Id);
 }
Beispiel #7
0
        /// <summary>
        ///     Validates the specified user account credentials.
        /// </summary>
        /// <param name="username">A string containing the username associated with the user account.</param>
        /// <param name="password">A string containing the password associated with the user account.</param>
        /// <param name="tenant">A string containing the tenant associated with the user account.</param>
        /// <param name="setContext">A Boolean that controls whether or not this method sets the context data within the logical thread for subsequent security checks.</param>
        /// <remarks>This method does not update any user account information associated with the request.</remarks>
        public static void Validate(string username, string password, string tenant, bool setContext)
        {
            if (string.IsNullOrEmpty(username))
            {
                throw new ArgumentNullException("username");
            }
            if (password == null)
            {
                throw new ArgumentNullException("password");
            }
            if (string.IsNullOrEmpty(tenant))
            {
                throw new ArgumentNullException("tenant");
            }

            // Check the credentials
            RequestContextData contextData = UserAccountCache.GetRequestContext(username, password, tenant);

            if (contextData == null)
            {
                EventLog.Application.WriteWarning(string.Format("Invalid username or password. {0}\\{1} : {2}", tenant, username,
                                                                (password.Length == 0 ? "blank" : "nonblank")));

                throw new InvalidCredentialException(InvalidUserNameOrPasswordMessage);
            }

            if (setContext)
            {
                // Set the user context data within the logical thread
                RequestContext.SetContext(contextData);
            }
        }
Beispiel #8
0
        /// <summary>
        /// Get the request context this workflow will be running as, taking into account triggering user and owner.
        /// </summary>
        private RequestContextData GetEffectiveSecurityContext(WorkflowRun run, WorkflowMetadata metaData)
        {
            var effectiveUser  = GetEffectiveUser(run, metaData);
            var triggeringUser = GetTriggeringUser(run);

            // Error! The caller will deal with the missing info. We can't throw becasue RunState is needed for the error reporting
            if (effectiveUser == null)
            {
                return(null);
            }

            if (metaData.WfRunAsOwner && metaData.WfSecurityOwner == null)
            {
                return(null);
            }

            var identityInfo = new IdentityInfo(effectiveUser.Id, effectiveUser.Name);


            var context = RequestContext.GetContext();

            var effectiveSecurityContext = new RequestContextData(context);

            effectiveSecurityContext.Identity = identityInfo;

            // If we are running as someone other than the triggerer, set the secondary identity to the triggerer.
            // NOTE: This could potentially cause a problem in the case where a wf triggering another wf scenario.
            // It's possible that the user will see stale data. The risk should be quite low.
            if (triggeringUser != null && triggeringUser.Id != effectiveUser.Id)
            {
                effectiveSecurityContext.SecondaryIdentity = new IdentityInfo(triggeringUser.Id, triggeringUser.Name);
            }

            return(effectiveSecurityContext);
        }
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="requestContextData"></param>
        /// <param name="accountStatus"></param>
        public IdentityProviderContextCacheValue(RequestContextData requestContextData, long accountStatus)
        {
            if (requestContextData == null)
            {
                throw new ArgumentNullException(nameof(requestContextData));
            }

            RequestContextData = requestContextData;
            AccountStatus      = accountStatus;
        }
Beispiel #10
0
        /// <summary>
        ///     Signs a software platform user into the system using an existing cookie.
        /// </summary>
        private HttpResponseMessage <LoginResult> SigninSoftwarePlatformWithCookie()
        {
            var userAgent = Request?.Headers?.UserAgent?.ToString();

            var context     = EDC.ReadiNow.IO.RequestContext.GetContext();
            var contextData = new RequestContextData(context.Identity, context.Tenant, CultureHelper.GetUiThreadCulture(CultureType.Specific), context.TimeZone);

            AuditLogInstance.Get().OnLogon(true, context.Identity.Name, userAgent);

            return(new HttpResponseMessage <LoginResult>(GetSuccessfulLoginResult(contextData, context.Identity.Id), HttpStatusCode.OK));
        }
        public override void QueueAction(Action action)
        {
            var contextData = new RequestContextData(RequestContext.GetContext());

            _queue.Enqueue(() =>
            {
                using (CustomContext.SetContext(contextData))
                {
                    action();
                }
            });
        }
Beispiel #12
0
        public ActionResult Create(CreateArticleModel createArticleModel)
        {
            RequestContextData requestContextData = this.RequestContextData;

            IApplicationDataCache applicationDataCache = InstanceContainer.ApplicationDataCache;

            List <IWikiLanguageThreadLookupItem> wikiLanguageThreadLookupItems = applicationDataCache.GetWikiLanguageThreadIdLookup(requestContextData.ApplicationThemeInfo.ApplicationName);

            return(View(new CreateArticleModel(
                            5
                            , new SelectList(wikiLanguageThreadLookupItems, "ArticleGroupThreadId", "LanguageName")
                            )));
        }
Beispiel #13
0
        public RunStateBase(WorkflowMetadata metaData, WorkflowRun _workflowRun, RequestContextData effectiveSecurityContext)
            : this(metaData)
        {
            WorkflowInvoker = new WorkflowInvoker();
            WorkflowRun     = _workflowRun;

            StepsTakenInSession      = 0;
            EffectiveSecurityContext = effectiveSecurityContext;
            ExitPointId     = _workflowRun.WorkflowRunExitPoint;
            HasTimeout      = _workflowRun.HasTimeout ?? false;
            PendingActivity = _workflowRun.PendingActivity;
            RunStatus       = _workflowRun.WorkflowRunStatus_Enum;
            CompletedAt     = _workflowRun.RunCompletedAt;
        }
Beispiel #14
0
        /// <summary>
        /// Start running a task asynchronously.
        /// </summary>
        /// <param name="action">The action to execute.</param>
        /// <param name="settings"></param>
        public void Start(Action action, AsyncRunnerSettings settings = null)
        {
            var context     = RequestContext.GetContext( );
            var contextData = new RequestContextData(context);

            Action wrappedAction = () =>
            {
                using (CustomContext.SetContext(contextData))
                {
                    action( );
                }
            };

            ThreadPool.QueueUserWorkItem(StartThread, wrappedAction);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="OpenIdConnectRequestContextResult" /> class.
        /// </summary>
        /// <param name="requestContextData">The request context data.</param>
        /// <param name="identityProviderUserName">Name of the identity provider user.</param>
        /// <exception cref="System.ArgumentNullException">
        /// </exception>
        public OpenIdConnectRequestContextResult(RequestContextData requestContextData, string identityProviderUserName)
        {
            if (requestContextData == null)
            {
                throw new ArgumentNullException(nameof(requestContextData));
            }

            if (string.IsNullOrWhiteSpace(identityProviderUserName))
            {
                throw new ArgumentNullException(nameof(identityProviderUserName));
            }

            RequestContextData       = requestContextData;
            IdentityProviderUserName = identityProviderUserName;
        }
        /// <summary>
        /// Run a action in the background
        /// </summary>
        /// <param name="action"></param>
        public virtual void QueueAction(Action action)
        {
            var contextData  = new RequestContextData(RequestContext.GetContext());
            var wfRunContext = WorkflowRunContext.Current;

            Action wrappedAction = () =>
            {
                using (CustomContext.SetContext(contextData))
                    using (new WorkflowRunContext(wfRunContext))
                    {
                        action();
                    }
            };

            ThreadPool.QueueUserWorkItem(StartThread, wrappedAction);
        }
Beispiel #17
0
        /// <summary>
        ///     Gets the successful login result.
        /// </summary>
        /// <returns></returns>
        private static LoginResult GetSuccessfulLoginResult(RequestContextData requestContextData, long accountId = -1)
        {
            /////
            // Construct the initial settings.
            /////
            var loginResult = new LoginResult
            {
                InitialSettings = new InitialSettings
                {
                    PlatformVersion       = SystemInfo.PlatformVersion,
                    RequiredClientVersion = GetRequiredClientVersion(),
                    BranchName            = SystemInfo.BranchName,
                    Culture         = requestContextData.Culture,
                    FeatureSwitches = Factory.FeatureSwitch.GetFeatureListString()
                }
            };

            if (accountId != -1)
            {
                loginResult.ActiveAccountInfo = new ActiveAccountInfo
                {
                    AccountId = accountId,
                };

                if (requestContextData != null)
                {
                    loginResult.ActiveAccountInfo.Tenant   = requestContextData.Tenant.Name;
                    loginResult.ActiveAccountInfo.Username = requestContextData.Identity.Name;
                    loginResult.ActiveAccountInfo.Provider = requestContextData.Identity.IdentityProviderTypeAlias;
                    loginResult.ConsoleTimeoutMinutes      = LoginConstants.Cookie.Timeout;

                    if (requestContextData.Identity.IdentityProviderId != WellKnownAliases.CurrentTenant.ReadiNowIdentityProviderInstance)
                    {
                        // Ensure we keep the cookie alive for non native identity providers
                        loginResult.ConsoleTimeoutMinutes /= 2;
                    }
                }

                // This is only set during integration tests

                loginResult.TestToken = TestAuthorization.IsEnabled ? TestAuthorization.Instance.GetTestToken(requestContextData.Tenant.Id, WellKnownAliases.CurrentTenant.ReadiNowIdentityProviderInstance, requestContextData.Identity.Name) : null;
            }


            return(loginResult);
        }
Beispiel #18
0
        public void LogEntryContainsSecondaryName(string secondaryName, string expected)
        {
            var toDelete = new List <long>();

            try
            {
                var policy = new RecordChangeAuditPolicy()
                {
                    Name = "TEST ResourceAuditEventHandlerTests LogCreate1", TriggeredOnType = Person.Person_Type, TriggerEnabled = true
                };
                policy.UpdatedFieldsToTriggerOn.Add(Resource.Name_Field.As <Field>());
                policy.Save();
                toDelete.Add(policy.Id);

                var person = Entity.Create <Person>();
                person.Name = "bob";
                person.Save();


                var log = RunAndLog(() =>
                {
                    var contextData = new RequestContextData(RequestContext.GetContext());

                    if (secondaryName != null)
                    {
                        contextData.SecondaryIdentity = new IdentityInfo(999, secondaryName);
                    }

                    RequestContext.SetContext(contextData);

                    person      = person.AsWritable <Person>();
                    person.Name = "jane";
                    person.Save();
                });

                Assert.That(log.Count, Is.EqualTo(1));
                Assert.That(log[0].Name, Is.EqualTo(expected));
            }
            finally
            {
                Entity.Delete(toDelete);
            }
        }
Beispiel #19
0
        public void SuspendWithNoSecondaryId()
        {
            var oldContext = new RequestContextData(RequestContext.GetContext());

            try
            {
                var mockHandler = new Mock <DummyHandler>();

                var handler = new DummyHandler();

                var bgTask = handler.ToBackgroundTask(new DummyParams()
                {
                    S = "SuspendRestore"
                });

                var primaryUa = new UserAccount()
                {
                    Name = "primaryId"
                };

                var primaryId = new IdentityInfo(primaryUa.Id, primaryUa.Name);

                var contextData = new RequestContextData(primaryId, RequestContext.GetContext().Tenant, "XYZ", null)
                {
                    TimeZone = "XYZTZ"
                };

                RequestContext.SetContext(contextData);

                using (new SecurityBypassContext())
                {
                    // Suspend
                    IEntity suspendedtask = handler.CreateSuspendedTask(bgTask);
                }
            }
            finally
            {
                RequestContext.SetContext(oldContext);
            }
        }
Beispiel #20
0
        public IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            // TODO (Roman): errorhandling, cleanup, upper/lower case stuff
            RequestContextData  requestContextData = InstanceContainer.RequestHelper.GetRequestContextData(requestContext.HttpContext.Request);
            IApplicationContext applicationContext = InstanceContainer.ApplicationContext;

            IThemeFolderLookup   themeFolderLookup   = applicationContext.GetThemeFolderLookup(requestContextData.ApplicationThemeInfo.ApplicationGroup);
            IStaticContentLookup staticContentLookup = applicationContext.GetStaticContentLookup(requestContextData.ApplicationThemeInfo.ApplicationGroup);

            string text = ContentFormatUtility.Format(
                requestContextData.Theme
                , staticContentLookup.GetContent(requestContextData.Theme, "js_globals")
                , staticContentLookup
                , themeFolderLookup
                , ContentFormatUtility.FormatMode.EscapeSingleQuotes);

            requestContext.HttpContext.Response.Clear();
            requestContext.HttpContext.Response.Write(text);
            requestContext.HttpContext.Response.End();

            return(null);
        }
Beispiel #21
0
        /// <summary>
        ///     Indicates whether the specified control is authorized.
        /// </summary>
        /// <param name="actionContext">The context.</param>
        /// <returns>
        ///     true if the control is authorized; otherwise, false.
        /// </returns>
        protected override bool IsAuthorized(HttpActionContext actionContext)
        {
            if (actionContext == null || actionContext.Request == null)
            {
                // This is intentionally an ArgumentNullException instead of a WebArgumentNullException because
                // this should never be called with a null actionContext by ASP.NET WebAPI.
                throw new ArgumentNullException("actionContext");
            }

            //
            // Integration Test Authorization
            // if we are in integrated testing mode and a test token has been provided, use it. If it fails, pretend it never happened.
            // Otherwise perform a normal test.
            //
            if (TestAuthorization.IsEnabled)
            {
                var authorizationHeader = HttpContext.Current.Request.Headers.Get("Authorization");
                if (!string.IsNullOrEmpty(authorizationHeader))
                {
                    long   tenantId;
                    long   providerId;
                    string userName;
                    if (TestAuthorization.Instance.TryGetIdentifier(authorizationHeader, out tenantId, out providerId, out userName))
                    {
                        var testRequestContextData = Factory.IdentityProviderRequestContextCache.GetRequestContextData(tenantId, providerId, userName, false);
                        RequestContext.SetContext(testRequestContextData);
                        return(true);
                    }
                }
                // fall back to usual login
            }

            Collection <CookieHeaderValue> cookies = actionContext.Request.Headers.GetCookies( );

            //
            // Normal authorization
            //
            CookieState aspxAuthCookie = cookies.Select(c => c[FormsAuthentication.FormsCookieName]).FirstOrDefault( );

            if (aspxAuthCookie == null)
            {
                throw new InvalidCredentialException(AuthenticationCookieMissingMessage);
            }

            string ticketData = aspxAuthCookie.Value;

            if (string.IsNullOrEmpty(ticketData))
            {
                throw new InvalidCredentialException(AuthenticationCookieInvalidMessage);
            }

            FormsAuthenticationTicket authenticationTicket;

            try
            {
                authenticationTicket = FormsAuthentication.Decrypt(ticketData);
            }
            catch (Exception ex)
            {
                EventLog.Application.WriteError("Error decrypting authentication ticket. " + ex.Message);
                throw new InvalidCredentialException(UserAccountValidator.InvalidUserNameOrPasswordMessage, ex);
            }
            if (authenticationTicket == null)
            {
                throw new InvalidCredentialException(UserAccountValidator.InvalidUserNameOrPasswordMessage);
            }

            /////
            // Check whether the ticket has expired.
            /////
            if (authenticationTicket.Expired)
            {
                throw new AuthenticationTokenExpiredException( );
            }

            // Get the encrypted cookie payload
            AuthenticationToken authTicket;

            try
            {
                using (var input = new StringReader(authenticationTicket.UserData))
                {
                    authTicket = JSON.Deserialize <AuthenticationToken>(input);
                }
            }
            catch (Exception ex)
            {
                throw new InvalidCredentialException(AuthenticationCookieInvalidMessage, ex);
            }
            if (authTicket == null)
            {
                throw new InvalidCredentialException(AuthenticationCookieInvalidMessage);
            }

            // Prevent XSRF attacks
            bool noXsrfCheck =
                actionContext.ActionDescriptor.GetCustomAttributes <NoXsrfCheckAttribute>( ).Count > 0 ||
                actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes <NoXsrfCheckAttribute>( ).Count > 0;

            if (!noXsrfCheck &&
                !CookieHelper.VerifyXsrfToken(actionContext, authTicket, cookies))
            {
                EventLog.Application.WriteWarning($"Invalid XSRF token detected. Headers:\n{actionContext?.Request?.Headers}");
                throw new XsrfValidationException( );
            }

            RequestContextData requestContextData = Factory.IdentityProviderRequestContextCache.GetRequestContextData(authTicket.TenantId,
                                                                                                                      authTicket.IdentityProviderId, authTicket.IdentityProviderUserName, false);

            if (requestContextData == null)
            {
                throw new InvalidCredentialException(UserAccountValidator.InvalidUserNameOrPasswordMessage);
            }

            if (authTicket.UserAccountId != requestContextData.Identity.Id)
            {
                throw new InvalidCredentialException(UserAccountValidator.InvalidUserNameOrPasswordMessage);
            }

            RequestContext.SetContext(requestContextData);

            /////
            // Don't extend the cookie timeout for challenge requests for the native identity provider
            /////
            if (actionContext.Request.RequestUri.LocalPath.ToLowerInvariant() == ChallengeRequestUri &&
                authTicket.IdentityProviderId == WellKnownAliases.CurrentTenant.ReadiNowIdentityProviderInstance)
            {
                return(true);
            }

            /////
            // Sliding window expiry.
            // Note* If the Web page is accessed before half of the expiration time passes, the ticket expiration
            // time will not be reset. As per http://support.microsoft.com/kb/910443/en-gb
            /////
            if (DateTime.Now <= authenticationTicket.Expiration.AddMinutes(-(LoginConstants.Cookie.Timeout / 2)))
            {
                return(true);
            }

            /////
            // Do not require the caller to have access to the authentication entities e.g. Open ID provider.
            /////
            using (new SecurityBypassContext( ))
            {
                CookieHelper.CreateAuthenticationAndXsrfCookies(authTicket.TenantId, authTicket.IdentityProviderId, authTicket.IdentityProviderUserName, authTicket.UserAccountId, authTicket.Persist, authTicket.XsrfToken);
            }

            return(true);
        }
Beispiel #22
0
        /// <summary>
        ///     Checks the credentials for the specified user account.
        /// </summary>
        /// <param name="username">A string containing the username associated with the user account. This cannot be null or empty.</param>
        /// <param name="password">A string containing the password associated with the user account. This cannot be null.</param>
        /// <param name="tenantName">Name of the tenant. This cannot be null or empty.</param>
        /// <param name="updateAccount">A Boolean value that controls whether or not user account information associated with the request is updated.</param>
        /// <param name="skipPasswordExpiryCheck">A Boolean that controls whether to perform the password expiry check.</param>
        /// <returns>An object representing the identity of the user account</returns>
        /// <exception cref="ArgumentException">
        /// The given account details are incorrect.
        /// </exception>
        /// <exception cref="TenantDisabledException">
        /// The tenant is disabled, meaning no user in that tenant can authenticate.
        /// </exception>
        private static RequestContextData ValidateAccount(string username, string password, string tenantName, bool updateAccount, bool skipPasswordExpiryCheck = false)
        {
            if (String.IsNullOrEmpty(username))
            {
                throw new ArgumentException("The specified username parameter is invalid.");
            }
            if (password == null)
            {
                throw new ArgumentNullException("password");
            }
            if (String.IsNullOrEmpty(tenantName))
            {
                throw new ArgumentException("The specified tenant parameter is invalid.");
            }

            RequestContextData contextData;

            // Cache the original request context
            RequestContext originalContextData = RequestContext.GetContext( );

            try
            {
                TenantInfo     tenantInfo;
                UserAccount    userAccount;
                PasswordPolicy passwordPolicy;

                // Set the system administrators context
                RequestContext.SetSystemAdministratorContext( );

                try
                {
                    if (password.Length > MaxPasswordLength)
                    {
                        throw new ArgumentException(
                                  string.Format("Password cannot be longer than {0} characters", MaxPasswordLength),
                                  "password");
                    }

                    if (tenantName == SpecialStrings.GlobalTenant)
                    {
                        // Create a Dummy Tenant Info
                        // No need to set the context as we are already the global admin
                        tenantInfo = new TenantInfo(0)
                        {
                            Name = SpecialStrings.GlobalTenant
                        };
                    }
                    else
                    {
                        // Get the tenant with the specified name
                        Tenant tenant = TenantHelper.Find(tenantName);
                        if (tenant == null)
                        {
                            throw new ArgumentException(string.Format("Unknown tenant '{0}'", tenantName), "tenantName");
                        }

                        if (tenant.IsTenantDisabled ?? false)
                        {
                            throw new TenantDisabledException(tenantName);
                        }

                        // Set the tenant administrators context
                        RequestContext.SetTenantAdministratorContext(tenant.Id);

                        tenantInfo = new TenantInfo(tenant.Id)
                        {
                            Name = tenantName.ToUpperInvariant()
                        };
                    }

                    // Get the user account with the specified name
                    userAccount = Entity.GetByField <UserAccount>(username, true, new EntityRef("core", "name")).FirstOrDefault( );
                    if (userAccount == null)
                    {
                        throw new ArgumentException(string.Format("Could not find user '{0}' in tenant '{1}'", username, tenantName));
                    }

                    // Get the password policy
                    passwordPolicy = Entity.Get <PasswordPolicy>(new EntityRef("core:passwordPolicyInstance"));
                    if (passwordPolicy == null)
                    {
                        throw new ArgumentException(string.Format("Could not find password policy for tenant '{0}'", tenantName));
                    }
                }
                catch (Exception ex)
                {
                    EventLog.Application.WriteWarning("Login failed: " + ex.Message);

                    // Validate a password here to mitigate timing attacks. An attacker could use this
                    // to guess which passwords are valid by timing the login. Without this, logins that
                    // have a invalid user name and tenant will be quicker than those with a valid user name.
                    CryptoHelper.CreateEncodedSaltedHash("test password");

                    throw;
                }


                ValidateAccount(userAccount, passwordPolicy, password, updateAccount, skipPasswordExpiryCheck);

                // Set the context data
                var identityInfo = new IdentityInfo(userAccount.Id, userAccount.Name);

                contextData = new RequestContextData(identityInfo, tenantInfo, CultureHelper.GetUiThreadCulture(CultureType.Specific));
            }
            finally
            {
                // Restore the original request context
                if ((originalContextData != null) && (originalContextData.IsValid))
                {
                    RequestContext.SetContext(originalContextData);
                }
            }

            return(contextData);
        }
        public HttpResponseMessage <string> Feedback([FromBody] FeedbackData data)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            var idString = Guid.NewGuid().ToString();

            var text = "";

            // Aggregate for some misguided reason throws if the collection is empty
            if (data.Messsages.Count > 0)
            {
                text = data.Messsages.Aggregate((a, p) => a + (string.IsNullOrEmpty(a) ? "" : "\r\n") + p);
            }

            var context = new RequestContextData(EDC.ReadiNow.IO.RequestContext.GetContext());

            if (context == null || context.Identity == null || context.Tenant == null)
            {
                throw new InvalidOperationException("Failed to determine identity");
            }

            string tenantName = context.Tenant.Name;
            string userName   = context.Identity.Name;

            var e = ReadiNow.Model.Entity.Get <UserAccount>(context.Identity.Id);

            if (e == null)
            {
                throw new InvalidOperationException("Failed to determine account holder");
            }

            string personName = e.AccountHolder != null ? e.AccountHolder.Name : context.Identity.Name;

            var path = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);

            path = Path.Combine(path, @"ReadiNow\ClientLogs");
            //todo- factor out that clean routine... just can't remember a quick way in C#....
            path = Path.Combine(path, Regex.Replace(tenantName, @"[^A-Za-z0-9_]+", "-"));
            path = Path.Combine(path, Regex.Replace(userName, @"[^A-Za-z0-9_]+", "-"));
            path = Path.Combine(path, idString);

            Directory.CreateDirectory(path);
            Directory.CreateDirectory(Path.Combine(path, "attachments"));

            using (var fs = new FileStream(Path.Combine(path, "comments.txt"), FileMode.Create))
                using (var w = new StreamWriter(fs))
                {
                    w.Write(data.Comments);
                    w.Close();
                }

            using (var fs = new FileStream(Path.Combine(path, "browser.log"), FileMode.Create))
                using (var w = new StreamWriter(fs))
                {
                    w.Write(text);
                    w.Close();
                }

            if (data.Attachments != null) // am so over null checks.... foreach throws
            {
                foreach (var a in data.Attachments)
                {
                    // strip off things like data:text/plain;base64,
                    if (Regex.IsMatch(a.Data, "^data:.*;base64,"))
                    {
                        a.Data = a.Data.Substring(a.Data.IndexOf(',') + 1);
                    }

                    using (var fs = new FileStream(Path.Combine(path, "attachments", a.Name + "." + a.Ext), FileMode.Create))
                        using (var bw = new BinaryWriter(fs))
                        {
                            var content = Convert.FromBase64String(a.Data);
                            bw.Write(content);
                            bw.Close();
                        }
                }
            }

            SaveRecentServerLogs(path);

            ReadiNow.Diagnostics.EventLog.Application.WriteInformation("Client feedback saved to {0}", path);

            // if configured to create a ticket in ReadiDesk then do so

            var description = "";

            description += "email: " + data.Email + "\n";
            description += "phone: " + data.Phone + "\n";
            description += "tenant: " + tenantName + "\n";
            description += "account: " + userName + "\n";
            description += "user: "******"\n";
            description += "front end server: " + Dns.GetHostEntry("localhost").HostName + "\n";
            description += "platform version: " + SystemInfo.PlatformVersion + "\n";
            description += "branch name: " + SystemInfo.BranchName + "\n";

            var apps    = ReadiNow.Model.Entity.GetInstancesOfType <Solution>();
            var appList = apps.Aggregate("", (a, p) => a + (string.IsNullOrEmpty(a) ? "" : ", ") +
                                         p.Name + " (" + p.SolutionVersionString + ")");

            description += "apps: " + appList + "\n";

            description += "\ndetails: " + data.Comments + "\n\n";

            var ticket = new ReadiDeskTicket
            {
                TenantName  = tenantName,
                UserName    = userName,
                Summary     = data.Comments.Split('\n').FirstOrDefault(),
                Description = description,
                Attachments = new List <Attachment>()
                {
                    new Attachment {
                        Name = "consolelog", Ext = "txt", Data = Convert.ToBase64String(Encoding.UTF8.GetBytes(text))
                    }
                }
            };

            ticket.Summary = GetSanitizedNameFieldValue(ticket.Summary);    // ticket summary is saved as the name of the ticket
            if (data?.Attachments != null)
            {
                ticket.Attachments = ticket.Attachments.Concat(data.Attachments).ToList( );
            }
            idString = ReadiDeskService.RemoteCreateTicket(ticket) ?? idString;

            return(new HttpResponseMessage <string>(idString, HttpStatusCode.OK));
        }
Beispiel #24
0
        protected override void Execute(IJobExecutionContext jobContext)
        {
            var stopWatch = new Stopwatch();

            perfCounters.GetPerformanceCounter <RatePerSecond32PerformanceCounter>(WorkflowPerformanceCounters.ScheduleFireRateCounterName).Increment();
            stopWatch.Start();

            var jobRef = ScheduledItemHelper.GetScheduledItemRef(jobContext);

            Diagnostics.EventLog.Application.WriteTrace($"Starting job {jobRef.Id}.");

            try
            {
                using (DeferredChannelMessageContext deferredMsgContext = new DeferredChannelMessageContext())  // needed to keep redis happy
                {
                    // Set the context to the owner of the scheduled item.
                    var scheduledItem = Entity.Get <ScheduledItem>(jobRef);

                    if (scheduledItem == null)
                    {
                        Diagnostics.EventLog.Application.WriteTrace($"Attempted to start a job which references a nonexistant item. Ignoring. JobContext: {jobContext.ToString()}");
                        return;
                    }

                    if (RunAsOwner)
                    {
                        var owner = scheduledItem.SecurityOwner;

                        if (owner == null)
                        {
                            var message = $"Unable to start scheduled job as import configuration has no owner";
                            Diagnostics.EventLog.Application.WriteError($"StartImportJob.Execute: {message}. {scheduledItem.Id}");
                            throw GenerateJobException(message, scheduledItem);
                        }

                        var identityInfo = new IdentityInfo(owner.Id, owner.Name);
                        var contextData  = new RequestContextData(RequestContext.GetContext());
                        contextData.Identity = identityInfo;

                        using (CustomContext.SetContext(contextData))
                        {
                            Execute(jobRef);
                        }
                    }
                    else
                    {
                        Execute(jobRef);
                    }
                }
            }
            catch (JobExecutionException ex)
            {
                EDC.ReadiNow.Diagnostics.EventLog.Application.WriteTrace("Job execution exception. Ex: {0}", ex.ToString());
                throw;  // The job has already handled the problem and taken action.
            }
            catch (PlatformSecurityException ex)
            {
                Diagnostics.EventLog.Application.WriteError($"Platform security exception thrown to scheduler. This should never occur. Ex: {ex}");
            }
            catch (Exception ex)
            {
                Diagnostics.EventLog.Application.WriteError("Exception thrown to scheduler. This should never occur and should be handled by the scheduled item. Ex: {0}", ex.ToString());
            }

            stopWatch.Stop();
            perfCounters.GetPerformanceCounter <AverageTimer32PerformanceCounter>(WorkflowPerformanceCounters.ScheduleJobDurationCounterName).AddTiming(stopWatch);
        }
        /// <summary>
        ///     Executed before the message is saved
        /// </summary>
        /// <param name="message"></param>
        /// <param name="postSaveAction">if not null an action run after the save. This happens even if the save is cancelled.</param>
        /// <returns>
        ///     True if the save is to be cancelled
        /// </returns>
        public bool BeforeSave(ReceivedEmailMessage message, out Action postSaveAction)
        {
            postSaveAction = null;

            /////
            // Check the message.
            /////
            if (message == null)
            {
                return(false);
            }

            var iCalMessage = message.As <ReceivedICalEmailMessage>( );

            /////
            // Ensure the message is a received iCal email message.
            /////
            if (iCalMessage == null)
            {
                return(false);
            }

            /////
            // The iCalUpdate field was set by the iCalMailMesssageFormatter that was called as part
            // of the ProcessInboxes action.
            /////
            if (string.IsNullOrEmpty(iCalMessage.ICalUpdate))
            {
                return(false);
            }

            /////
            // Read the iCal update.
            /////
            using (var sr = new StringReader(iCalMessage.ICalUpdate))
            {
                /////
                // Deserialize the string into the iCal object model.
                /////
                IICalendarCollection iCalendarCollection = iCalendar.LoadFromStream(sr);

                if (iCalendarCollection == null)
                {
                    return(false);
                }

                /////
                // Get the first calendar.
                /////
                IICalendar calendar = iCalendarCollection.FirstOrDefault( );

                if (calendar == null || calendar.Events == null)
                {
                    return(false);
                }

                /////
                // Get the first calendar event.
                /////
                IEvent calendarEvent = calendar.Events.FirstOrDefault( );

                if (calendarEvent == null)
                {
                    return(false);
                }

                /////
                // Make sure the calendar events UID is set.
                /////
                if (string.IsNullOrEmpty(calendarEvent.Uid))
                {
                    return(false);
                }

                EventEmail  eventEntity = null;
                Appointment appointment = null;

                /////
                // Find all sent iCal UID containers that correlate to the received calendar events UID.
                /////
                IEnumerable <ICalUidContainer> iCalUidContainers = Entity.GetByField <ICalUidContainer>(calendarEvent.Uid, ICalUidContainer.ICalUid_Field);

                if (iCalUidContainers != null)
                {
                    /////
                    // Get the first sent message.
                    /////
                    ICalUidContainer iCalUidContainer = iCalUidContainers.FirstOrDefault( );

                    if (iCalUidContainer != null && iCalUidContainer.CalendarEventEmail != null)
                    {
                        /////
                        // Get the original event email object that was used to create the sent iCal Email Message.
                        /////
                        eventEntity = iCalUidContainer.CalendarEventEmail.AsWritable <EventEmail>( );
                    }
                }

                bool modificationsMade = false;

                if (eventEntity == null)
                {
                    /////
                    // No existing event email so this is a new request.
                    /////
                    EntityRef type = GetEventCreationType(message);

                    eventEntity = type != null?Entity.Create(type).As <EventEmail>( ) : new EventEmail( );

                    appointment = Entity.Create <Appointment>();
                    eventEntity.EventEmailAppt = appointment;

                    modificationsMade = true;

                    eventEntity.Name = calendarEvent.Summary;

                    var calUidContainer = new ICalUidContainer
                    {
                        ICalUid = calendarEvent.Uid
                    };

                    eventEntity.CalendarId = calUidContainer;

                    string creatorEmailAddress = GetEmailAddress(message.EmFrom);

                    if (creatorEmailAddress != null)
                    {
                        EmailContact creatorEmailContact = FindEmailContact(creatorEmailAddress);

                        if (creatorEmailContact == null)
                        {
                            var mailAddress = new MailAddress(message.EmFrom);

                            creatorEmailContact = CreateEmailContact(creatorEmailAddress, mailAddress.DisplayName ?? creatorEmailAddress);
                        }

                        eventEntity.EventEmailCreator = creatorEmailContact;
                    }

                    foreach (IAttendee attendee in calendarEvent.Attendees)
                    {
                        string emailAddress = GetEmailAddress(attendee.Value.ToString( ));

                        if (emailAddress != null)
                        {
                            EmailContact emailContact = FindEmailContact(emailAddress);

                            if (emailContact == null)
                            {
                                CreateEmailContact(emailAddress, attendee.CommonName);
                            }

                            appointment.EventEmailAttendees.Add(emailContact.EmailContactOwner);
                        }
                    }

                    CreateAndSendAcceptance(calendar, iCalMessage, eventEntity);
                }
                else
                {
                    appointment = eventEntity.EventEmailAppt;

                    if (calendar.Method == Methods.Publish || calendar.Method == Methods.Request)
                    {
                        /////
                        // A REQUEST or PUBLISH means a new event arriving in the system.
                        /////
                        CreateAndSendAcceptance(calendar, iCalMessage, eventEntity);
                    }
                }


                eventEntity.ReceivedEmailMessages.Add(iCalMessage);


                /////
                // Start time.
                /////
                if (calendarEvent.Start != null)
                {
                    DateTime utcTime = calendarEvent.Start.Utc;

                    if (!Equals(utcTime, appointment.EventStart))
                    {
                        appointment.EventStart = utcTime;
                        modificationsMade      = true;
                    }
                }

                /////
                // End time.
                /////
                if (calendarEvent.End != null)
                {
                    DateTime utcTime = calendarEvent.End.Utc;

                    if (!Equals(utcTime, appointment.EventEnd))
                    {
                        appointment.EventEnd = utcTime;
                        modificationsMade    = true;
                    }
                }

                /////
                // All Day Event.
                /////
                if (appointment.EventIsAllDay == null || !Equals(calendarEvent.IsAllDay, appointment.EventIsAllDay.Value))
                {
                    appointment.EventIsAllDay = calendarEvent.IsAllDay;
                    modificationsMade         = true;
                }

                /////
                // Location.
                /////
                if (calendarEvent.Location != null)
                {
                    if (!Equals(calendarEvent.Location, appointment.EventLocation))
                    {
                        appointment.EventLocation = calendarEvent.Location;
                        modificationsMade         = true;
                    }
                }

                /////
                // Location.
                /////
                if (eventEntity.EventEmailAppt.EventEmailPriority == null || !Equals(calendarEvent.Priority, eventEntity.EventEmailAppt.EventEmailPriority))
                {
                    string priorityAlias;

                    if (calendarEvent.Priority <= 0)
                    {
                        /////
                        // Undefined.
                        /////
                        priorityAlias = null;
                    }
                    else if (calendarEvent.Priority <= 4)
                    {
                        /////
                        // High priority.
                        /////
                        priorityAlias = "core:highPriority";
                    }
                    else if (calendarEvent.Priority == 5)
                    {
                        /////
                        // Normal priority.
                        /////
                        priorityAlias = "core:normalPriority";
                    }
                    else if (calendarEvent.Priority <= 9)
                    {
                        /////
                        // Low priority.
                        /////
                        priorityAlias = "core:lowPriority";
                    }
                    else
                    {
                        /////
                        // Invalid priority.
                        /////
                        priorityAlias = null;
                    }

                    eventEntity.EventEmailAppt.EventEmailPriority = priorityAlias != null?Entity.Get <EventEmailPriorityEnum>(priorityAlias) : null;

                    modificationsMade = true;
                }

                /////
                // Status.
                /////
                string statusAlias = null;

                switch (calendarEvent.Status)
                {
                case EventStatus.Cancelled:
                    statusAlias = "core:eventStatusCancelled";
                    break;

                case EventStatus.Confirmed:
                    statusAlias = "core:eventStatusConfirmed";
                    break;

                case EventStatus.Tentative:
                    statusAlias = "core:eventStatusTentative";
                    break;
                }

                if (!string.IsNullOrEmpty(statusAlias))
                {
                    if (appointment.EventStatus == null || appointment.EventStatus.Alias != statusAlias)
                    {
                        appointment.EventStatus = Entity.Get <EventStatusEnum>(statusAlias);
                        modificationsMade       = true;
                    }
                }

                if (modificationsMade)
                {
                    CustomContext cc = null;

                    try
                    {
                        string timeZone = null;

                        if (eventEntity != null)
                        {
                            /////
                            // Find all sent iCal Email Messages that correlate to the received calendar events UID.
                            /////
                            IEnumerable <SentICalEmailMessage> sentICalEmailMessages = eventEntity.SentEmailMessages;

                            if (sentICalEmailMessages != null)
                            {
                                SentICalEmailMessage sentICalEmailMessage = sentICalEmailMessages.FirstOrDefault(sent => sent.ICalTimeZone != null);

                                if (sentICalEmailMessage != null)
                                {
                                    timeZone = sentICalEmailMessage.ICalTimeZone;
                                }
                            }
                        }

                        if (string.IsNullOrEmpty(timeZone))
                        {
                            if (calendar.TimeZones != null)
                            {
                                ITimeZone calendarTimeZone = calendar.TimeZones.FirstOrDefault( );

                                if (calendarTimeZone != null)
                                {
                                    timeZone = calendarTimeZone.TzId;
                                }
                            }
                        }

                        if (!string.IsNullOrEmpty(timeZone))
                        {
                            /////
                            // Set up a custom context just for the duration of this call.
                            /////
                            RequestContext currentRequestContext = RequestContext.GetContext( );

                            var data = new RequestContextData(currentRequestContext)
                            {
                                TimeZone = timeZone
                            };

                            cc = new CustomContext(data);
                        }

                        eventEntity.Save( );
                    }
                    finally
                    {
                        /////
                        // Ensure the custom context is disposed.
                        /////
                        if (cc != null)
                        {
                            cc.Dispose( );
                        }
                    }
                }
            }

            return(false);
        }
Beispiel #26
0
 /// <summary>
 ///     Sets the request context data associated with the service request.
 /// </summary>
 internal static void SetRequestContextData(RequestContextData contextData)
 {
     AppRequestContext.SetContext(contextData);
 }
Beispiel #27
0
        public void SuspendRestore()
        {
            var mockHandler = new Mock <DummyHandler>();

            var handler = new DummyHandler();

            var primaryUa = new UserAccount()
            {
                Name = Guid.NewGuid().ToString()
            };

            primaryUa.Save();
            var secondaryUa = new UserAccount()
            {
                Name = Guid.NewGuid().ToString()
            };

            secondaryUa.Save();

            var primaryId   = new IdentityInfo(primaryUa.Id, primaryUa.Name);
            var secondaryId = new IdentityInfo(secondaryUa.Id, secondaryUa.Name);

            var contextData = new RequestContextData(primaryId, RequestContext.GetContext().Tenant, "XYZ", secondaryId)
            {
                TimeZone = "XYZTZ"
            };

            var oldContext = new RequestContextData(RequestContext.GetContext());

            try
            {
                RequestContext.SetContext(contextData);


                using (new SecurityBypassContext())
                {
                    // Suspend
                    IEntity        suspendedtask;
                    BackgroundTask bgTask;


                    bgTask = handler.ToBackgroundTask(new DummyParams()
                    {
                        S = "SuspendRestore"
                    });

                    suspendedtask = handler.CreateSuspendedTask(bgTask);
                    suspendedtask.Save();

                    Assert.That(handler.annotateSuspendedTask_calls, Is.EqualTo(1));

                    var castTask = suspendedtask.As <SuspendedTask>();
                    Assert.That(castTask.StCulture, Is.EqualTo("XYZ"));
                    Assert.That(castTask.StTimezone, Is.EqualTo("XYZTZ"));
                    Assert.That(castTask.StIdentity.Id, Is.EqualTo(primaryUa.Id));
                    Assert.That(castTask.StSecondaryIdentity.Id, Is.EqualTo(secondaryUa.Id));

                    IEnumerable <BackgroundTask> restoredTasks;

                    //Restore
                    restoredTasks = handler.RestoreSuspendedTasks();

                    Assert.That(handler.restoreTaskData_Calls, Is.EqualTo(1));
                    Assert.That(restoredTasks.Count(), Is.EqualTo(1));

                    var context = restoredTasks.First().Context;

                    Assert.That(context.Culture, Is.EqualTo("XYZ"));
                    Assert.That(context.TimeZone, Is.EqualTo("XYZTZ"));
                    Assert.That(context.Identity.Id, Is.EqualTo(primaryId.Id));
                    Assert.That(context.SecondaryIdentity.Id, Is.EqualTo(secondaryId.Id));

                    var parameter = restoredTasks.First().GetData <DummyParams>();
                    Assert.That(parameter.S, Is.EqualTo("restored"));
                }
            }
            finally
            {
                RequestContext.SetContext(oldContext);
            }
        }
        /// <summary>
        ///     Gets the request context data factory implementation.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns>RequestContextData.</returns>
        private IdentityProviderContextCacheValue GetRequestContextDataFactoryImpl(IdentityProviderContextCacheKey key)
        {
            IdentityProviderContextCacheValue cacheValue;

            var isSystem = key.IdentityProviderId == WellKnownAliases.CurrentTenant.ReadiNowIdentityProviderInstance;

            QueryBuild queryResult = GetSql(isSystem);

            using (var dbContext = DatabaseContext.GetContext())
            {
                using (var command = dbContext.CreateCommand(queryResult.Sql))
                {
                    command.AddParameterWithValue("@identityProviderUser", key.IdentityProviderUserName, 500);

                    if (!isSystem)
                    {
                        command.AddParameterWithValue("@identityProviderId", key.IdentityProviderId);
                    }
                    dbContext.AddParameter(command, "@tenant", DbType.Int64, key.TenantId);

                    if (queryResult.SharedParameters != null)
                    {
                        foreach (var parameter in queryResult.SharedParameters)
                        {
                            dbContext.AddParameter(command, parameter.Value, parameter.Key.Type, parameter.Key.Value);
                        }
                    }

                    using (var reader = command.ExecuteReader())
                    {
                        if (!reader.Read())
                        {
                            return(null);
                        }

                        var userAccountId             = reader.GetInt64(0);
                        var userAccountName           = reader.GetString(1);
                        var identityProviderId        = isSystem ? key.IdentityProviderId : reader.GetInt64(2);
                        var identityProviderUserId    = isSystem ? userAccountId : reader.GetInt64(3);
                        var identityProviderTypeAlias = isSystem ? "core:readiNowIdentityProvider" : "core:" + reader.GetString(4);

                        int  accountStatusColumnIndex = isSystem ? 2 : 5;
                        long accountStatusId          = -1;

                        if (!reader.IsDBNull(accountStatusColumnIndex))
                        {
                            accountStatusId = reader.GetInt64(accountStatusColumnIndex);
                        }

                        var identityInfo = new IdentityInfo(userAccountId, userAccountName)
                        {
                            IdentityProviderId        = identityProviderId,
                            IdentityProviderUserId    = identityProviderUserId,
                            IdentityProviderTypeAlias = identityProviderTypeAlias
                        };
                        var tenantInfo = new TenantInfo(key.TenantId);

                        var contextData = new RequestContextData(identityInfo, tenantInfo,
                                                                 CultureHelper.GetUiThreadCulture(CultureType.Specific));

                        cacheValue = new IdentityProviderContextCacheValue(contextData, accountStatusId);

                        if (CacheContext.IsSet())
                        {
                            using (CacheContext cacheContext = CacheContext.GetContext())
                            {
                                cacheContext.Entities.Add(userAccountId);
                                cacheContext.Entities.Add(identityProviderId);
                                if (identityProviderUserId != userAccountId)
                                {
                                    cacheContext.Entities.Add(identityProviderUserId);
                                }
                            }
                        }
                    }
                }
            }

            return(cacheValue);
        }
        /// <summary>
        ///     Sets the request context.
        /// </summary>
        private void SetRequestContext( )
        {
            RequestContext context = RequestContext.GetContext( );

            if (context != null && context.IsValid && context.Tenant?.Name != null)
            {
                if (context.Tenant.Name.Equals(TenantName, StringComparison.OrdinalIgnoreCase))
                {
                    /////
                    // Context already set.
                    /////
                    return;
                }
            }

            RequestContextData contextData;

            /////
            // See if the request context has been cached.
            /////
            if (!RequestContextCache.TryGetValue(TenantName, out contextData))
            {
                if (TenantName.Equals(SpecialStrings.GlobalTenant))
                {
                    var tenantInfo   = new TenantInfo(0);
                    var identityInfo = new IdentityInfo(0, SpecialStrings.SystemAdministratorUser);

                    contextData = new RequestContextData(identityInfo, tenantInfo, CultureHelper.GetUiThreadCulture(CultureType.Neutral));
                }
                else
                {
                    /////
                    // Set system administrators context to retrieve the tenant.
                    /////
                    RequestContext.SetSystemAdministratorContext( );

                    /////
                    // Retrieve the requested tenant.
                    /////
                    Tenant tenant = TenantHelper.Find(TenantName);
                    RequestContext.SetTenantAdministratorContext(tenant.Id);
                    UserAccount userAccount = Entity.GetByField <UserAccount>(SpecialStrings.SystemAdministratorUser, false, new EntityRef("core", "name")).FirstOrDefault() ?? Entity.GetByField <UserAccount>(SpecialStrings.TenantAdministratorUser, false, new EntityRef("core", "name")).FirstOrDefault();

                    if (userAccount == null)
                    {
                        throw new EntityNotFoundException("The 'Administrator' account for tenant '" + TenantName + "' could not be found.");
                    }

                    /////
                    // Set the context data
                    /////
                    var identityInfo = new IdentityInfo(userAccount.Id, userAccount.Name);
                    var tenantInfo   = new TenantInfo(tenant.Id);
                    contextData = new RequestContextData(identityInfo, tenantInfo, CultureHelper.GetUiThreadCulture(CultureType.Neutral));
                }

                RequestContextCache[TenantName] = contextData;
            }

            RequestContext.SetContext(contextData);
        }