How to programmatically authenticate to UAG protected SharePoint
Wednesday, February 23, 2011 at 10:48AM this post is not a how-to configure UAG and SharePoint for Authentication. It's about how to programmatically authenticate to UAG and use the SharePoint Client Object Model under the following scenario.
The scenario:
<! Your SharePoint Site is behind a Forefront Unified Access Gateway (UAG) that’s configured to have a single login experience with SSO, by providing you a login page that redirects you to the appropriate ADFS protected SharePoint Content.
For the SSO to work, UAG has to issue cookie based security token to the user before the SharePoint content can be delivered. When you hit your public SharePoint URL for the first time, UAG responses back with an automatic redirection taking you to a form-based UAG login page. When the user submits their credentials, the cookie-based security token generated by UAG is submitted behind the scene. UAG will then validate the credentials and approves the cookie-based security token. At this point any request to the SharePoint URL with the approved cookie-based security token will be granted access to the SharePoint content.
Now, what happens when you connect to the SharePoint URL programmatically?
After UAG redirects you to a login Page, it sends you back cookie-based security tokens that you are supposed to submit along with your credentials. If you don’t use the cookies, you will be stuck in a loop where UAG will keep redirecting you till you provide a cookie container, and you would reach the maximum automatic redirection allowed by your http request. Therefore you get the following error: “Too many automatic redirections were attempted” (I talk about this, because that's the first issue I encountered, when dealing witht UAG and SharePoint authentication).
If you are creating a .NET client application connecting to SharePoint, you would either build proxies against the SharePoint Web Services or use the SharePoint Client Object Model. I choose to use the SharePoint Client Object Model because it’s simpler, especially because I don’t have to worry about passing canary value (X-Request Digest Information), because that is already taking care of behind the scene.
So the first thing you should figure out is how you can pass cookies to each HTTP requests that the SharePoint Client Object Model uses. The answer is simple: Create an event handler to Microsoft.SharePoint.Client.ClientContext ExecutingWebRequest event that initializes a cookie container for the underlying HTTP Request before doing anything. And add the UAG approved cookies to the cookie container.
How to get the UAG approved cookies:
<! 1. Do a GET on https://SharePointURL
2. 2. Get the cookie from the Response
3. Construct the UAG Login Page URL
4. Do a POST to the UAG Login Page URL with the correct credentials along with the cookie
<! 5. Then pass the cookie to the ClientContext’s underlying HTTP Request using the event handler.
I have created a class called CookieAuthenticator that will do the first 4 steps for you and returns the cookies that you can add to the SharePoint client context underlying HTTP request.
CookieAthenticator:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
namespace net.usingnat.SharePoint.Uag
{
public class CookieAuthenticator
{
NetworkCredential Credential
{
get;
set;
}
string Url
{
get;
set;
}
string UserAgent
{
set;
get;
}
private CookieCollection Cookies
{
get;
set;
}
private string[] Queries
{
get;
set;
}
private string ValidationUrl
{
get;
set;
}
private void Connect()
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.Url);
request.CookieContainer = new CookieContainer();
request.UserAgent = this.UserAgent;
//Do a GET on the SharePoint URL
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
//Get the UAG generated cookies from the response
this.Cookies = response.Cookies;
//Get the query strings to construct login page URL
this.Queries = response.ResponseUri.Query.Substring(1).Split(new string[] { "&" }, StringSplitOptions.RemoveEmptyEntries);
this.ValidationUrl = this.Url;
//Construct the login page URL
for (int i = 0; i < response.ResponseUri.Segments.Length - 1; i++)
{
this.ValidationUrl += response.ResponseUri.Segments[i];
}
this.ValidationUrl += "Validate.asp";
}
}
private void ValidateCredentials()
{
//Construct the POST HTTP Request Data
ASCIIEncoding encoding = new ASCIIEncoding();
string postData = string.Empty;
postData += string.Format("user_name={0}", this.Credential.UserName);
postData += string.Format("&password={0}", this.Credential.Password);
postData += string.Format("&repository={0}", "AD");
foreach (var query in this.Queries)
{
if (query.Contains("site_name=")
|| query.Contains("resource_id=")
|| query.Contains("secure=")
|| query.Contains("login_type="))
postData += "&" + query;
}
byte[] data = encoding.GetBytes(postData);
//Do a POST on the Login Page URL
HttpWebRequest postRequest = (HttpWebRequest)WebRequest.Create(this.ValidationUrl);
postRequest.ContentType = "application/x-www-form-urlencoded";
postRequest.ContentLength = data.Length;
postRequest.CookieContainer = new CookieContainer();
foreach (Cookie cookie in this.Cookies)
{
postRequest.CookieContainer.Add(cookie);
}
postRequest.Method = "POST";
postRequest.AllowAutoRedirect = true;
using (Stream newStream = postRequest.GetRequestStream())
{
newStream.Write(data, 0, data.Length);
}
//get back the cookies
using (HttpWebResponse response = (HttpWebResponse)postRequest.GetResponse())
{
this.Cookies = response.Cookies;
}
}
public CookieAuthenticator(string url, string userAgent, NetworkCredential credentials)
{
this.Url = url;
this.UserAgent = userAgent;
this.Credential = credentials;
}
public CookieCollection Authenticate()
{
this.Connect();
this.ValidateCredentials();
return this.Cookies;
}
}
}
Sample Program (How to pass the cookie to the ClientContext):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.IO;
using Microsoft.SharePoint.Client;
using System.ComponentModel;
using System.Data;
using System.Net;
namespace net.usingnat.SharePoint.Uag
{
class Program
{
private CookieCollection cookies;
static void Main(string[] args)
{
var program = new Program();
program.Authenticate();
program.GetData();
}
public void GetData()
{
using (ClientContext ctx = new ClientContext("https://SharePointURL"))
{
ctx.ExecutingWebRequest += new EventHandler<WebRequestEventArgs>(ctx_ExecutingWebRequest);
ctx.AuthenticationMode = ClientAuthenticationMode.Default;
var list = ctx.Web.Lists.GetByTitle("Documents");
ctx.Load(list);
ctx.ExecuteQuery();
Console.WriteLine("Title: " + list.Title);
Console.WriteLine("Description: " + list.Description);
Console.WriteLine("Count: " + list.ItemCount);
Console.ReadLine();
}
}
public void Authenticate()
{
Console.WriteLine("Enter your username: ");
var userName = Console.ReadLine();
Console.WriteLine("Enter your password: ");
var password = Console.ReadLine();
var url = "https://SharePointURL";
var userAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13";
var credentials = new NetworkCredential(userName, password);
var authenticator = new CookieAuthenticator(url, userAgent, credentials);
this.cookies = authenticator.Authenticate();
}
private void ctx_ExecutingWebRequest(object sender, WebRequestEventArgs e)
{
e.WebRequestExecutor.WebRequest.CookieContainer = new CookieContainer();
foreach (Cookie cookie in this.cookies)
{
e.WebRequestExecutor.WebRequest.CookieContainer.Add(cookie);
}
}
}
}
The next step should be how to sign-out from UAG. Well, if you figure that out please let me know.
Thanks,
Using NaT

Reader Comments (7)
Hey! Can you please guide me in how to do this with Forefront TMG? Is it the same procedure?
Toni,
It should be the same. UAG and TMG work together. Are you having any problem?
Yes. This is our case. We use Form Based Authentication on the TMG. I send password and username with your code but ít wont work.
In my case I cant get the cookie from the response. I get 401 Authentication failed.,
I also wonder how to construct the TMG login page url.
Is this the way to authenticate through TMG with FBA with Sharepoint Client OM?
Sorry, for the late response...
You have to first have the plain SharePoint URL and use that. So, when you first hit that url, UAG should respond back with cookies. Can you double check that?
And, second. If you have fiddler (http://www.fiddler2.com/fiddler2/version.asp), open up fiddler and watch all the URL that gets requested from your machine when you hit the plain SharePoint URL using the browser (from fiddler you should be able to see what is the exact UAG Login you are getting redirected to and etc.).
Hello, can you please advice how to store data from a Android app through a UAG into a SharePoint 2010 list? Thank you for reading - Don
Have you ever encountered UAG with a ActiveX plugin?
I'm getting redirects to the download page and would need to fake having it. ;-)
Hi!
I found your post very interesting, but I have to use Sharepoint Web Services... have you a link or a sample code I can follow to accomplish my task?!
Thanx in advance!