OpenID Connect/OAuth2 server framework for OWIN/Katana and ASP.NET Core
Yes.
here is my
public override async Task HandleAuthorizationRequest(HandleAuthorizationRequestContext context)
{
if (context.Request.IsImplicitFlow())
{
var clientId = context.Request.ClientId;
var rdi = context.Request.RedirectUri;
var state = context.Request.State;
var scope = context.Request.Scope;
if (string.IsNullOrEmpty(clientId))
{
context.Reject(error: OpenIdConnectConstants.Errors.InvalidClient,
description: "client id cannot be null");
return;
}
else if (string.IsNullOrEmpty(rdi))
{
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidClient,
description: "redirect_uri cannot be empty"
);
return;
}
else if (string.IsNullOrEmpty(scope))
{
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidClient,
description: "scope cannot be empty"
);
return;
}
var identity = new ClaimsIdentity(
OpenIdConnectServerDefaults.AuthenticationScheme,
OpenIdConnectConstants.Claims.Name,
OpenIdConnectConstants.Claims.Role);
var clientService = context.HttpContext.RequestServices.GetRequiredService<IClientService>();
var clientService = await partnerService.GetPartnerBrokerAuthClientByClientAccessId(clientId);
if (clientService == null)
{
context.Reject(error: OpenIdConnectConstants.Errors.InvalidClient,
description: "client id cannot be found");
return;
}
if (string.IsNullOrEmpty(clientService .AllowedOrigin))
{
context.Reject(error: OpenIdConnectConstants.Errors.InvalidClient,
description: "The redirect url of the client cannot be null");
return;
}
if (!clientService .AllowedOrigin.Split(',').Any(x => string.Equals(x, rdi, StringComparison.OrdinalIgnoreCase)))
{
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidClient,
description: "The supplied redirect uri is incorrect"
);
return;
}
if (clientService .Scopes == null || ( clientService .Scopes != null && clientService .Scopes.Count == 0 ))
{
context.Reject(error: OpenIdConnectConstants.Errors.InvalidClient,
description: "Ths definition of the client's scopes cannot be null");
return;
}
}
ticket.SetAccessTokenLifetime(TimeSpan.FromSeconds(clientService.AccessTokenLifeTime));
ticket.SetIdentityTokenLifetime(TimeSpan.FromSeconds(clientService.AccessTokenLifeTime));
context.Validate(ticket);
ValidateAuthorizationRequest
and remove options.ApplicationCanDisplayErrors = true
.
await this._next(context);
var openIdConnectResponse = context.GetOpenIdConnectResponse();
if (openIdConnectResponse != null && !string.IsNullOrEmpty(openIdConnectResponse.Error) && !string.IsNullOrEmpty(openIdConnectResponse.ErrorDescription))
{
if (!context.Response.HasStarted)
{
context.Response.Headers.Clear();
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
var result = JsonConvert.SerializeObject(new Infrastructure.Utils.HttpClient.GenericResponse<string>()
{
Exception = openIdConnectResponse.ErrorDescription ?? openIdConnectResponse.Error,
StatusCode = HttpStatusCode.BadRequest
});
this._logger.LogError("The openIdConnect error with path" + context.Request.Path + ", ##IP:" + context.Connection.RemoteIpAddress + "## result: " + result);
await context.Response.WriteAsync(result);
return;
}
}
if (string.IsNullOrEmpty(clientId))
{
//context.HttpContext.Response.
context.Reject(error: OpenIdConnectConstants.Errors.InvalidClient,
description: "client id cannot be null");
return;
}
[18:05:10 Error] AspNet.Security.OAuth.Apple.Internal.DefaultAppleClientSecretGenerator
Failed to generate new client secret for the Apple authentication scheme.
Interop+Crypto+OpenSslCryptographicException: error:0D08303A:asn1 encoding routines:ASN1_TEMPLATE_NOEXP_D2I:nested asn1 error
at Internal.Cryptography.Pal.CertificatePal.FromBlob(Byte[] rawData, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)
at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(Byte[] rawData, String password, X509KeyStorageFlags keyStorageFlags)
at AspNet.Security.OAuth.Apple.Internal.DefaultAppleClientSecretGenerator.CreateAlgorithmLinuxOrMac(Byte[] keyBlob, String password)
at AspNet.Security.OAuth.Apple.Internal.DefaultAppleClientSecretGenerator.CreateAlgorithm(Byte[] keyBlob, String password)
at AspNet.Security.OAuth.Apple.Internal.DefaultAppleClientSecretGenerator.GenerateNewSecretAsync(AppleGenerateClientSecretContext context)
at AspNet.Security.OAuth.Apple.Internal.DefaultAppleClientSecretGenerator.GenerateAsync(AppleGenerateClientSecretContext context)
[18:05:10 Information] AspNet.Security.OAuth.Apple.AppleAuthenticationHandler
Error from RemoteAuthentication: error:0D08303A:asn1 encoding routines:ASN1_TEMPLATE_NOEXP_D2I:nested asn1 error.
[18:05:10 Error] Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware
An unhandled exception has occurred while executing the request.
System.Exception: An error was encountered while handling the remote login. ---> Interop+Crypto+OpenSslCryptographicException: error:0D08303A:asn1 encoding routines:ASN1_TEMPLATE_NOEXP_D2I:nested asn1 error
at Internal.Cryptography.Pal.CertificatePal.FromBlob(Byte[] rawData, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)
at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(Byte[] rawData, String password, X509KeyStorageFlags keyStorageFlags)
at AspNet.Security.OAuth.Apple.Internal.DefaultAppleClientSecretGenerator.CreateAlgorithmLinuxOrMac(Byte[] keyBlob, String password)
at AspNet.Security.OAuth.Apple.Internal.DefaultAppleClientSecretGenerator.CreateAlgorithm(Byte[] keyBlob, String password)
at AspNet.Security.OAuth.Apple.Internal.DefaultAppleClientSecretGenerator.GenerateNewSecretAsync(AppleGenerateClientSecretContext context)
at AspNet.Security.OAuth.Apple.Internal.DefaultAppleClientSecretGenerator.GenerateAsync(AppleGenerateClientSecretContext context)
at AspNet.Security.OAuth.Apple.AppleAuthenticationEvents.<>c.<<-ctor>b__10_0>d.MoveNext()
Providing the secret using the UsePrivateKey extension of the apple package. When running it on windows using:
var bytes = Convert.FromBase64String("base64-string");
var privateKey = Encoding.UTF8.GetString(bytes);
if (privateKey.StartsWith("-----BEGIN PRIVATE KEY-----", StringComparison.Ordinal))
{
string[] lines = privateKey.Split(new char[1]
{
'\n'
});
privateKey = string.Join(string.Empty, lines.Skip(1).Take(lines.Length - 2));
}
bytes = Convert.FromBase64String(privateKey);
var key = CngKey.Import(bytes, CngKeyBlobFormat.Pkcs8PrivateBlob);
var k = new ECDsaCng(key) { HashAlgorithm = CngAlgorithm.Sha256 };
it works using the same base64 string as in the container
Hi! Sorry for bothering but I have a question related to the authorization code flow described here https://kevinchalet.com/2016/07/13/creating-your-own-openid-connect-server-with-asos-implementing-the-authorization-code-and-implicit-flows/
I have implemented this, very similar to the code that is described there. I use the Authorize attribute on the Authorize endpoint to make sure the user is logged in before they see the authorization page, but unauthenticated users are not being redirected to the login page, it just returns a 401.
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler:Debug: AuthenticationScheme: Identity.Application was not authenticated.
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler:Debug: AuthenticationScheme: Identity.External was not authenticated.
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler:Debug: AuthenticationScheme: Identity.TwoFactorRememberMe was not authenticated.
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler:Debug: AuthenticationScheme: Identity.TwoFactorUserId was not authenticated.
AspNet.Security.OAuth.Validation.OAuthValidationHandler:Debug: Authentication was skipped because no bearer token was received.
AspNet.Security.OAuth.Validation.OAuthValidationHandler:Debug: AuthenticationScheme: Bearer was not authenticated.
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization failed.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
Microsoft.AspNetCore.Mvc.ChallengeResult:Information: Executing ChallengeResult with authentication schemes (Identity.Application, Identity.External, Identity.TwoFactorRememberMe, Identity.TwoFactorUserId, Bearer).
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler:Information: AuthenticationScheme: Identity.Application was challenged.
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler:Information: AuthenticationScheme: Identity.External was challenged.
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler:Information: AuthenticationScheme: Identity.TwoFactorRememberMe was challenged.
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler:Information: AuthenticationScheme: Identity.TwoFactorUserId was challenged.
AspNet.Security.OAuth.Validation.OAuthValidationHandler:Information: AuthenticationScheme: Bearer was challenged.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action ..Controllers.OAuthController.Authorize (...) in 67.3042ms
Identity.Application
to redirect the user to the login page.
That's OK, it was enough to get me started. Combined with the repo on Github I could find most of the things I needed.
There's one thing I haven't fixed yet, and that I have been searching for a while now. I derived from OpenIdConnectServerProvider and have overridden the serialize/deserialize methods so I can store the tokens in our database. However, it seems that at this point the tokens are not generated yet. I'm now generating them manually, but I'd really like to keep using the ones that OIDC generates.