views:

200

answers:

1

Hi all,

I'm trying to approximate Single Sign on. Currently, the most workable solution involves the user imputing details on my site before being sent off to goggle Apps to authenicate.

I'm using dotnetopenauth to send and recieve the requests

This means that it takes no account of google apps login cookies should they be present.

There are several questions covering this already. But none seem to have an answer to this.

This is the current code (note that I'm constraining the possible domains that can be used to just google apps for my domain):

public ActionResult Authenticate(string returnUrl)
    {
        string input=Request.Form["openid_identifier"]+"@example.com";
        openid.DiscoveryServices.Clear();
        openid.DiscoveryServices.Insert(0, GoogleAppsDiscovery); // it should be first if we don't clear the other discovery services

        var response = openid.GetResponse();
        if (response == null)
        {
            // Stage 2: user submitting Identifier
            Identifier id;
            if (Identifier.TryParse(input, out id))
            {
                try
                {
                    return openid.CreateRequest(input).RedirectingResponse.AsActionResult();
                }
                catch (ProtocolException ex)
                {
                    ViewData["Message"] = ex.Message;
                    return View("Login");
                }
            }
            else
            {
                ViewData["Message"] = "Invalid identifier";
                return View("Login");
            }
        }
        else
        {
            // Stage 3: OpenID Provider sending assertion response
            switch (response.Status)
            {
                case AuthenticationStatus.Authenticated:

                    FormsAuthentication.SetAuthCookie(response.ClaimedIdentifier, false);

                    var results = userstable.Select(response.FriendlyIdentifierForDisplay);

                    if (results.Count() > 0)
                    {
                        Session["FriendlyIdentifier"] = results.ElementAt(0).UserFName;
                        return RedirectToAction("Index", "Home", results.ElementAt(0).UserID);
                    }
                    else
                    {
                        UsersDataModel user = new UsersDataModel();

                        user.OpenID = response.ClaimedIdentifier.ToString();
                        user.UserID = Utils.HashToBase64(response.FriendlyIdentifierForDisplay);
                        user.Type = "Empolyee";
                        userstable.Insert(user);

                        //return RedirectToAction("Register");
                    }

                    if (!string.IsNullOrEmpty(returnUrl))
                    {
                        return Redirect(returnUrl);
                    }
                    else
                    {
                        return RedirectToAction("Index", "Home");
                    }
                case AuthenticationStatus.Canceled:
                    ViewData["Message"] = "Canceled at provider";
                    return View("Login");
                case AuthenticationStatus.Failed:
                    ViewData["Message"] = response.Exception.Message;
                    return View("Login");
            }

        }
        return new EmptyResult();
    }

The only difference between this code and the normal pattern are the following lines:

openid.DiscoveryServices.Clear();
        openid.DiscoveryServices.Insert(0, GoogleAppsDiscovery); // it should be first if we don't clear the other discovery services

These lines correctly setup OpenId to process the response from google apps.

As I said, this works only if the user inputs his/her email address first. i can't find a way of automatically redirecting to the Google Apps Login

In normal gmail, if I pass the user off to: https://www.google.com/accounts/o8/id instead of processing the input, google will have the user input login details on their site rather than on mine. It will skip that if there are cookies and just pass the user right back to my site with no fuss.

I would like to have the same behavior for my site for the google apps logins.

Additionally, it would be nice if I could constrain the logins to my google apps domain.

There are a couple of URLs floating around:

https://www.google.com/accounts/o8/site-xrds?hd=example.com or https://www.google.com/a/example.com/o8/id

But even with those lines of code I pointed out earlier, dontnetopenauth refuses to see an openid endpoint at either address.

Even the sample in dotnetaopenauth for webforms still requires user input.

Any help would be most appreciated.

A: 

You can't have no user input and any Google Apps Domain work for the user, because the user may be logged into 15 Google Apps for Domains accounts, and then no one would know which account the user means to log in with.

But since you say you'd like them to only be able to log in with your own domain, that's easy. Skip asking the user, and just pretend "example.com" was the user input and pass that into DotNetOpenAuth. It doesn't have to be an email address. Only the domain name is used anyway.

That said, that doesn't guarantee no one from other Providers or domains can log into your site. To do that, you need to filter on the IAuthenticationResponse that comes back and make sure its Provider property matches the one value you intend to allow. Otherwise, "unsolicited assertions" can still come in.

Andrew Arnott