mandag den 18. juni 2012

Remote Desktop and Claimsbased authentication

I have had a wet dream for a long time, about implementing WIF/Claimsbased authentication into Windows Credential Provider/Remote Desktop. I don’t really care weather it could be though the RDP Website and/or directly on the Windows Server.

If we want to implement claims based authentication in corporation with remote desktop we need to consider what scenario this makes sense for, and how the logon process should be. Doing passive authentication in a browser, the user gets redirected to an identity provider and validated, has a SAML token issued and posted back to the website. Validation at the Identity Provider could also involve redirecting the user to yet another Identity provider (Microsoft Azure ACS, another ADFS 2.0 server, Google ID, Facebook and such) and the all this without the original website knowing anything about this, all it cares about is getting a SAML token from its trusted Identity Provider.

Doing Active Federation, lets say, from a Windows Application, we (could) ask the user how he wants to be validated and then though Kerberos, Certificates or Username/Password send the users credentials to the Identity Provider on behalf of the user and get’s back a SAML token. If the user want to logon though Windows Live ID in this scenario, we first need to ask the user for he's username/password ( this is where all alarm bells should go off for most security aware users ) and send this to login.live.com and by some kind of magic we get back a SAML token. We then ask out local Identity provider to Authorize us, using the SAML token from Windows Live ID and get back a SAML token and can continue the login process.

First of all, asking a user to type in a username and password for Facebook/windows Live ID/what ever on a “proprietary login page” is not good practice. Next, I doubt Microsoft/Facebook/whatever is allowing validating username and passwords though any kind of API, so the above will not work in any case.

So why is this even interesting, if its wrong ? Imaging the most common setup. Company A and Company B wants to collaborate and allow each other users access to certain resources. Instead of creating an Active Directory trust, Company A and B both install ADFS 2.0 and created a mutual trust between these. Now they can both add users to each others SharePoint 2010 and other Claims aware web applications. But what if they want to grant access to Microsoft CRM 2011, create Exchange mailbox's, allow access to Axapta 2009/2012 or use any other kind of application that rely on a Windows user in the Active Directory, then they need to map the User Principal name to locally created Active Directory users. How you do that, is beyond the scope of this post, but its doable and used many places.

Now image you want to allow users from Company A to access Company B’s Citrix XenApp or Remote Desktop servers. So User1 from Company A also have a User account in Company B, but he doesn’t know the password for that account. To give the whole Single Sing-on experience all he needs to know is the username and password to he’s own AD account in Company A.

You might think that implementing Claimsbased authentication on Remote Desktop WebApp is easy, and to be honest, it is. it just doesn’t work. The reason is, when you login to RDWeb the webpage loads an instance of your locally installed Remote Desktop client, though JavaScript/ActiveX and feeds it, the username and password you logged in with. So after implementing Claimsbased authentication in enabling it to use the c2wts service ( Claims to Windows Token Service ) you WILL get the correct list of application, but when ever you launch any of those, you will be prompted to login with a real windows username and password, and the whole concept falls apart. See this post

If you rely on Citrix XenApp you could implement the solution explained here, but that will not work with Remote Desktop. The solution explained there, will not work for user accessing the solution with PNAgent installed locally either ( PDA, Tablets, Thin Clients or what ever ) so an alternative solution will need to rely on replacing the Credential Provider ( called Gina pre windows vista ).

I came across this blog post and I really really wish I was better a coding C++ so I could create this my self. I can do hello world and maybe write to a text file, but this is just to much for my skillset. Google is not much help here, but you will probably come across www.pgina.org at some point.

This will not be completely what I wanted, but at least it’s a few steps in the right direction. Pgina is a cool, yet in some ways limited implementation of a Gina/Credential Provider that send events back to a Service written in .NET 4.0, you can then develop plugins that gets loaded into this service and react/modify things doing the login process. It come bundled with tons of cute add-ons that can validate users though LDAP/Radius/SQL or even IMAP/POP3 . When I say it is limited, I do that, from the perspective that it could have been nice if they had implemented support for asking for more than just username and password. a 3rd field for a passcode to do RSA Token or SMS 2 factor validation would have been a very nice touch, but for now lets just focus on Claimsbased authentication.

So just to test my theory I installed Pgina on a server and wrote a simple add-on to Pgina, that would take what ever the user types in, validate it against and Identity Provider, find the user based on the UPN claim in the local Active Directory and then log the user on.

image

Doing login, no matter what, it all have to end up with win logon getting a valid username and password. But in a world of claims based authentication we don’t have the password. God knows how Citrix manage to get a user logged on purely based on a Kerberos Ticket, and I would love to see this implemented in Pgina too, but a even better solution would be if someone with more brains than me, could write an Authentication Package as explained by Steve Syfuhs in he's blog post. But for now, we focus on the scenario where a user from Company A logs on to a Server inside Company B and the user have an account in the local AD with same UPN.
What I do here is validate what ever the user types in,
1) by asking for a SAML token from the remote Identity Provider.
2) If I get a token back, I extract the User Principal name and search the local Active Directory for such an user.
3) I then validate that the password the user typed is also the password the local Active Directory account, and if login fails, I reset the password and set the login password to this.

Since the context the login process run as, does not have permission to look up in the local AD and/or reset passwords, we also need to tell the PGina addon what username and password to use when talking to AD

image

Finally, since RDP will try to Negotiate security (the popup for credentials before you are connected) and we want PGina to handle this, you need to open Remote Desktop Session Host Configuration and set it to RDP Security Layer

image

And voila, we just logged on to Remote Desktop using Claims based authentication.

4 kommentarer:

  1. How can I get a copy of the plugin you wrote for pgina?
    -Chris @ SecureAuth

    SvarSlet
  2. hey Chris.

    The code is a little "messy" but feel free to have a look. https://skadefro.blob.core.windows.net/public/WIFCP.zip

    SvarSlet
  3. Hej Allan, kan man hyre dig til at kigge på denne løsning hos os? Vi vil gerne have claims login til at virke for et 2012r2 rds miljø.

    SvarSlet
    Svar
    1. Gerne, men mig bekendt findes der ikke nogle løsning som kan det.

      Microsoft har selv lavet, en super fed løsning som kan men så virker det kun imod microsofts egne RD servere ( https://www.remoteapp.windowsazure.com/en/ ), men det hjælper jo ikke alle dem som ikke føler at alt skal ligge i microsoft sky.

      Alternativt kan man skrive sin egen kode, og så kommer den store kamp. Hvor i "kæden" ønsker man at gøre tingene anderledes. Skal vi bruge en Custom RDP klient, lige som Microsoft har valgt at gøre ?
      Skal vi skrive en custom Credential Provider ( tidligere kaldt GINA ) og enten authentikere på vegne af brugeren imod en STS ( ikke særlig sikkert, men illustreret i min kode oven over ) eller lave nogle krump spring for at rendere en browser og så samle en SAML token op den vej. Eller man kunne gå den eksotiske vej og prøve og misbruge nogle af mulighederne for network level authentication, men det ville nok ende ud med at kræve en custom klient alligevel, nu jeg tænker lidt over det.

      Det alt overskyggende problem er at en standard RDP klient kun kan bede om 3(4 hvis vi tæller domain med) informationer, men vi har brug for at rendere en browser hvis det skal være en SIKKER løsning.
      Så kunne vi skube opgaven med at rendere en browser ud til GINA/Credential provider, men det understøtter den slet ikke, og så skal man lave nogle weird krumspring med at logge brugeren midlertidigt på, med en custom shell osv. og det åbner i sig selv en lang række issues.

      Lige nu, har jeg ikke tiden til, i min fritid, at udvikle en custom rdp klient og tilhørende Credential Provider, som vil kunne logge en bruger sikkert og forsvarligt på via RD og/eller RD Gateway. Og skal man det, hvad så med Windows Phone Users ? hvad med Ipad, android osv. osv. osv.

      Slet