Authenticating to SharePoint from iPhone and iPad
We wanted to publish our internal portal, running on SharePoint 2010, to company-approved mobile devices (we mostly have iPads and iPhones.) Since these devices are not sitting on the internal network we needed to publish the sites so they are available externally. We use Forefront Unified Access Gateway (UAG) from Microsoft for secure access. UAG is a software-based reverse proxy with built-in capabilities to publish SharePoint sites. A good place to start installing and configuration UAG is Ben-Ari articles and books on the subject http://blogs.technet.com/b/ben/archive/2010/12/29/sharepoint-publishing-concepts-and-considerations.aspx. other resources are available on the web as well http://bit.ly/XnBqHQ.
Smaller devices are good for many things, but typing user ID and passwords of any complexity are tasks that make most corporate users cringe. Since we “own” the device and can impose policy and push data and links into it, we have more options to offer better login experience than an open web site.
We are also bound by security and compliance challenges. We require two-form authentication and our policy enforces a screen lock password. So, we need to come up with a second form of authentication to satisfy our compliance requirement.
Besides two-form authentication we need to provide authorization and personalization so that we can identify each user individually and as part of a role to, and how them relevant content such as personal bookmarks and personal “activity streams” on the portal. These are not uncommon requirements in accessing a company portal.
Certificates – Multiple Authentication Providers
Authenticating to IIS with personal certificate was introduce with IIS 6 and enhanced with more capabilities with IIS 7. Unfortunately SharePoint 2010 doesn’t support such authentication directly. One way to use certificate to authenticate into SharePoint 2010 is to use its support for multiple authentication providers and authenticate against a third-part (such as ADFS) that accepts certificates.
The inherit problem with multiple authentication providers approach in the context of our requirements is that identities from different authentication providers cannot be combined. So, if Joe Smith logs in to the portal from his laptop (with a Kerberos ticket) and then connects from his iPhone, using a certificate via ADFS, SharePoint will see two different tokens. Without massive coding effort Joe will not be authorized the same way from his iPhone, nor will he have the same personalized content when logging in with each authentication provider. (Microsoft support claims that changes to Claims to Windows Token service (CW2T) API makes it possible to support this in SharePoint 2013, but I did not personally try it.)
I’m not complaining about the available technology. ADFS and multiple authentication provides some fantastic features, such as the ability to easily integrate external users into your portal. I’m just saying that this is not the right technology to allow mobile device authentication for your domain users in SharePoint 2010. (I do have a gripe about ADFS for its inability to connect to AD-LDS data sources, but I have a blog in the making that will show how to write your own STS to provide that capability.)
Certificates – UAG
The approach that proved successful in accepting personal certificates was by using UAG to authenticate into SharePoint. Users access a UAG trunk for accessing the SharePoint portal. The Trunk is responsible for authentication and can also provide some levels of authorization if needed (SharePoint authorization story is much more compelling..)
Once UAG authenticates the user, either by passing credentials or by accepting a certificates, it gets a Kerberos ticket for the user to authenticate back to SharePoint. Once the user is logged in to UAG trunk, UAG is handling the interaction with the SharePoint. UAG works on authenticating tno matter what application or page the user is accessing.
Setting up UAG to for certificate authentication
Before you begin this process, you need to install and configure UAG, create the UAG portal trunk, and publish your SharePoint application on that trunk. During that process you will create a connection to your AD in the UAG manager under Admin | Authentication and Authorization Servers. You can name that connection anything you want, and you will use that name later in this section. Let’s assume that you name the connection MyDomain. We list our DC explicitly and connect on port 3268 to get a list of all forest users from Global Catalog. Make sure that “default domain name” is empty. UAG will preprend the default domain to ALL users. However, we have different domains in our forest and want the correct domain prepeneded for each user. We will achieve that through code below..
You will also need a certificate issued and installed on your favorite device with the root certificates for the certificate authority also installed on the device (the entire chain)
Make sure that the UAG server contains the root certificate of your certificate authority as well.
Next, we are going to enable certificate authentication. To do that, follow the instructions in the Forefront UAG manual here http://technet.microsoft.com/en-us/library/ee861163.aspx. These instructions will take you through copying and configuring the necessary files into ../von/InternalSite/Inc/CustomUpdate. When you are done, you should have 4 files under the CustomUpdate directory. If you have a trunk named SharePoint, and the repository connection named MyDomain, the files are:
The instructions takes you through 3 options for authentication: SubjectCN, SubjectEMAIL, and CertificateUPN. It leads you through the changes necessary to use each of these settings. SubjectCN and SubjectEMAIL assume that you have a CN and E in your subject line. E.g. Subject=CN=dummy,EMAILemail@example.com. CN is always there, but email may not be. CertificateUPN assumes that UPN is present in the Subject Alternative Name field. I was not able to make it work despite having a UPN in the SAN.
What I’m going to demonstrate is some more examples of manipulating the certificate to derive more data from the certificate and from the AD connection to authenticate users in more complicated scenarios.
Working with certificate fields
I am going to demonstrate 3 additional manipulations of the certificate
- Our certificate CN are not the same CN in active directory and we don’t have EMAIL in the subject. Instead we have Email field in the SAN field. We are going to extract that and use it for authentication
- We have 2 domains in our forest (USA, and EUR). for SSO I’m going to need the format domain.dc\username. I’m going to
- get the domain from Active Directory
- inject the domain name into the user name
If I didn’t do that, I will need two separate trunks set up – one for each domain in the forest.
WARNING: Always have the last set of files saved as a backup. Developing in this environment can be very frustrating at times to developers used to advanced IDE with ReSharper. Syntax errors will result in the system just not processing login. The process of changing UAG includes “Activating” your trunk and waiting for it to synchronize with TMG. So, be patient before you conclude what effects a change had had on your setup. Finally, take baby steps. Learn to crawl before you walk, etc.
Before you do any manipulation to certificate fields, it’s nice to have a list of the fields in a certificate. So, we start by writing it out to a file.
This is the first file that gets processed as part of the cert.asp file. I’m going to use two functions that I found elsewhere (can’t remember where, but I’d like to attribute them to the right owner.) The first, is a simple VB function to write to a file
Function WriteToFile(FileName, Contents, Append) on error resume next if Append = true then iMode = 8 else iMode = 2 end if set oFs = server.createobject("Scripting.FileSystemObject") set oTextFile = oFs.OpenTextFile(FileName, iMode, True) oTextFile.WriteLine Contents oTextFile.Close set oTextFile = nothing set oFS = nothing end function
We can now call the function to write out all the elements of the certificate
sFile = "e:\log\cert.txt" For Each strKey in Request.ClientCertificate WriteToFile sFile, strkey, true Next
Make sure that the log directory exists and that Everyone has full access permission to it to prevent errors. Also make sure that your code is between <% %>. Now activate your site and try to log in with your device. Open the log file and you should see a list of all certificate keys. You will notice that the keys have a hierarchy. So, you will see SUBJECT, SUBJECTCN, SUBJECTL etc if these exist on your Subject line in the ticket.
Next, we going to add a function to convert the binary Certificate field (SAN) to a string. Please note that this is a “hack”. The correct way to do it is to parse the field into a class (it’s in ASN1 format.) I have nor the patience nor the inclination for that, so I just hack it by extracting the string that I need.
I first add a function to convert the binary data in the SAN to a string
Function SimpleBinaryToString(Binary) 'SimpleBinaryToString converts binary data (VT_UI1 | VT_ARRAY Or MultiByte string) 'to a string (BSTR) using MultiByte VBS functions Dim I, S For I = 1 To LenB(Binary) S = S & Chr(AscB(MidB(Binary, I, 1))) Next SimpleBinaryToString = S End Function
Now I can convert the binary data in the SAN to a string and we are going to write that value to our file
cer=Request.ClientCertificate("Certificate") results = SimpleBinaryToString(cer) writeToFile sFile, results, false
Activate again and access the site with your device. You should see the value of the SAN as string in your text file. Most of it is gibberish, but the email address and UPN should be there. I write some string silly string parsing code to extract the email address (I’m not proud of it, but it works! the code is in the attached files) and then create a parameter to store the email address
cer=Request.ClientCertificate("Certificate") results = SimpleBinaryToString(cer) email = GetEmailFromCert(results) SetSessionParamWithType g_cookie,"CertificateEMAIL",email,CERTIFICATE_PARAM_TYPE
Of course, you need to activate, wait and login again to the site from your device. The last line in the code does two things: It creates a session parameter for CertificateEMAIL, and also surfaces the value into the session manager. To make sure that it works, open web monitor on your UAG server (http://localhost:50002/) and click on a a session (select the number of sessions and then the GUID of the session). Select the Parameters tab and filter for Certificate in the drop down. You should see the CertificateEMAIL parameter with the value derived from the SAN. This is a great way to inspect the extracted value and make changes as needed.
Repository file – MyDomain.inc
As part of SharePoint application setup, you should have already enabled Kerberos authentication. If you haven’t yet, do it now! in the first line of code in the file
KCDAuthentication_on = true
First, find the line that says param_email.Name = “SubjectCN”. Replace SubjectCN with CertificateEMAIL, the new parameter that we created in the previous step (you can call that parameter anything you want, by the way.) So the line should now read:
param_email.Name = "CertificateEMAIL"
further down there is a second param_email.Name = “”. We are going to set that to “email” and add a new parameter for the distinguishedName
set param_email = Server.CreateObject("UserMgrComLayer.Param") param_email.Name = "mail" set param_DN = Server.CreateObject("UserMgrComLayer.Param") param_DN.Name = "distinguishedName"
The first param is a session param, the second is the lookup value in AD. By creating the second set of parameters we are setting up a query for the values in AD.
Finally find the section that loops through the user parameters (for i = 0 to UBound(user_params)) and change it to the following
for i = 0 to UBound(user_params) if user_params(i).Name = param_UPN.Name then SetSessionParamWithType g_cookie,CERTIFICATE_UPN_PARAM,user_params(i).Value,CERTIFICATE_PARAM_TYPE else if user_params(i).Name = param_DN.Name then dn = user_params(i).Value domainPos = InStr(dn, "DC=") + 3 domain = Mid(dn, domainPos, InStr(domainPos, dn, ",") - domainPos) companyPos = InStr(domainPos + Len(domain) + 1, dn, "DC=") + 3 domain = domain & "." & Mid(dn, companyPos, Len(dn) - companyPos + 1) SetSessionParamWithType g_cookie,"Domain",domain,CERTIFICATE_PARAM_TYPE end if end if next
This code looks at a distinguishedName string that looks like the following
and sets a Session parameters – Domain – to “contoso.com”. You can test the results of the operation by activating again and inspecting the parameters under Certificate as above.
Finally, At the bottom of the file find the line:
insert the following code BEFORE that line:
set param_DN = Nothing Session(“user_name1″) = domain & “\” & Session(“user_name1″)
set domain = nothing
The Domain value is pre-pended to the login name of the user. So, each user in the forest is distinguished by the domain. When you Activate again and then login with your mobile device you should be able login to your SharePoint application with proper domain\user syntax verified by the email encoded into the certificate.
In this blog I demonstrated how to authenticate to SharePoint with personal certificates via UAG. I am only changing files in the CustomUpdate directory. So, my changes are consistent with Microsoft guidelines for customizing UAG and should hold fine with future updates and changes to the software.
I also attach the set of files as they would be written for the Contoso.com domain. You will need to change the names of the file and domain to match your configuration. and remember. baby steps and lots of patience (a snifter of Single Malt can come in handy..)