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!
No one has answered this question yet
Check out similar questions: