« Looking SharePoint Topologies as Patterns (MOSS 2007) | Main | Add-SPSolution : "Access Denied" Vicious Circle (SharePoint 2010) »
Wednesday
Feb232011

How to programmatically authenticate to UAG protected SharePoint

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

 

 

PrintView Printer Friendly Version

EmailEmail Article to Friend

References (9)

References allow you to track sources for this article, as well as articles that were written in response to this article.
  • Response
    [...]How to programmatically authenticate to UAG protected SharePoint - SharePoint - Using (NaT)[...]
  • Response
    [...]How to programmatically authenticate to UAG protected SharePoint - SharePoint - Using (NaT)[...]
  • Response
    Response: adatmentés
    How to programmatically authenticate to UAG protected SharePoint - SharePoint - Using (NaT)
  • Response
    Response: Fruit Of Mattseh
    How to programmatically authenticate to UAG protected SharePoint - SharePoint - Using (NaT)
  • Response
    How to programmatically authenticate to UAG protected SharePoint - SharePoint - Using (NaT)
  • Response
    Response: get rid of herpes
    How to programmatically authenticate to UAG protected SharePoint - SharePoint - Using (NaT)
  • Response
    Response: Buton4E.Com
    How to programmatically authenticate to UAG protected SharePoint - SharePoint - Using (NaT)
  • Response
    How to programmatically authenticate to UAG protected SharePoint - SharePoint - Using (NaT)
  • Response
    Response: drug abuse
    How to programmatically authenticate to UAG protected SharePoint - SharePoint - Using (NaT)

Reader Comments (10)

Hey! Can you please guide me in how to do this with Forefront TMG? Is it the same procedure?

May 16, 2011 | Unregistered CommenterToni

Toni,

It should be the same. UAG and TMG work together. Are you having any problem?

May 17, 2011 | Registered CommenterNaT

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?

May 17, 2011 | Unregistered CommenterToni

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.).

June 3, 2011 | Registered CommenterNaT

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

October 19, 2011 | Unregistered CommenterDon

Have you ever encountered UAG with a ActiveX plugin?
I'm getting redirects to the download page and would need to fake having it. ;-)

May 22, 2012 | Unregistered CommenterJonas

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!

May 31, 2012 | Unregistered Commenterele

I know this post is 2 years old. I am struggling with getting anything to work through UAG - either Client Object Model like you have here, or Web Services using the same methodology. I have posted a question in MS Forums here (MS Forum Post) for anyone who might have the chance to comment on what they think might be wrong.

Thanks in advance

April 11, 2013 | Unregistered CommenterSusan H

Navigating to error page when used the approach which you mentioned in the blog...this is the error displayed in the errorpage "the logon process cannot be completed. the page was accessed from an unauthorized url"

January 3, 2014 | Unregistered CommenterRamesh

This code sample is not working for me. If I use Web Services, I always get back an HTML response that basically says UAG error code 123, which is that "my browser" does not have JavaScript and/or Meta Refresh enabled. If I use the Client Object Model, I get back the error "To access this site adjust the security settings in the browser to a lower level".

January 6, 2014 | Unregistered CommenterRamesh

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>