/// <summary> /// Invoked when a challenge response is returned to the caller. /// </summary> public virtual Task ApplyChallenge(ApplyChallengeContext context) => OnApplyChallenge(context);
protected override async Task HandleChallengeAsync(AuthenticationProperties properties) { // Note: always return the error/error_description/error_uri/realm/scope specified // in the authentication properties even if IncludeErrorDetails is set to false. var notification = new ApplyChallengeContext(Context, Scheme, Options, properties) { Error = properties.GetProperty(OAuthIntrospectionConstants.Properties.Error), ErrorDescription = properties.GetProperty(OAuthIntrospectionConstants.Properties.ErrorDescription), ErrorUri = properties.GetProperty(OAuthIntrospectionConstants.Properties.ErrorUri), Realm = properties.GetProperty(OAuthIntrospectionConstants.Properties.Realm), Scope = properties.GetProperty(OAuthIntrospectionConstants.Properties.Scope), }; // If an error was stored by AuthenticateCoreAsync, // add the corresponding details to the notification. var error = Context.Features.Get <OAuthIntrospectionFeature>()?.Error; if (error != null && Options.IncludeErrorDetails) { // If no error was specified in the authentication properties, // try to use the error returned from HandleAuthenticateAsync. if (string.IsNullOrEmpty(notification.Error)) { notification.Error = error.Error; } // If no error_description was specified in the authentication properties, // try to use the error_description returned from HandleAuthenticateAsync. if (string.IsNullOrEmpty(notification.ErrorDescription)) { notification.ErrorDescription = error.ErrorDescription; } // If no error_uri was specified in the authentication properties, // try to use the error_uri returned from HandleAuthenticateAsync. if (string.IsNullOrEmpty(notification.ErrorUri)) { notification.ErrorUri = error.ErrorUri; } // If no realm was specified in the authentication properties, // try to use the realm returned from HandleAuthenticateAsync. if (string.IsNullOrEmpty(notification.Realm)) { notification.Realm = error.Realm; } // If no scope was specified in the authentication properties, // try to use the scope returned from HandleAuthenticateAsync. if (string.IsNullOrEmpty(notification.Scope)) { notification.Scope = error.Scope; } } // At this stage, if no realm was provided, try to // fallback to the realm registered in the options. if (string.IsNullOrEmpty(notification.Realm)) { notification.Realm = Options.Realm; } await Events.ApplyChallenge(notification); if (notification.Handled) { Logger.LogInformation("The default challenge handling was skipped from user code."); return; } Response.StatusCode = 401; // Optimization: avoid allocating a StringBuilder if the // WWW-Authenticate header doesn't contain any parameter. if (string.IsNullOrEmpty(notification.Realm) && string.IsNullOrEmpty(notification.Error) && string.IsNullOrEmpty(notification.ErrorDescription) && string.IsNullOrEmpty(notification.ErrorUri) && string.IsNullOrEmpty(notification.Scope)) { Response.Headers.Append(HeaderNames.WWWAuthenticate, OAuthIntrospectionConstants.Schemes.Bearer); } else { var builder = new StringBuilder(OAuthIntrospectionConstants.Schemes.Bearer); // Append the realm if one was specified. if (!string.IsNullOrEmpty(notification.Realm)) { builder.Append(' '); builder.Append(OAuthIntrospectionConstants.Parameters.Realm); builder.Append("=\""); builder.Append(notification.Realm); builder.Append('"'); } // Append the error if one was specified. if (!string.IsNullOrEmpty(notification.Error)) { if (!string.IsNullOrEmpty(notification.Realm)) { builder.Append(','); } builder.Append(' '); builder.Append(OAuthIntrospectionConstants.Parameters.Error); builder.Append("=\""); builder.Append(notification.Error); builder.Append('"'); } // Append the error_description if one was specified. if (!string.IsNullOrEmpty(notification.ErrorDescription)) { if (!string.IsNullOrEmpty(notification.Realm) || !string.IsNullOrEmpty(notification.Error)) { builder.Append(','); } builder.Append(' '); builder.Append(OAuthIntrospectionConstants.Parameters.ErrorDescription); builder.Append("=\""); builder.Append(notification.ErrorDescription); builder.Append('"'); } // Append the error_uri if one was specified. if (!string.IsNullOrEmpty(notification.ErrorUri)) { if (!string.IsNullOrEmpty(notification.Realm) || !string.IsNullOrEmpty(notification.Error) || !string.IsNullOrEmpty(notification.ErrorDescription)) { builder.Append(','); } builder.Append(' '); builder.Append(OAuthIntrospectionConstants.Parameters.ErrorUri); builder.Append("=\""); builder.Append(notification.ErrorUri); builder.Append('"'); } // Append the scope if one was specified. if (!string.IsNullOrEmpty(notification.Scope)) { if (!string.IsNullOrEmpty(notification.Realm) || !string.IsNullOrEmpty(notification.Error) || !string.IsNullOrEmpty(notification.ErrorDescription) || !string.IsNullOrEmpty(notification.ErrorUri)) { builder.Append(','); } builder.Append(' '); builder.Append(OAuthIntrospectionConstants.Parameters.Scope); builder.Append("=\""); builder.Append(notification.Scope); builder.Append('"'); } Response.Headers.Append(HeaderNames.WWWAuthenticate, builder.ToString()); } }