WAP & ADFS the persistent cookie conundrum
I recently did some work with WAP 2012R2 (Web Application Proxy) and ADFS 3.0 (Active Directory Federation Services) looking into how the different timeout values work in conjunction with publishing internal legacy applications to the intrawebz. This using IWA (Integrated Windows Authentication) for the backend, and that meant setting up KCD (Kerberos Constrained Delegation) between WAP and the application servers. I will not focus on that configuration here. I am more interested in how the security mechanisms work, and how that impacts how to configure the different time constraint values for logon and session related parameters.
Tristan has a great post here about how the different parameters work for a pure token based implementation. Meaning no legacy IWA applications involved.
Also you will need KB3020813 on the WAP severs to expose the PersistentAccessCookieExpirationTimeSec parameter I use in my tests.
Web SSO Token : ADFS value that controls the active duration of SSO (Single-Sign-On). Meaning no need for user to input credentials inside this window. Global value that cannot be set per published application.
WAP Token : ADFS value that controls the duration the authenticated session for the published application on WAP can live without having to go back to ADFS for renewal. Global value for WAP.
EdgeAccessCookie : Token stored in the browser of the user. This is issued by WAP, and is the ticket for accessing the legacy application. So instead of having a Kerberos ticket, we now have a cookie instead. WAP is holding the Kerberos token for the user gotten through KCD.
PersistentAccessCookieExpirationTimeSec : WAP value that changes the EdgeAccessCookie from a session cookie to a time constrained persistent cookie. The value set for this parameter will be the lifetime of the cookie in seconds. This value can be set per published application.
My goal was to see if I could balance the end user experience for the legacy application and security. In my implementation I’m using MFA (MultiFactor Authentication) through ADFS with the Duo plugin.
What I observed was a bit lack of subtlety for controlling different user behavior with the existing settings. The only value that mattered in the end was the value of Web SSO token, as expiation of this would determine when the user needed to login anew. This is the current limitation of the Window Server 2012R2 WAP version, though with Server 2016 right around the corner, there are some new settings there that might help. Though I will come to that in a later post.
Back to the current discussion; there are some details that are good to know about how all the different values interact.
Setting PersistentAccessCookieExpirationTimeSec only changes the EdgeAccessCookie from a session cookie to a persistent cookie with a set lifetime. Though if you have configured your browser to save your open tabs at closure (same for Chrome, Firefox, Edge and IE), it does not matter if the EdgeAccessCookie is a session or a persistent one, as both will let the user directly back into the backend application without having to login anew (as long as the Web SSO token is not expired). Though if your browser is not set up to save the open tabs, the session cookie gets deleted when you close it. Opening it up again, the user will need to log back in to ADFS to be able to access the backend application. Though with a persistent cookie (as long as it has not expired) the user will be let back in.
Also even if you set a large value for PersistentAccessCookieExpirationTimeSec, the EdgeAccessCookie will not be given that value if the WAP token and Web SSO token has a smaller value. It will be set to the lowest value of either the WAP or Web SSO token. So that means you will need to set both Web SSO and WAP token value higher, and as these are global, it will impact all published applications. This means all applications get longer exposure in Kiosk scenarios having to do this. This will be a balancing act, and depends on what your organization finds acceptable.
In the end this setting was therefore not so helpful with my balance goal. Though I can see it is needed in scenarios with Sharepoint, and needing to support editing Office documents. It would get annoying for the end user if they needed to input credentials multiple times opening, saving and such of these documents.
To recap how all these tokens fit together:
The EdgeAccessCookie will only ever be able to live as long as the WAP token lifetime value is set to. This even if you try to set the PersistentAccessCookieExpirationTimeSec value to a higher one. When the WAP token expires, the users browser will be handed back to ADFS by WAP (browser redirect). What happens next depends on the Web SSO token, if this is still valid a new WAP token will be issued and the end user is none the wiser. Though if the token has expired, the user will need to log in again through the ADFS login page to get the WAP and Web SSO token renewed. Then the user is back in and can continue being productive.
So just to keep things hassle free I would set Web SSO = WAP token and be done with it.
If thing could only be so easy. This will be fine as long as you don’t need there to be more frequent user disabled checks. If this is needed, you will have to lower the value of the WAP token lifetime to something that is more in line with that constraint. Then there will be more frequent handoffs back to ADFS (as ADFS will check if the user account is disabled when renewing the WAP token) and user account checks with AD done. Though setting the WAP token lifetime lower, you might see issues with SharePoint stuff (depending on version) when WAP tries to hand the browser connection with SP back to ADFS. All kinds of breakage might ensue. It is never easy is it?
I have not even touched KMSI (Keep Me Signed In) or device join, as these also have their separate tokens to take into consideration. But I am just rambling now.
How to configure the things we have talked about here with Powershell:
Set-ADFSProperties -SsoLifetime <value in minutes>
Set-AdfsWebApplicationProxyRelyingPartyTrust -TokenLifetime <value in minutes>
Get-WebApplicationProxyApplication <NameofPublishedApp> | Set-WebApplicationProxyApplication -PersistentAccessCookieExpirationTimeSec <value in seconds>