简体   繁体   中英

How to make a STS using Gmail OAuth

We want to make an STS that outsources the authentication to google.

Following the steps stated in https://developers.google.com/accounts/docs/OAuth2Login?hl=es-ES we have the following code in the Login.aspx generated by the sts web site template in vs2010:

protected void Page_Load(object sender, EventArgs e)
{
    if (Request.QueryString["code"] != null)
    {
        //I'm coming from google, already authenticated
        FormsAuthentication.SetAuthCookie(GetUserName(Request.QueryString["code"]), false);
        Response.Redirect("default.aspx");
    }
    else
    {
        //I want to authenticate
        Response.Redirect(
            "https://accounts.google.com/o/oauth2/auth?" +
            "response_type=code&" +
            "client_id=988046895016.apps.googleusercontent.com&" +
            "redirect_uri=" + HttpUtility.UrlEncode("https://localhost/GmailSTS/login.aspx") + "&" +
            "scope=" + HttpUtility.UrlEncode("https://www.googleapis.com/auth/userinfo.email")
            );
    }
}

But I get an error beacuse wa is not specified in the QueryString, debugging the samples and the generated template I saw that wa,wtrealm,wctx and wct are the parameters needed so I used the state parameter so they roundtrip and get them back:

protected void Page_Load(object sender, EventArgs e)
{
    if (Request.QueryString["code"] != null)
    {
        //I'm coming from google, already authenticated
        FormsAuthentication.SetAuthCookie("johannsw", false);
        String lQueryStrings = HttpUtility.UrlDecode(Request.QueryString["state"]);
        lQueryStrings.Replace('?', '&');
        Response.Redirect("default.aspx" + "?" + lQueryStrings);

    }
    else
    {
        //I want to authenticate
        String lState = String.Empty;
        foreach (var key in Request.QueryString.AllKeys)
        {
            if (String.Equals("wa", key) ||
                String.Equals("wtrealm", key) ||
                String.Equals("wctx", key) ||
                String.Equals("wct", key))
                lState += key + "=" + Request.QueryString[key] + "&";
        }
        lState = lState.Remove(lState.Length - 1);

        Response.Redirect(
            "https://accounts.google.com/o/oauth2/auth?" +
            "response_type=code&" +
            "client_id=988046895016.apps.googleusercontent.com&" +
            "redirect_uri=" + HttpUtility.UrlEncode("https://localhost/GmailSTS/login.aspx") + "&" +
            "scope=" + HttpUtility.UrlEncode("https://www.googleapis.com/auth/userinfo.email") + "&" +
            "state=" + HttpUtility.UrlEncode(lState)
            );
    }
}

but now I get an error saying "The HTTP verb POST used to access path '/WebSite1/' is not allowed."

Any hints? Thanks!

Well finally I made it. Here is how I solved it just in case it helps someone else:

Login.aspx.cs

protected void Page_Load(object sender, EventArgs e)
{
    if (Request.QueryString["code"] != null && Request.QueryString["error"] != "access_denied")
    { 
        // If I got code and no error then 
        // ask for access_code so I can get user email

        //Here I ask for the access_code.
        WebRequest requestLogIn = null;
        Stream stream = null;
        WebResponse response = null;
        StreamReader reader = null;

        string sendData = "code=" + Request.QueryString["code"] + "&";
        sendData += "client_id=" + ObtenerClientID() + "&";
        sendData += "client_secret=" + ObtenerClientSecret() + "&";
        sendData += "redirect_uri=" + System.Configuration.ConfigurationManager.AppSettings["urlLogin"] + "&"; //TODO: ver si es necesario
        sendData += "grant_type=authorization_code";

        requestLogIn = WebRequest.Create("https://accounts.google.com/o/oauth2/token");

        requestLogIn.Method = "POST";
        requestLogIn.ContentType = "application/x-www-form-urlencoded";

        byte[] arrayToSend = Encoding.UTF8.GetBytes(sendData);
        requestLogIn.ContentLength = arrayToSend.Length;

        stream = requestLogIn.GetRequestStream();
        stream.Write(arrayToSend, 0, arrayToSend.Length);
        stream.Close();

        response = requestLogIn.GetResponse();

        if (((HttpWebResponse)response).StatusCode == HttpStatusCode.OK)
        {
            stream = response.GetResponseStream();
            reader = new StreamReader(stream);
            string responseValue = reader.ReadToEnd();
            reader.Close();

            var lJSONResponse = new JavaScriptSerializer().Deserialize<JSONResponseToken>(responseValue);

            //Now that I have the access_code ask for the user email so I can match him in my base and load claims.

            WebRequest myRequest = WebRequest.Create("https://www.googleapis.com/oauth2/v2/userinfo");
            myRequest.Method = "GET";

            myRequest.Headers.Add("Authorization", "Bearer " + lJSONResponse.Access_Token);

            response = myRequest.GetResponse();
            if (((HttpWebResponse)response).StatusCode == HttpStatusCode.OK)
            {
                stream = response.GetResponseStream();
                reader = new StreamReader(stream);
                responseValue = reader.ReadToEnd();

                var lUserMail = new JavaScriptSerializer().Deserialize<JSONResponseUserMail>(responseValue);

                // User is authenticated
                FormsAuthentication.SetAuthCookie(lUserMail.Email, false);

                // default.aspx will load claims
                Response.Redirect("default.aspx?" + Request.QueryString.ToString());
            }
        }


    }
    else
    {
        //redirect to google for login.

        //Save original url in a cookie for later use.
        Guid lGuid = Guid.NewGuid();
        CreateContextCookie(lGuid.ToString(), this.Request.Url.AbsoluteUri);

        Response.Redirect(
            "https://accounts.google.com/o/oauth2/auth?" +
            "response_type=code&" +
            "client_id=" + ObtenerClientID() + "&" +
            //I want to return here again
            "redirect_uri=" + HttpUtility.UrlEncode(System.Configuration.ConfigurationManager.AppSettings["urlLogin"]) + "&" + 
            //Add scope so I can get user mail.
            "scope=" + HttpUtility.UrlEncode("https://www.googleapis.com/auth/userinfo.email") + "&" +
            //Reference to the cookie so I can get the original url again
            "state=" + HttpUtility.UrlEncode(lGuid.ToString())
            );
    }
}

Default.aspx.cs:

protected void Page_PreRender(object sender, EventArgs e) {

    String lCode = Request.QueryString["code"];
    String lSTate = Request.QueryString["state"];
    var ctxCookie = this.Request.Cookies[lSTate];

    var requestMessage = (SignInRequestMessage)WSFederationMessage.CreateFromUri(new Uri(ctxCookie.Value));
    //Erase cookie
    var contextCookie = new HttpCookie(lSTate)
    {
        Expires = DateTime.UtcNow.AddDays(-1)
    };

    //process login request
    SecurityTokenService sts =
        new CustomSecurityTokenService(CustomSecurityTokenServiceConfiguration.Current);
    SignInResponseMessage responseMessage =
        FederatedPassiveSecurityTokenServiceOperations.ProcessSignInRequest(requestMessage, this.User, sts);
    FederatedPassiveSecurityTokenServiceOperations.ProcessSignInResponse(responseMessage, this.Response);

    this.Response.Cookies.Add(contextCookie);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM