-
Notifications
You must be signed in to change notification settings - Fork 598
Conversation
/// Gets or sets the <see cref="OpenIdConnectMessage"/>. | ||
/// </summary> | ||
/// <exception cref="ArgumentNullException">if 'value' is null.</exception> | ||
public OpenIdConnectMessage ProtocolMessage { get; [param: NotNull] set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't NotNull discouraged for properties?
I still don't know why replacing the message was important for @brentschmaltz since it's already fully mutable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since these contexts are OIDC-specific, consider using more appropriate names like LogoutRequest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NotNull removed.
I actually like the standard property name across all the OIDC events.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is an exact copy of the other Redirect context, can we not just have a single RedirectContext we use for both? I'm really not a huge fan of all of these context objects in general. Even if we have to add to the context in the future, I don't think sharing in this case is really going to haunt us will it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or if we want unique context classes per event, we should at least consider pulling the ProtocolMessage property that appears in all of them I think to a OpenIdBaseContext? That would at least make them empty child classes
For the new events, I wonder if RedirectToAuthorizationEndpoint and RedirectToLogoutEndpoint wouldn't be a bit more expressive. |
idToken = tokenEndpointResponse.Message.IdToken; | ||
|
||
var authorizationCodeRedeemedContext = await RunAuthorizationCodeRedeemedEventAsync(message, tokenEndpointResponse); | ||
var authorizationCodeRedeemedContext = await RunAuthorizationCodeRedeemedEventAsync(message, code, tokenEndpointResponse); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should consider exposing both authorization response and the token response when you can.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't follow. We're including the token response here. What authorization response are you looking for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wooops, wrong line. This remark was for the SecurityTokenReceived
/SecurityTokenValidated
notifications, where the token response is not added to the context.
This is a very annoying thing that currently prevents adding the access token retrieved from the token endpoint to the final ClaimsIdentity
, since only the authorization response is exposed. (that's why I haven't updated this sample: https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/blob/vNext/samples/Mvc/Mvc.Client/Startup.cs#L101-L109)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SecurityTokenReceived only runs in the IdToken flow, where the token response is only available in the code flow. That said, yes, I can add the token response to the SecurityTokenValidated event.
@PinpointTownes It's actually called the EndSessionEndpoint. RedirectToEndSessionEndpoint? Seems ok. |
Yeah, but this name sounds weird (that's why I never use it). That said, if you want to use the official name, I'm fine.
|
Updated. |
Updated. @HaoK @PinpointTownes @brentschmaltz |
I'll test it in a real world app. Some renamed notifications look weird. |
There's a terrible bug with the authorization code flow. I'll investigate. |
// 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.ValidateSignature = false; | ||
|
||
ticket = ValidateToken(idToken, message, properties, validationParameters, out jwt); | ||
ticket = ValidateToken(message.IdToken, message, properties, validationParameters, out jwt); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line is bugged: message
actually represents the authorization response, not the token response. And since we're in a path that only supports the code flow (and not the hybrid flow), message.IdToken
is always null. You must instead extract the id_token
from the token response.
error : [Microsoft.AspNet.Authentication.OpenIdConnect.OpenIdConnectAuthentica
tionMiddleware] OIDCH_0017: Exception occurred while processing message.
System.ArgumentNullException: La valeur ne peut pas être null.
Nom du paramètre : IDX10000: The parameter 'tokenstring' cannot be a 'null' or a
n empty string.
à Microsoft.IdentityModel.Logging.LogHelper.Throw(String message, Type except
ionType, EventLevel logLevel, Exception innerException)
à System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.CanReadToken(String
tokenString)
à Microsoft.AspNet.Authentication.OpenIdConnect.OpenIdConnectAuthenticationHa
ndler.ValidateToken(String idToken, OpenIdConnectMessage message, Authentication
Properties properties, TokenValidationParameters validationParameters, JwtSecuri
tyToken& jwt)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, fixed.
On a related note, you should consider cleaning this code path: https://github.com/aspnet/Security/blob/dev/src/Microsoft.AspNet.Authentication.OpenIdConnect/OpenIdConnectAuthenticationHandler.cs#L374-L392 Now that the OIDC middleware has appropriate anti-XSRF countermeasures ( |
69d06c0
to
1f801d8
Compare
Updated. |
I briefly chatted with a friend about these notifications and we agreed they were terribly confusing. I suggest a much more aggressive renaming to match the standard names:
|
Hmm, there's something to that... lets see... There's a catch with MessageReceived, you don't actually know if it's an OIDC message / Authorization Response yet, it could be any form post or get query. OIDC does not require a restricted callback path. Your IdTokenReceived argument seems to apply to AuthorizationCodeReceived as well. I think these have some value over MessageReceived because you're now in a validated OIDC flow (error, state, correlation, etc.). AuthorizationCodeRedeemed -> TokenResponseReceived makes sense. IdTokenValidated -> AuthorizationResponseValidated vs TokenResponseValidated: There is an authorization response in both flows, but you only validate it in the implicit flow. Really the event is the big "Everything" validated at the end of the flow, almost like AuthenticationCompleted but it still has the details. How about just AuthenticationValidated? On a related note comparing the two flows, it looks a little odd that code flow runs GetUserInformationAsync before Validated, but the implicit flow runs AuthorizationCodeReceived after Validated. Of the two, I think I'd move GetUserInformationAsync later. |
Or maybe you could merge IdTokenReceived and AuthorizationCodeReceived into a single AuthorizationResponseReceived. |
Well, in its current form, At this point, yeah, we don't know yet if it's a "standard-compliant" authorization response, but on the other hand, you have no way to guarantee that. Not to mention that an OIDC message that contains an error or has no state parameter is still an authorization response, at least semantically speaking.
Do you have a concrete use case for these events? IMHO,
Yup 👍
Yeah, good idea 👍 |
The ODICMessage constructor doesn't do any message validation, it would work with almost any query or form post, so MessageReceived will fire for most requests. Listening to it is the only place developers can pre-process or filter incoming messages. I realized that AuthorizationCodeReceived is called at different places in both flows. In code flow it's just before redeeming the code, but in implicit/hybrid it is your chance to redeem the code yourself. I'll have to think about how to rationalize that. They may need to be two different events. |
Updated PR. |
I never said it did (luckily, or I wouldn't use it so massively 😄). I just said that an OIDC message posted at client's
Talking about that, I wonder if this feature is still useful. IIRC, your main argument to keep it was to support "unsolicited assertions". With |
I think the hybrid flow needs more work, but I'll call this good for now. @HaoK @brentschmaltz Can you take a quick pass? |
@@ -391,6 +387,26 @@ public OpenIdConnectHandler(HttpClient backchannel) | |||
_configuration = await Options.ConfigurationManager.GetConfigurationAsync(Context.RequestAborted); | |||
} | |||
|
|||
Logger.LogDebug("Authorization response received."); | |||
var authorizationResponseReceivedContext = new AuthorizationResponseReceivedContext(Context, Options) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: this is one really long local var name...just saying :)
|
// if state is missing, just log it | ||
if (string.IsNullOrEmpty(message.State)) | ||
// if any of the error fields are set, throw error null | ||
if (!string.IsNullOrEmpty(message.Error)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider moving this block after the state
check to reject requests missing a valid state
since it must be returned by the server even on errored responses:
http://openid.net/specs/openid-connect-core-1_0.html#AuthError
https://tools.ietf.org/html/rfc6749#section-4.1.2.1
#358 Add a UserInformationReceived event. #327 Add AuthenticationCompleted event. #340 Split the Redirect event for Authentication and SignOut. Rename OnAuthorizationCodeRedeemed to OnTokenResponseReceived. Move IdTokenReceived to AuthorizationResponseReceived. Rename IdTokenValidated to AuthenticationValidated.
725088a
to
1c0768f
Compare
Add new OIDC events:
#340 RedirectToIdentityProvider -> RedirectForAuthentication & RedirectForSignOut
#358 UserInformationReceived
#327 AuthenticationCompleted
Also, #372 make sure any mutable event state flows after the event.
@HaoK @brentschmaltz @tushargupta51 @PinpointTownes @Eilon @muratg