vasiliyfomichev / Sitecore-ADFS-Authenticator-Module

The ADFS Authenticator is a rewritten version of the Fed Authenticator module in .NET 4.5, using the new System.IdentityModel namespaces, with specific configuration for the Active Directory Federated Services (ADFS). The module implements the following additional features: ADFS Logout Authenticating users as Administrators
http://www.cmsbestpractices.com
MIT License
17 stars 8 forks source link

Log in of real users synched with AD module #1

Open DiegoSSJ opened 9 years ago

DiegoSSJ commented 9 years ago

Hi!

We have just set up ADFS Auth module and AD synchronization. We had to use Forms authentication to log in users as real users instead of virtual users. This is in FederatedAuthenticationProvider.cs, where there is a check for the Federated session cookies:

if (!FederatedAuthentication.SessionAuthenticationModule.TryReadSessionTokenFromCookie(out sessionToken)) 
FormsAuthentication.SetAuthCookie(userName, persistent);

We had to make an exception for real users so that the Forms Authentication cookie was set, otherwise Sitecore kept on logging out the user.

Should this be done? If it is okay, then maybe it could be a good idea to push this change.

vasiliyfomichev commented 9 years ago

Hi @DiegoSSJ, just to make sure I'm on the same page, the change in code is to introduce the persistency flag instead of always having it as false?

DiegoSSJ commented 9 years ago

Hi Vasiliy!

The changes are:

    public override bool Login(string userName, bool persistent)
    {
    Assert.ArgumentNotNullOrEmpty(userName, "userName");
            if (!base.Login(userName, persistent))
                return false;
            SessionSecurityToken sessionToken;
            if (!FederatedAuthentication.SessionAuthenticationModule.TryReadSessionTokenFromCookie(out sessionToken))
                FormsAuthentication.SetAuthCookie(userName, persistent);
            return true;
        }

To

       public override bool Login(string userName, bool persistent)
        {
            Assert.ArgumentNotNullOrEmpty(userName, "userName");
            if (!base.Login(userName, persistent))
                return false;
            SessionSecurityToken sessionToken;
            if (!FederatedAuthentication.SessionAuthenticationModule.TryReadSessionTokenFromCookie(out sessionToken)
                || !User.FromName(userName,false).RuntimeSettings.IsVirtual)                
            {
                FormsAuthentication.SetAuthCookie(userName, persistent);
            }

            return true;
        }
        public override bool Login(User user)
        {
            Assert.ArgumentNotNull(user, "user");
            if (!base.Login(user))
                return false;

            SessionSecurityToken sessionToken;
            if (!FederatedAuthentication.SessionAuthenticationModule.TryReadSessionTokenFromCookie(out sessionToken))
                FormsAuthentication.SetAuthCookie(user.Name, false);
            StoreMetaData(user);
            return true;
        }

To

        public override bool Login(User user)
        {
            Assert.ArgumentNotNull(user, "user");
            if (!base.Login(user))
                return false;
            SessionSecurityToken sessionToken;
            if (!FederatedAuthentication.SessionAuthenticationModule.TryReadSessionTokenFromCookie(out sessionToken)
                || !user.RuntimeSettings.IsVirtual)
            {
                FormsAuthentication.SetAuthCookie(user.Name, false);
            }                
            StoreMetaData(user);
            return true;
        }

And

        public override void Logout()
        {
            base.Logout();
            RecentDocuments.Remove();
            SessionSecurityToken sessionToken;
            if (!FederatedAuthentication.SessionAuthenticationModule.TryReadSessionTokenFromCookie(out sessionToken))
            {
                FormsAuthentication.SignOut();
                ClearFormCookies();
            }
            FederatedAuthentication.SessionAuthenticationModule.SignOut();
        }

To

        public override void Logout()
        {
            base.Logout();
            RecentDocuments.Remove();
            SessionSecurityToken sessionToken;
            if (!FederatedAuthentication.SessionAuthenticationModule.TryReadSessionTokenFromCookie(out sessionToken)
                || !Context.User.RuntimeSettings.IsVirtual)
            {
                FormsAuthentication.SignOut();
                ClearFormCookies();
            }
            FederatedAuthentication.SessionAuthenticationModule.SignOut();
        }

This is because !FederatedAuthentication.SessionAuthenticationModule.TryReadSessionTokenFromCookie(out sessionToken is always false when the user is logged in and we need FormsAuthentication for real users.

rangler2 commented 9 years ago

Hi @DiegoSSJ

Thanks for your comment on the Sitecore Marketplace - I'm carrying on from Ben who left a comment saying he was being logged out immediately after logging in.

I tried making your changes from above but it made no difference in our situation. I don't think it applies to us because our users ARE virtual (as created by the ADFS module). Have you made some other changes in order to log users in as Real rather than Virtual users? It looks like the module is meant to work fine with virtual users.

This is what is happening for us:

image

The SSO posts back to the root of the site, which authenticates etc and redirects to /sitecore/shell/default.aspx but then this seems to think we are logged out and redirects to the loginPage of the "shell" site. (I commented out the config that makes this go to the ADFS logout.aspx page).

Any ideas would be much appreciated.

Which version of Sitecore has the module been tested working on? We're using Sitecore.NET 7.0 (rev. 140120).

Thanks Andy

DiegoSSJ commented 9 years ago

Hi, Andy

You can read my reply on the ADFS authenticator module page at the sitecore marketplace. It is off topic here.

rangler2 commented 9 years ago

Thanks for this @DiegoSSJ , we got it working in the end, logging in as real users.

I'd be interested to know where in the code you logged in as a real user rather than virtual. Did you do this in LoginHelper.cs in place of where it builds/logs in with a virtual user? This is what I did, but we had to add some code (provided by Sitecore Support) to create a Ticket and set a cookie, otherwise it would not stay logged in.

DiegoSSJ commented 9 years ago

Hi!

Have been away for some time, so I couldn't answer earlier.

Yes, exactly, we logged in as real user in LoginHelper.cs, we check if the user exists and then proceed to log in the user.

                if (User.Exists(userName))                
                {
                    var realUser = User.FromName(userName, true);

                    Boolean loginResult = AuthenticationManager.Login(realUser);                                            
                    // Behövs så att TicketManager körs, via allowLogintoShell = true
                    Boolean loginResult2 =  AuthenticationManager.Login(userName, true, true);

                    State.ClientLanguage = Context.User.Profile.ClientLanguage;

                    if (loginResult && loginResult2)
                        Log.Info("ADFS: User " + userName + " authenticated and logged in as existing user in Sitecore", this);
                    else Log.Info("ADFS: User " + userName + " failed to log in as existing user in Sitecore", this);

                }  

The code that we had to add to set the ticket and cookie is just what this issue is about, and you can see it above. I'm very interested in knowing which code Sitecore shared with you, as we were told to fix this ourselves considering this module is not officially supported by Sitecore. Would you mind sharing it?

Also, right now we have found a problem with setting the Sitecore client language cookie for AD synched users, we see the language preference is saved in the user profile but the language is not set. We suspect we should set some language cookie here at the ADFS log in, so that's what we are trying to fix right now. Again, would be interesting to know if the code Sitecore shared with you actually does this or how.

DiegoSSJ commented 9 years ago

Actually in the code above you see a line that says

State.ClientLanguage = Context.User.Profile.ClientLanguage;

That's what we want to test now to see if the language cookie is set.