/// <summary>
        /// MVC and private use only.
        /// </summary>
        public static void SetFormsAuthCookieAndUser(FormsAuthCapableUser user)
        {
            if (AppRequestState.Instance.ImpersonatorExists)
            {
                UserImpersonationStatics.SetCookie(user);
            }
            else
            {
                var strictProvider = SystemProvider as StrictFormsAuthUserManagementProvider;

                // If the user's role requires enhanced security, require re-authentication every 12 minutes. Otherwise, make it the same as a session timeout.
                var authenticationDuration = (strictProvider?.AuthenticationTimeoutInMinutes).HasValue
                                                                     ? TimeSpan.FromMinutes(strictProvider.AuthenticationTimeoutInMinutes.Value)
                                                                     : user.Role.RequiresEnhancedSecurity ? TimeSpan.FromMinutes(12) : SessionDuration;

                var ticket = new FormsAuthenticationTicket(user.UserId.ToString(), false /*meaningless*/, (int)authenticationDuration.TotalMinutes);
                AppRequestState.AddNonTransactionalModificationMethod(() => setFormsAuthCookie(ticket));
            }
            AppRequestState.Instance.SetUser(user);
        }
        protected override void loadData()
        {
            var logInPb =
                PostBack.CreateFull(
                    actionGetter:
                        () =>
                        new PostBackAction( user.MustChangePassword ? ChangePassword.Page.GetInfo( info.ReturnUrl ) as ResourceInfo : new ExternalResourceInfo( info.ReturnUrl ) ) );
            var newPasswordPb = PostBack.CreateFull( id: "newPw", actionGetter: getSendNewPasswordAction );

            var registeredTable = EwfTable.Create( caption: "Registered users" );
            registeredTable.AddItem(
                new EwfTableItem(
                    ( "You may log in to this system if you have registered your email address with " + FormsAuthStatics.SystemProvider.AdministratingCompanyName ).ToCell(
                        new TableCellSetup( fieldSpan: 2 ) ) ) );

            emailAddress = new DataValue<string>();
            var emailVl = new BasicValidationList();
            registeredTable.AddItem(
                new EwfTableItem( "Email address", emailAddress.GetEmailAddressFormItem( "", "Please enter a valid email address.", emailVl ).ToControl() ) );
            logInPb.AddValidations( emailVl );
            newPasswordPb.AddValidations( emailVl );

            var password = new DataValue<string>();
            registeredTable.AddItem(
                new EwfTableItem(
                    "Password",
                    FormItem.Create(
                        "",
                        new EwfTextBox( "", masksCharacters: true ),
                        validationGetter: control => new EwfValidation( ( pbv, v ) => password.Value = control.GetPostBackValue( pbv ), logInPb ) ).ToControl() ) );

            if( FormsAuthStatics.PasswordResetEnabled ) {
                registeredTable.AddItem(
                    new EwfTableItem(
                        new PlaceHolder().AddControlsReturnThis(
                            "If you are a first-time user and do not know your password, or if you have forgotten your password, ".GetLiteralControl(),
                            new PostBackButton( newPasswordPb, new TextActionControlStyle( "click here to immediately send yourself a new password." ), usesSubmitBehavior: false ) )
                            .ToCell( new TableCellSetup( fieldSpan: 2 ) ) ) );
            }

            ph.AddControlsReturnThis( registeredTable );

            var specialInstructions = EwfUiStatics.AppProvider.GetSpecialInstructionsForLogInPage();
            if( specialInstructions != null )
                ph.AddControlsReturnThis( specialInstructions );
            else {
                var unregisteredTable = EwfTable.Create( caption: "Unregistered users" );
                unregisteredTable.AddItem( new EwfTableItem( "If you have difficulty logging in, please " + FormsAuthStatics.SystemProvider.LogInHelpInstructions ) );
                ph.AddControlsReturnThis( unregisteredTable );
            }

            EwfUiStatics.SetContentFootActions( new ActionButtonSetup( "Log In", new PostBackButton( logInPb ) ) );

            var logInMethod = FormsAuthStatics.GetLogInMethod(
                this,
                emailAddress,
                password,
                getUnregisteredEmailMessage(),
                "Incorrect password. If you do not know your password, enter your email address and send yourself a new password using the link below.",
                logInPb );
            logInPb.AddModificationMethod( () => user = logInMethod() );
        }
        private static void setFormsAuthCookieAndUser( FormsAuthCapableUser user )
        {
            if( AppRequestState.Instance.ImpersonatorExists )
                UserImpersonationStatics.SetCookie( user );
            else {
                var strictProvider = SystemProvider as StrictFormsAuthUserManagementProvider;

                // If the user's role requires enhanced security, require re-authentication every 12 minutes. Otherwise, make it the same as a session timeout.
                var authenticationDuration = strictProvider != null && strictProvider.AuthenticationTimeoutInMinutes.HasValue
                                                 ? TimeSpan.FromMinutes( strictProvider.AuthenticationTimeoutInMinutes.Value )
                                                 : user.Role.RequiresEnhancedSecurity ? TimeSpan.FromMinutes( 12 ) : SessionDuration;

                var ticket = new FormsAuthenticationTicket( user.UserId.ToString(), false /*meaningless*/, (int)authenticationDuration.TotalMinutes );
                AppRequestState.AddNonTransactionalModificationMethod( () => setFormsAuthCookie( ticket ) );
            }
            AppRequestState.Instance.SetUser( user );
        }
        /// <summary>
        /// Call this during LoadData.
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="vl"></param>
        /// <param name="availableRoles">Pass a restricted list of <see cref="Role"/>s the user may select. Otherwise, Roles available 
        /// in the System Provider are used.</param>
        /// <param name="validationPredicate">If the function returns true, validation continues.</param>
        public void LoadData( int? userId, ValidationList vl, List<Role> availableRoles = null, Func<bool> validationPredicate = null )
        {
            availableRoles = ( availableRoles != null ? availableRoles.OrderBy( r => r.Name ) : UserManagementStatics.SystemProvider.GetRoles() ).ToList();

            user = userId.HasValue ? UserManagementStatics.GetUser( userId.Value, true ) : null;
            if( includePasswordControls() && user != null )
                facUser = FormsAuthStatics.GetUser( user.UserId, true );

            Func<bool> validationShouldRun = () => validationPredicate == null || validationPredicate();

            var b = FormItemBlock.CreateFormItemTable( heading: "Security Information" );

            b.AddFormItems(
                FormItem.Create(
                    "Email address",
                    new EwfTextBox( user != null ? user.Email : "" ),
                    validationGetter: control => new EwfValidation(
                                                     ( pbv, validator ) => {
                                                         if( validationShouldRun() )
                                                             Email = validator.GetEmailAddress( new ValidationErrorHandler( "email address" ), control.GetPostBackValue( pbv ), false );
                                                     },
                                                     vl ) ) );

            if( includePasswordControls() ) {
                var group = new RadioButtonGroup( false );

                var keepPassword = FormItem.Create(
                    "",
                    group.CreateInlineRadioButton( true, label: userId.HasValue ? "Keep the current password" : "Do not create a password" ),
                    validationGetter: control => new EwfValidation(
                                                     ( pbv, validator ) => {
                                                         if( !validationShouldRun() || !control.IsCheckedInPostBack( pbv ) )
                                                             return;
                                                         if( user != null ) {
                                                             Salt = facUser.Salt;
                                                             SaltedPassword = facUser.SaltedPassword;
                                                             MustChangePassword = facUser.MustChangePassword;
                                                         }
                                                         else
                                                             genPassword( false );
                                                     },
                                                     vl ) );

                var generatePassword = FormItem.Create(
                    "",
                    group.CreateInlineRadioButton( false, label: "Generate a " + ( userId.HasValue ? "new, " : "" ) + "random password and email it to the user" ),
                    validationGetter: control => new EwfValidation(
                                                     ( pbv, validator ) => {
                                                         if( validationShouldRun() && control.IsCheckedInPostBack( pbv ) )
                                                             genPassword( true );
                                                     },
                                                     vl ) );

                var newPassword = new DataValue<string>();
                var confirmPassword = new DataValue<string>();
                var newPasswordTable = EwfTable.Create( style: EwfTableStyle.StandardExceptLayout );
                newPasswordTable.AddItem(
                    new EwfTableItem(
                        "Password",
                        FormItem.Create(
                            "",
                            new EwfTextBox( "", masksCharacters: true, disableBrowserAutoComplete: true ) { Width = Unit.Pixel( 200 ) },
                            validationGetter: control => new EwfValidation( ( pbv, v ) => newPassword.Value = control.GetPostBackValue( pbv ), vl ) ).ToControl() ) );
                newPasswordTable.AddItem(
                    new EwfTableItem(
                        "Password again",
                        FormItem.Create(
                            "",
                            new EwfTextBox( "", masksCharacters: true, disableBrowserAutoComplete: true ) { Width = Unit.Pixel( 200 ) },
                            validationGetter: control => new EwfValidation( ( pbv, v ) => confirmPassword.Value = control.GetPostBackValue( pbv ), vl ) ).ToControl() ) );

                var providePasswordRadio = group.CreateBlockRadioButton( false, label: "Provide a " + ( userId.HasValue ? "new " : "" ) + "password" );
                providePasswordRadio.NestedControls.Add( newPasswordTable );
                var providePassword = FormItem.Create(
                    "",
                    providePasswordRadio,
                    validationGetter: control => new EwfValidation(
                                                     ( pbv, validator ) => {
                                                         if( !validationShouldRun() || !control.IsCheckedInPostBack( pbv ) )
                                                             return;
                                                         FormsAuthStatics.ValidatePassword( validator, newPassword, confirmPassword );
                                                         var p = new Password( newPassword.Value );
                                                         Salt = p.Salt;
                                                         SaltedPassword = p.ComputeSaltedHash();
                                                         MustChangePassword = false;
                                                     },
                                                     vl ) );

                b.AddFormItems(
                    FormItem.Create( "Password", ControlStack.CreateWithControls( true, keepPassword.ToControl(), generatePassword.ToControl(), providePassword.ToControl() ) ) );
            }

            b.AddFormItems(
                FormItem.Create(
                    "Role",
                    SelectList.CreateDropDown(
                        from i in availableRoles select SelectListItem.Create( i.RoleId as int?, i.Name ),
                        user != null ? user.Role.RoleId as int? : null ),
                    validationGetter: control => new EwfValidation(
                                                     ( pbv, validator ) => {
                                                         if( validationShouldRun() )
                                                             RoleId = control.ValidateAndGetSelectedItemIdInPostBack( pbv, validator ) ?? default ( int );
                                                     },
                                                     vl ) ) );

            Controls.Add( b );
        }