diff --git a/samples/OpenIdConnectSample/Startup.cs b/samples/OpenIdConnectSample/Startup.cs
index f0f9feb3ae..ddcf9fa2b2 100644
--- a/samples/OpenIdConnectSample/Startup.cs
+++ b/samples/OpenIdConnectSample/Startup.cs
@@ -1,3 +1,4 @@
+using System;
using System.Linq;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
@@ -34,6 +35,28 @@ namespace OpenIdConnectSample
{
loggerfactory.AddConsole(LogLevel.Information);
+ // Simple error page
+ app.Use(async (context, next) =>
+ {
+ try
+ {
+ await next();
+ }
+ catch (Exception ex)
+ {
+ if (!context.Response.HasStarted)
+ {
+ context.Response.Clear();
+ context.Response.StatusCode = 500;
+ await context.Response.WriteAsync(ex.ToString());
+ }
+ else
+ {
+ throw;
+ }
+ }
+ });
+
app.UseIISPlatformHandler();
app.UseCookieAuthentication(new CookieAuthenticationOptions
@@ -52,17 +75,30 @@ namespace OpenIdConnectSample
app.Run(async context =>
{
- if (!context.User.Identities.Any(identity => identity.IsAuthenticated))
+ if (context.Request.Path.Equals("/signout"))
{
- await context.Authentication.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties { RedirectUri = "/" });
-
- context.Response.ContentType = "text/plain";
- await context.Response.WriteAsync("Hello First timer");
+ await context.Authentication.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
+ context.Response.ContentType = "text/html";
+ await context.Response.WriteAsync($"
Signing out {context.User.Identity.Name}
{Environment.NewLine}");
+ await context.Response.WriteAsync("Sign In");
+ await context.Response.WriteAsync($"");
return;
}
- context.Response.ContentType = "text/plain";
- await context.Response.WriteAsync("Hello Authenticated User");
+ if (!context.User.Identities.Any(identity => identity.IsAuthenticated))
+ {
+ await context.Authentication.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties { RedirectUri = "/" });
+ return;
+ }
+
+ context.Response.ContentType = "text/html";
+ await context.Response.WriteAsync($"Hello Authenticated User {context.User.Identity.Name}
{Environment.NewLine}");
+ foreach (var claim in context.User.Claims)
+ {
+ await context.Response.WriteAsync($"{claim.Type}: {claim.Value}
{Environment.NewLine}");
+ }
+ await context.Response.WriteAsync("Sign Out");
+ await context.Response.WriteAsync($"");
});
}
diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectHandler.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectHandler.cs
index f7c675ff32..4084e21007 100644
--- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectHandler.cs
+++ b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectHandler.cs
@@ -308,16 +308,16 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
{
Logger.LogTrace(10, "Entering: {0}." + nameof(HandleRemoteAuthenticateAsync), GetType());
- OpenIdConnectMessage message = null;
+ OpenIdConnectMessage authorizationResponse = null;
if (string.Equals(Request.Method, "GET", StringComparison.OrdinalIgnoreCase))
{
- message = new OpenIdConnectMessage(Request.Query.Select(pair => new KeyValuePair(pair.Key, pair.Value)));
+ authorizationResponse = new OpenIdConnectMessage(Request.Query.Select(pair => new KeyValuePair(pair.Key, pair.Value)));
// response_mode=query (explicit or not) and a response_type containing id_token
// or token are not considered as a safe combination and MUST be rejected.
// See http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#Security
- if (!string.IsNullOrEmpty(message.IdToken) || !string.IsNullOrEmpty(message.AccessToken))
+ if (!string.IsNullOrEmpty(authorizationResponse.IdToken) || !string.IsNullOrEmpty(authorizationResponse.AccessToken))
{
if (Options.SkipUnrecognizedRequests)
{
@@ -336,10 +336,10 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
&& Request.Body.CanRead)
{
var form = await Request.ReadFormAsync();
- message = new OpenIdConnectMessage(form.Select(pair => new KeyValuePair(pair.Key, pair.Value)));
+ authorizationResponse = new OpenIdConnectMessage(form.Select(pair => new KeyValuePair(pair.Key, pair.Value)));
}
- if (message == null)
+ if (authorizationResponse == null)
{
if (Options.SkipUnrecognizedRequests)
{
@@ -349,54 +349,52 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
return AuthenticateResult.Fail("No message.");
}
+ AuthenticateResult result;
+
try
{
- var messageReceivedContext = await RunMessageReceivedEventAsync(message);
- if (messageReceivedContext.HandledResponse)
+ var messageReceivedContext = await RunMessageReceivedEventAsync(authorizationResponse);
+ if (CheckEventResult(messageReceivedContext, out result))
{
- return AuthenticateResult.Success(messageReceivedContext.Ticket);
+ return result;
}
- else if (messageReceivedContext.Skipped)
- {
- return AuthenticateResult.Skip();
- }
- message = messageReceivedContext.ProtocolMessage;
+ authorizationResponse = messageReceivedContext.ProtocolMessage;
// Fail if state is missing, it's required for the correlation id.
- if (string.IsNullOrEmpty(message.State))
+ if (string.IsNullOrEmpty(authorizationResponse.State))
{
// This wasn't a valid OIDC message, it may not have been intended for us.
+ Logger.LogDebug(11, "message.State is null or empty.");
if (Options.SkipUnrecognizedRequests)
{
return AuthenticateResult.Skip();
}
- Logger.LogDebug(11, "message.State is null or empty.");
return AuthenticateResult.Fail(Resources.MessageStateIsNullOrEmpty);
}
// if state exists and we failed to 'unprotect' this is not a message we should process.
- var properties = Options.StateDataFormat.Unprotect(Uri.UnescapeDataString(message.State));
+ var properties = Options.StateDataFormat.Unprotect(Uri.UnescapeDataString(authorizationResponse.State));
if (properties == null)
{
+ Logger.LogDebug(12, "Unable to read the message.State.");
if (Options.SkipUnrecognizedRequests)
{
// Not for us?
return AuthenticateResult.Skip();
}
- Logger.LogError(12, "Unable to read the message.State.");
return AuthenticateResult.Fail(Resources.MessageStateIsInvalid);
}
// if any of the error fields are set, throw error null
- if (!string.IsNullOrEmpty(message.Error))
+ if (!string.IsNullOrEmpty(authorizationResponse.Error))
{
- Logger.LogError(13, "Message contains error: '{0}', error_description: '{1}', error_uri: '{2}'.", message.Error, message.ErrorDescription ?? "ErrorDecription null", message.ErrorUri ?? "ErrorUri null");
- return AuthenticateResult.Fail(new OpenIdConnectProtocolException(string.Format(CultureInfo.InvariantCulture, Resources.MessageContainsError, message.Error, message.ErrorDescription ?? "ErrorDecription null", message.ErrorUri ?? "ErrorUri null")));
+ Logger.LogError(13, "Message contains error: '{0}', error_description: '{1}', error_uri: '{2}'.", authorizationResponse.Error, authorizationResponse.ErrorDescription ?? "ErrorDecription null", authorizationResponse.ErrorUri ?? "ErrorUri null");
+ return AuthenticateResult.Fail(new OpenIdConnectProtocolException(string.Format(CultureInfo.InvariantCulture, Resources.MessageContainsError, authorizationResponse.Error, authorizationResponse.ErrorDescription ?? "ErrorDecription null", authorizationResponse.ErrorUri ?? "ErrorUri null")));
}
string userstate = null;
properties.Items.TryGetValue(OpenIdConnectDefaults.UserstatePropertiesKey, out userstate);
- message.State = userstate;
+ authorizationResponse.State = userstate;
if (!ValidateCorrelationId(properties))
{
@@ -409,38 +407,113 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
_configuration = await Options.ConfigurationManager.GetConfigurationAsync(Context.RequestAborted);
}
- Logger.LogTrace(15, "Authorization response received.");
- var authorizationResponseReceivedContext = new AuthorizationResponseReceivedContext(Context, Options, properties)
+ var authorizationResponseReceivedContext = await RunAuthorizationResponseReceivedEventAsync(authorizationResponse, properties);
+ if (CheckEventResult(authorizationResponseReceivedContext, out result))
{
- ProtocolMessage = message
- };
- await Options.Events.AuthorizationResponseReceived(authorizationResponseReceivedContext);
- if (authorizationResponseReceivedContext.HandledResponse)
- {
- Logger.LogDebug(16, "AuthorizationResponseReceived.HandledResponse");
- return AuthenticateResult.Success(authorizationResponseReceivedContext.Ticket);
+ return result;
}
- else if (authorizationResponseReceivedContext.Skipped)
- {
- Logger.LogDebug(17, "AuthorizationResponseReceived.Skipped");
- return AuthenticateResult.Skip();
- }
- message = authorizationResponseReceivedContext.ProtocolMessage;
+ authorizationResponse = authorizationResponseReceivedContext.ProtocolMessage;
properties = authorizationResponseReceivedContext.Properties;
- if (string.IsNullOrEmpty(message.IdToken) && !string.IsNullOrEmpty(message.Code))
+ PopulateSessionProperties(authorizationResponse, properties);
+
+ AuthenticationTicket ticket = null;
+ JwtSecurityToken jwt = null;
+ string nonce = null;
+ var validationParameters = Options.TokenValidationParameters.Clone();
+
+ // Hybrid or Implicit flow
+ if (!string.IsNullOrEmpty(authorizationResponse.IdToken))
{
- return await HandleCodeOnlyFlow(message, properties);
+ Logger.LogDebug(23, "'id_token' received.");
+ ticket = ValidateToken(authorizationResponse.IdToken, properties, validationParameters, out jwt);
+
+ nonce = jwt?.Payload.Nonce;
+ if (!string.IsNullOrEmpty(nonce))
+ {
+ nonce = ReadNonceCookie(nonce);
+ }
}
- else if (!string.IsNullOrEmpty(message.IdToken))
+
+ Options.ProtocolValidator.ValidateAuthenticationResponse(new OpenIdConnectProtocolValidationContext()
{
- return await HandleIdTokenFlows(message, properties);
- }
- else
+ ClientId = Options.ClientId,
+ ProtocolMessage = authorizationResponse,
+ ValidatedIdToken = jwt,
+ Nonce = nonce
+ });
+
+ // TODO: AuthorizationResponseValidated event?
+
+ OpenIdConnectMessage tokenEndpointResponse = null;
+
+ // Authorization Code or Hybrid flow
+ if (!string.IsNullOrEmpty(authorizationResponse.Code))
{
- Logger.LogTrace(18, "Cannot process the message. Both id_token and code are missing.");
- return AuthenticateResult.Fail(Resources.IdTokenCodeMissing);
+ // TODO: Does this event provide any value over AuthorizationResponseReceived or AuthorizationResponseValidated?
+ var authorizationCodeReceivedContext = await RunAuthorizationCodeReceivedEventAsync(authorizationResponse, properties, ticket, jwt);
+ if (CheckEventResult(authorizationCodeReceivedContext, out result))
+ {
+ return result;
+ }
+ authorizationResponse = authorizationCodeReceivedContext.ProtocolMessage;
+ var code = authorizationCodeReceivedContext.Code;
+
+ tokenEndpointResponse = await RedeemAuthorizationCodeAsync(code, authorizationCodeReceivedContext.RedirectUri);
+
+ var authorizationCodeRedeemedContext = await RunTokenResponseReceivedEventAsync(authorizationResponse, tokenEndpointResponse, properties);
+ if (CheckEventResult(authorizationCodeRedeemedContext, out result))
+ {
+ return result;
+ }
+ authorizationResponse = authorizationCodeRedeemedContext.ProtocolMessage;
+ tokenEndpointResponse = authorizationCodeRedeemedContext.TokenEndpointResponse;
+
+ // We only have to process the IdToken if we didn't already get one in the AuthorizationResponse
+ if (ticket == null)
+ {
+ // no need to validate signature when token is received using "code flow" as per spec
+ // [http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation].
+ validationParameters.RequireSignedTokens = false;
+
+ ticket = ValidateToken(tokenEndpointResponse.IdToken, properties, validationParameters, out jwt);
+
+ nonce = jwt?.Payload.Nonce;
+ if (!string.IsNullOrEmpty(nonce))
+ {
+ nonce = ReadNonceCookie(nonce);
+ }
+ }
+
+ Options.ProtocolValidator.ValidateTokenResponse(new OpenIdConnectProtocolValidationContext()
+ {
+ ClientId = Options.ClientId,
+ ProtocolMessage = tokenEndpointResponse,
+ ValidatedIdToken = jwt,
+ Nonce = nonce
+ });
}
+
+ var authenticationValidatedContext = await RunAuthenticationValidatedEventAsync(authorizationResponse, ticket, properties, tokenEndpointResponse);
+ if (CheckEventResult(authenticationValidatedContext, out result))
+ {
+ return result;
+ }
+ authorizationResponse = authenticationValidatedContext.ProtocolMessage;
+ tokenEndpointResponse = authenticationValidatedContext.TokenEndpointResponse;
+ ticket = authenticationValidatedContext.Ticket;
+
+ if (Options.SaveTokensAsClaims)
+ {
+ SaveTokens(ticket.Principal, tokenEndpointResponse ?? authorizationResponse, jwt.Issuer);
+ }
+
+ if (Options.GetClaimsFromUserInfoEndpoint)
+ {
+ return await GetUserInformationAsync(tokenEndpointResponse ?? authorizationResponse, jwt, ticket);
+ }
+
+ return AuthenticateResult.Success(ticket);
}
catch (Exception exception)
{
@@ -456,179 +529,43 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
}
}
- var authenticationFailedContext = await RunAuthenticationFailedEventAsync(message, exception);
- if (authenticationFailedContext.HandledResponse)
+ var authenticationFailedContext = await RunAuthenticationFailedEventAsync(authorizationResponse, exception);
+ if (CheckEventResult(authenticationFailedContext, out result))
{
- return AuthenticateResult.Success(authenticationFailedContext.Ticket);
- }
- else if (authenticationFailedContext.Skipped)
- {
- return AuthenticateResult.Skip();
+ return result;
}
- throw;
+ return AuthenticateResult.Fail(exception);
}
}
- // Authorization Code Flow
- private async Task HandleCodeOnlyFlow(OpenIdConnectMessage message, AuthenticationProperties properties)
+ private bool CheckEventResult(BaseControlContext context, out AuthenticateResult result)
{
- AuthenticationTicket ticket = null;
- JwtSecurityToken jwt = null;
-
- Options.ProtocolValidator.ValidateAuthenticationResponse(new OpenIdConnectProtocolValidationContext()
+ if (context.HandledResponse)
{
- ClientId = Options.ClientId,
- ProtocolMessage = message,
- });
-
- var authorizationCodeReceivedContext = await RunAuthorizationCodeReceivedEventAsync(message, properties, ticket, jwt);
- if (authorizationCodeReceivedContext.HandledResponse)
- {
- return AuthenticateResult.Success(authorizationCodeReceivedContext.Ticket);
+ result = AuthenticateResult.Success(context.Ticket);
+ return true;
}
- else if (authorizationCodeReceivedContext.Skipped)
+ else if (context.Skipped)
{
- return AuthenticateResult.Skip();
+ result = AuthenticateResult.Skip();
+ return true;
}
- message = authorizationCodeReceivedContext.ProtocolMessage;
- var code = authorizationCodeReceivedContext.Code;
-
- // Redeeming authorization code for tokens
- Logger.LogTrace(21, "Id Token is null. Redeeming code '{0}' for tokens.", code);
-
- var tokenEndpointResponse = await RedeemAuthorizationCodeAsync(code, authorizationCodeReceivedContext.RedirectUri);
-
- var authorizationCodeRedeemedContext = await RunTokenResponseReceivedEventAsync(message, tokenEndpointResponse, properties);
- if (authorizationCodeRedeemedContext.HandledResponse)
- {
- return AuthenticateResult.Success(authorizationCodeRedeemedContext.Ticket);
- }
- else if (authorizationCodeRedeemedContext.Skipped)
- {
- return AuthenticateResult.Skip();
- }
-
- message = authorizationCodeRedeemedContext.ProtocolMessage;
- tokenEndpointResponse = authorizationCodeRedeemedContext.TokenEndpointResponse;
-
- // no need to validate signature when token is received using "code flow" as per spec [http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation].
- var validationParameters = Options.TokenValidationParameters.Clone();
- validationParameters.RequireSignedTokens = false;
-
- ticket = ValidateToken(tokenEndpointResponse.IdToken, message, properties, validationParameters, out jwt);
-
- var nonce = jwt?.Payload.Nonce;
- if (!string.IsNullOrEmpty(nonce))
- {
- nonce = ReadNonceCookie(nonce);
- }
-
- Options.ProtocolValidator.ValidateTokenResponse(new OpenIdConnectProtocolValidationContext()
- {
- ClientId = Options.ClientId,
- ProtocolMessage = tokenEndpointResponse,
- ValidatedIdToken = jwt,
- Nonce = nonce
- });
-
- var authenticationValidatedContext = await RunAuthenticationValidatedEventAsync(message, ticket, properties, tokenEndpointResponse);
- if (authenticationValidatedContext.HandledResponse)
- {
- return AuthenticateResult.Success(authenticationValidatedContext.Ticket);
- }
- else if (authenticationValidatedContext.Skipped)
- {
- return AuthenticateResult.Skip();
- }
- ticket = authenticationValidatedContext.Ticket;
-
- if (Options.SaveTokensAsClaims)
- {
- // Persist the tokens extracted from the token response.
- SaveTokens(ticket.Principal, tokenEndpointResponse, jwt.Issuer, saveRefreshToken: true);
- }
-
- if (Options.GetClaimsFromUserInfoEndpoint)
- {
- Logger.LogTrace(22, "Sending request to user info endpoint for retrieving claims.");
- ticket = await GetUserInformationAsync(tokenEndpointResponse, jwt, ticket);
- }
-
- return AuthenticateResult.Success(ticket);
+ result = null;
+ return false;
}
- // Implicit Flow or Hybrid Flow
- private async Task HandleIdTokenFlows(OpenIdConnectMessage message, AuthenticationProperties properties)
+ private void PopulateSessionProperties(OpenIdConnectMessage message, AuthenticationProperties properties)
{
- Logger.LogTrace(23, "'id_token' received: '{0}'", message.IdToken);
-
- JwtSecurityToken jwt = null;
- var validationParameters = Options.TokenValidationParameters.Clone();
- var ticket = ValidateToken(message.IdToken, message, properties, validationParameters, out jwt);
-
- var nonce = jwt?.Payload.Nonce;
- if (!string.IsNullOrEmpty(nonce))
+ if (!string.IsNullOrEmpty(message.SessionState))
{
- nonce = ReadNonceCookie(nonce);
+ properties.Items[OpenIdConnectSessionProperties.SessionState] = message.SessionState;
}
- Options.ProtocolValidator.ValidateAuthenticationResponse(new OpenIdConnectProtocolValidationContext()
+ if (!string.IsNullOrEmpty(_configuration.CheckSessionIframe))
{
- ClientId = Options.ClientId,
- ProtocolMessage = message,
- ValidatedIdToken = jwt,
- Nonce = nonce
- });
-
- var authenticationValidatedContext = await RunAuthenticationValidatedEventAsync(message, ticket, properties, tokenEndpointResponse: null);
- if (authenticationValidatedContext.HandledResponse)
- {
- return AuthenticateResult.Success(authenticationValidatedContext.Ticket);
+ properties.Items[OpenIdConnectSessionProperties.CheckSessionIFrame] = _configuration.CheckSessionIframe;
}
- else if (authenticationValidatedContext.Skipped)
- {
- return AuthenticateResult.Skip();
- }
- message = authenticationValidatedContext.ProtocolMessage;
- ticket = authenticationValidatedContext.Ticket;
-
- // Hybrid Flow
- if (message.Code != null)
- {
- var authorizationCodeReceivedContext = await RunAuthorizationCodeReceivedEventAsync(message, properties, ticket, jwt);
- if (authorizationCodeReceivedContext.HandledResponse)
- {
- return AuthenticateResult.Success(authorizationCodeReceivedContext.Ticket);
- }
- else if (authorizationCodeReceivedContext.Skipped)
- {
- return AuthenticateResult.Skip();
- }
- message = authorizationCodeReceivedContext.ProtocolMessage;
- ticket = authorizationCodeReceivedContext.Ticket;
-
- if (Options.SaveTokensAsClaims)
- {
- // TODO: call SaveTokens with the token response and set
- // saveRefreshToken to true when the hybrid flow is fully implemented.
- SaveTokens(ticket.Principal, message, jwt.Issuer, saveRefreshToken: false);
- }
- }
- // Implicit Flow
- else
- {
- if (Options.SaveTokensAsClaims)
- {
- // Note: don't save the refresh token when it is extracted from the authorization
- // response, since it's not a valid parameter when using the implicit flow.
- // See http://openid.net/specs/openid-connect-core-1_0.html#Authentication
- // and https://tools.ietf.org/html/rfc6749#section-4.2.2.
- SaveTokens(ticket.Principal, message, jwt.Issuer, saveRefreshToken: false);
- }
- }
-
- return AuthenticateResult.Success(ticket);
}
///
@@ -639,6 +576,8 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
/// OpenIdConnect message that has tokens inside it.
protected virtual async Task RedeemAuthorizationCodeAsync(string authorizationCode, string redirectUri)
{
+ Logger.LogDebug(21, "Redeeming code for tokens.");
+
var openIdMessage = new OpenIdConnectMessage()
{
ClientId = Options.ClientId,
@@ -648,6 +587,8 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
RedirectUri = redirectUri
};
+ // TODO: Event that lets you customize the message. E.g. use certificates, specify resources.
+
var requestMessage = new HttpRequestMessage(HttpMethod.Post, _configuration.TokenEndpoint);
requestMessage.Content = new FormUrlEncodedContent(openIdMessage.Parameters);
var responseMessage = await Backchannel.SendAsync(requestMessage);
@@ -663,21 +604,28 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
/// message that is being processed
/// authentication ticket with claims principal and identities
/// Authentication ticket with identity with additional claims, if any.
- protected virtual async Task GetUserInformationAsync(OpenIdConnectMessage message, JwtSecurityToken jwt, AuthenticationTicket ticket)
+ protected virtual async Task GetUserInformationAsync(OpenIdConnectMessage message, JwtSecurityToken jwt, AuthenticationTicket ticket)
{
var userInfoEndpoint = _configuration?.UserInfoEndpoint;
if (string.IsNullOrEmpty(userInfoEndpoint))
{
- Logger.LogWarning(24, nameof(_configuration.UserInfoEndpoint) + " is not set. Request to retrieve claims cannot be completed.");
- return ticket;
+ Logger.LogDebug(24, $"{nameof(_configuration.UserInfoEndpoint)} is not set. Claims cannot be retrieved.");
+ return AuthenticateResult.Success(ticket);
}
+ if (string.IsNullOrEmpty(message.AccessToken))
+ {
+ Logger.LogDebug(47, "The access_token is not available. Claims cannot be retrieved.");
+ return AuthenticateResult.Success(ticket);
+ }
+ Logger.LogTrace(22, "Retrieving claims from the user info endpoint.");
var requestMessage = new HttpRequestMessage(HttpMethod.Get, userInfoEndpoint);
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", message.AccessToken);
var responseMessage = await Backchannel.SendAsync(requestMessage);
responseMessage.EnsureSuccessStatusCode();
var userInfoResponse = await responseMessage.Content.ReadAsStringAsync();
+
JObject user;
var contentType = responseMessage.Content.Headers.ContentType;
if (contentType.MediaType.Equals("application/json", StringComparison.OrdinalIgnoreCase))
@@ -691,17 +639,14 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
}
else
{
- throw new NotSupportedException("Unknown response type: " + contentType.MediaType);
+ return AuthenticateResult.Fail("Unknown response type: " + contentType.MediaType);
}
var userInformationReceivedContext = await RunUserInformationReceivedEventAsync(ticket, message, user);
- if (userInformationReceivedContext.HandledResponse)
+ AuthenticateResult result;
+ if (CheckEventResult(userInformationReceivedContext, out result))
{
- return userInformationReceivedContext.Ticket;
- }
- else if (userInformationReceivedContext.Skipped)
- {
- return ticket;
+ return result;
}
ticket = userInformationReceivedContext.Ticket;
user = userInformationReceivedContext.User;
@@ -742,7 +687,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
identity.AddClaim(new Claim(pair.Key, claimValue, ClaimValueTypes.String, jwt.Issuer));
}
- return ticket;
+ return AuthenticateResult.Success(ticket);
}
///
@@ -750,8 +695,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
///
/// The principal in which tokens are saved.
/// The OpenID Connect response.
- /// A indicating whether the refresh token should be stored.
- private void SaveTokens(ClaimsPrincipal principal, OpenIdConnectMessage message, string issuer, bool saveRefreshToken)
+ private void SaveTokens(ClaimsPrincipal principal, OpenIdConnectMessage message, string issuer)
{
var identity = (ClaimsIdentity)principal.Identity;
@@ -767,7 +711,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
ClaimValueTypes.String, issuer));
}
- if (saveRefreshToken && !string.IsNullOrEmpty(message.RefreshToken))
+ if (!string.IsNullOrEmpty(message.RefreshToken))
{
identity.AddClaim(new Claim(OpenIdConnectParameterNames.RefreshToken, message.RefreshToken,
ClaimValueTypes.String, issuer));
@@ -911,6 +855,25 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
return messageReceivedContext;
}
+ private async Task RunAuthorizationResponseReceivedEventAsync(OpenIdConnectMessage message, AuthenticationProperties properties)
+ {
+ Logger.LogTrace(15, "Authorization response received.");
+ var authorizationResponseReceivedContext = new AuthorizationResponseReceivedContext(Context, Options, properties)
+ {
+ ProtocolMessage = message
+ };
+ await Options.Events.AuthorizationResponseReceived(authorizationResponseReceivedContext);
+ if (authorizationResponseReceivedContext.HandledResponse)
+ {
+ Logger.LogDebug(16, "AuthorizationResponseReceived.HandledResponse");
+ }
+ else if (authorizationResponseReceivedContext.Skipped)
+ {
+ Logger.LogDebug(17, "AuthorizationResponseReceived.Skipped");
+ }
+ return authorizationResponseReceivedContext;
+ }
+
private async Task RunAuthorizationCodeReceivedEventAsync(OpenIdConnectMessage message, AuthenticationProperties properties, AuthenticationTicket ticket, JwtSecurityToken jwt)
{
var redirectUri = properties.Items[OpenIdConnectDefaults.RedirectUriForCodePropertiesKey];
@@ -960,13 +923,13 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
return tokenResponseReceivedContext;
}
- private async Task RunAuthenticationValidatedEventAsync(OpenIdConnectMessage message, AuthenticationTicket ticket, AuthenticationProperties properties, OpenIdConnectMessage tokenEndpointResponse)
+ private async Task RunAuthenticationValidatedEventAsync(OpenIdConnectMessage message, AuthenticationTicket ticket, AuthenticationProperties properties, OpenIdConnectMessage tokenResponse)
{
var authenticationValidatedContext = new AuthenticationValidatedContext(Context, Options, properties)
{
Ticket = ticket,
ProtocolMessage = message,
- TokenEndpointResponse = tokenEndpointResponse,
+ TokenEndpointResponse = tokenResponse,
};
await Options.Events.AuthenticationValidated(authenticationValidatedContext);
@@ -1027,10 +990,13 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
return authenticationFailedContext;
}
- private AuthenticationTicket ValidateToken(string idToken, OpenIdConnectMessage message, AuthenticationProperties properties, TokenValidationParameters validationParameters, out JwtSecurityToken jwt)
+ private AuthenticationTicket ValidateToken(string idToken, AuthenticationProperties properties, TokenValidationParameters validationParameters, out JwtSecurityToken jwt)
{
- AuthenticationTicket ticket = null;
- jwt = null;
+ if (!Options.SecurityTokenValidator.CanReadToken(idToken))
+ {
+ Logger.LogError(48, "Unable to read the 'id_token', no suitable ISecurityTokenValidator was found for: '{0}'.", idToken);
+ throw new SecurityTokenException(string.Format(CultureInfo.InvariantCulture, Resources.UnableToValidateToken, idToken));
+ }
if (_configuration != null)
{
@@ -1047,16 +1013,12 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
}
SecurityToken validatedToken = null;
- ClaimsPrincipal principal = null;
- if (Options.SecurityTokenValidator.CanReadToken(idToken))
+ var principal = Options.SecurityTokenValidator.ValidateToken(idToken, validationParameters, out validatedToken);
+ jwt = validatedToken as JwtSecurityToken;
+ if (jwt == null)
{
- principal = Options.SecurityTokenValidator.ValidateToken(idToken, validationParameters, out validatedToken);
- jwt = validatedToken as JwtSecurityToken;
- if (jwt == null)
- {
- Logger.LogError(45, "The Validated Security Token must be of type JwtSecurityToken, but instead its type is: '{0}'", validatedToken?.GetType());
- throw new SecurityTokenException(string.Format(CultureInfo.InvariantCulture, Resources.ValidatedSecurityTokenNotJwt, validatedToken?.GetType()));
- }
+ Logger.LogError(45, "The Validated Security Token must be of type JwtSecurityToken, but instead its type is: '{0}'", validatedToken?.GetType());
+ throw new SecurityTokenException(string.Format(CultureInfo.InvariantCulture, Resources.ValidatedSecurityTokenNotJwt, validatedToken?.GetType()));
}
if (validatedToken == null)
@@ -1065,16 +1027,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
throw new SecurityTokenException(string.Format(CultureInfo.InvariantCulture, Resources.UnableToValidateToken, idToken));
}
- ticket = new AuthenticationTicket(principal, properties, Options.AuthenticationScheme);
- if (!string.IsNullOrEmpty(message.SessionState))
- {
- ticket.Properties.Items[OpenIdConnectSessionProperties.SessionState] = message.SessionState;
- }
-
- if (_configuration != null && !string.IsNullOrEmpty(_configuration.CheckSessionIframe))
- {
- ticket.Properties.Items[OpenIdConnectSessionProperties.CheckSessionIFrame] = _configuration.CheckSessionIframe;
- }
+ var ticket = new AuthenticationTicket(principal, properties, Options.AuthenticationScheme);
if (Options.UseTokenLifetime)
{