OWIN Authorization Server and External Login with Google / Facebook

I had a question for a long time.

So, I read this article and downloaded the sample code. Very good examples of using OWIN to create a Google Signed Authorization Server. It also includes 4 clients for a grant for an authorization code, a grant for a client mandate, an implicit grant, and a mandate for a resource owner password.

For the sake of brevity, I'm only going to put the startup config file here, then my problem and questions. Also, I found my problem using Implicit Grant client. Here we go...

Startup.cs

public partial class Startup
{

    public void ConfigureAuth(IAppBuilder app)
    {
        // Enable Application Sign In Cookie
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = "Application",
            AuthenticationMode = AuthenticationMode.Passive,
            LoginPath = new PathString(Paths.LoginPath),
            LogoutPath = new PathString(Paths.LogoutPath),
        });

        // Enable External Sign In Cookie
        app.SetDefaultSignInAsAuthenticationType("External");
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = "External",
            AuthenticationMode = AuthenticationMode.Passive,
            CookieName = CookieAuthenticationDefaults.CookiePrefix + "External",
            ExpireTimeSpan = TimeSpan.FromMinutes(2),
        });

        // Enable google authentication
        //var googleOptions = new GoogleOAuth2AuthenticationOptions
        //{
        //    Caption = "Google+",
        //    ClientId = "blablabla.apps.googleusercontent.com",
        //    ClientSecret = "Q1zNmqf-U3ZffeZgcTPh760j",
        //    CallbackPath = new PathString("/OAuth/Authorize"),
        //    Provider = new GoogleOAuth2AuthenticationProvider
        //    {
        //        OnAuthenticated = async context =>
        //            {
        //                context.Identity.AddClaim(new Claim(ClaimTypes.Name, context.Identity.FindFirst(ClaimTypes.Name).Value));
        //                context.Identity.AddClaim(new Claim(ClaimTypes.Name, context.Identity.FindFirst(ClaimTypes.Email).Value));
        //                context.Identity.AddClaim(new Claim(ClaimTypes.Name, context.User.GetValue("picture").ToString()));
        //                context.Identity.AddClaim(new Claim(ClaimTypes.Name, context.User.GetValue("profile").ToString()));
        //                context.Identity.AddClaim(new Claim("Token", context.AccessToken));
        //            }
        //    }
        //};
        //googleOptions.Scope.Add("https://www.googleapis.com/auth/plus.login");
        //googleOptions.Scope.Add("https://www.googleapis.com/auth/plus.login");

        //app.UseGoogleAuthentication(googleOptions);

        app.UseGoogleAuthentication();


        // Setup Authorization Server
        app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
        {
            AuthorizeEndpointPath = new PathString(Paths.AuthorizePath),
            TokenEndpointPath = new PathString(Paths.TokenPath),
            ApplicationCanDisplayErrors = true,
            AllowInsecureHttp = true,

            // Authorization server provider which controls the lifecycle of Authorization Server
            Provider = new OAuthAuthorizationServerProvider
            {
                OnValidateClientRedirectUri = ValidateClientRedirectUri,
                OnValidateClientAuthentication = ValidateClientAuthentication,
                OnGrantResourceOwnerCredentials = GrantResourceOwnerCredentials,
                OnGrantClientCredentials = GrantClientCredetails
            },

            // Authorization code provider which creates and receives authorization code
            AuthorizationCodeProvider = new AuthenticationTokenProvider
            {
                OnCreate = CreateAuthenticationCode,
                OnReceive = ReceiveAuthenticationCode,
            },

            // Refresh token provider which creates and receives referesh token
            RefreshTokenProvider = new AuthenticationTokenProvider
            {
                OnCreate = CreateRefreshToken,
                OnReceive = ReceiveRefreshToken,
            }
        });
    }

    private Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
    {
        if (context.ClientId == Clients.Client1.Id)
        {
            context.Validated(Clients.Client1.RedirectUrl);
        }
        else if (context.ClientId == Clients.Client2.Id)
        {
            context.Validated(Clients.Client2.RedirectUrl);
        }
        return Task.FromResult(0);
    }

    private Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        string clientId;
        string clientSecret;
        if (context.TryGetBasicCredentials(out clientId, out clientSecret) ||
            context.TryGetFormCredentials(out clientId, out clientSecret))
        {
            if (clientId == Clients.Client1.Id && clientSecret == Clients.Client1.Secret)
            {
                context.Validated();
            }
            else if (clientId == Clients.Client2.Id && clientSecret == Clients.Client2.Secret)
            {
                context.Validated();
            }
        }
        return Task.FromResult(0);
    }

    private Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
        var identity = new ClaimsIdentity(new GenericIdentity(context.UserName, OAuthDefaults.AuthenticationType), context.Scope.Select(x => new Claim("urn:oauth:scope", x)));

        context.Validated(identity);

        return Task.FromResult(0);
    }

    private Task GrantClientCredetails(OAuthGrantClientCredentialsContext context)
    {
        var identity = new ClaimsIdentity(new GenericIdentity(context.ClientId, OAuthDefaults.AuthenticationType), context.Scope.Select(x => new Claim("urn:oauth:scope", x)));

        context.Validated(identity);

        return Task.FromResult(0);
    }


    private readonly ConcurrentDictionary<string, string> _authenticationCodes =
        new ConcurrentDictionary<string, string>(StringComparer.Ordinal);

    private void CreateAuthenticationCode(AuthenticationTokenCreateContext context)
    {
        context.SetToken(Guid.NewGuid().ToString("n") + Guid.NewGuid().ToString("n"));
        _authenticationCodes[context.Token] = context.SerializeTicket();
    }

    private void ReceiveAuthenticationCode(AuthenticationTokenReceiveContext context)
    {
        string value;
        if (_authenticationCodes.TryRemove(context.Token, out value))
        {
            context.DeserializeTicket(value);
        }
    }

    private void CreateRefreshToken(AuthenticationTokenCreateContext context)
    {
        context.SetToken(context.SerializeTicket());
    }

    private void ReceiveRefreshToken(AuthenticationTokenReceiveContext context)
    {
        context.DeserializeTicket(context.Token);
    }
}

      

Now, notice that there is a piece of code that has been commented out. Here is the key and the confusion.

The source code looks like this: app.UseGoogleAuthentication (); ... So this code works great with get go (and for those looking to download and test this code, it's ready to go, just press F5).

Now I understand that this code still allows someone to "authenticate" with Google just to get a "verified user" response and then create their own validator / token (LOCAL AUTHORITY).

The problem comes when I want to extend a little more than google authentication. I want to actually collect more data from google (besides valid / invalid google user). As soon as I uncomment these lines, the authorization part of the authorization server will stop. I don't get an exception or whatever, it just keeps spinning.

Does anyone have any experience with this specific issue?

Thank!

+3


source to share





All Articles