Skip to content

Commit

Permalink
Add optional HttpResponse parameter to ReplyForbiddenWithWwwAuthentic…
Browse files Browse the repository at this point in the history
…ateHeaderAsync. Handle null context. (#412)
  • Loading branch information
pmaytak authored Aug 6, 2020
1 parent 4870017 commit bd0c266
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 15 deletions.
3 changes: 2 additions & 1 deletion src/Microsoft.Identity.Web/Constants/IDWebErrorMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ namespace Microsoft.Identity.Web
internal static class IDWebErrorMessage
{
// General IDW10000 = "IDW10000:"
public const string HttpContextIsNull = "IDW10000: HttpContext is null. ";
public const string HttpContextIsNull = "IDW10001: HttpContext is null. ";
public const string HttpContextAndHttpResponseAreNull = "IDW10002: Current HttpContext and HttpResponse argument are null. Pass an HttpResponse argument. ";

// Configuration IDW10100 = "IDW10100:"
public const string ProvideEitherScopeKeySectionOrScopes = "IDW10101: Either provide the '{0}' or the '{1}' to the 'AuthorizeForScopes'. ";
Expand Down
6 changes: 4 additions & 2 deletions src/Microsoft.Identity.Web/ITokenAcquisition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,12 @@ Task<string> GetAccessTokenForUserAsync(
/// the client can trigger an interaction with the user so the user can consent to more scopes.
/// </summary>
/// <param name="scopes">Scopes to consent to.</param>
/// <param name="msalSeviceException"><see cref="MsalUiRequiredException"/> triggering the challenge.</param>
/// <param name="msalServiceException"><see cref="MsalUiRequiredException"/> triggering the challenge.</param>
/// <param name="httpResponse">The <see cref="HttpResponse"/> to update.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
Task ReplyForbiddenWithWwwAuthenticateHeaderAsync(
IEnumerable<string> scopes,
MsalUiRequiredException msalSeviceException);
MsalUiRequiredException msalServiceException,
HttpResponse? httpResponse = null);
}
}
14 changes: 11 additions & 3 deletions src/Microsoft.Identity.Web/Microsoft.Identity.Web.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 13 additions & 9 deletions src/Microsoft.Identity.Web/TokenAcquisition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -533,8 +533,9 @@ private async Task<string> GetAccessTokenForWebAppWithAccountFromCacheAsync(
/// </summary>
/// <param name="scopes">Scopes to consent to.</param>
/// <param name="msalServiceException">The <see cref="MsalUiRequiredException"/> that triggered the challenge.</param>
/// <param name="httpResponse">The <see cref="HttpResponse"/> to update.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public async Task ReplyForbiddenWithWwwAuthenticateHeaderAsync(IEnumerable<string> scopes, MsalUiRequiredException msalServiceException)
public async Task ReplyForbiddenWithWwwAuthenticateHeaderAsync(IEnumerable<string> scopes, MsalUiRequiredException msalServiceException, HttpResponse? httpResponse = null)
{
// A user interaction is required, but we are in a web API, and therefore, we need to report back to the client through a 'WWW-Authenticate' header https://tools.ietf.org/html/rfc6750#section-3.1
string proposedAction = Constants.Consent;
Expand Down Expand Up @@ -562,23 +563,26 @@ public async Task ReplyForbiddenWithWwwAuthenticateHeaderAsync(IEnumerable<strin

string parameterString = string.Join(", ", parameters.Select(p => $"{p.Key}=\"{p.Value}\""));

if (CurrentHttpContext != null)
{
var httpResponse = CurrentHttpContext.Response;
var headers = httpResponse.Headers;
httpResponse.StatusCode = (int)HttpStatusCode.Forbidden;
httpResponse ??= CurrentHttpContext?.Response;

headers[HeaderNames.WWWAuthenticate] = new StringValues($"{Constants.Bearer} {parameterString}");
if (httpResponse == null)
{
throw new InvalidOperationException(IDWebErrorMessage.HttpContextAndHttpResponseAreNull);
}

var headers = httpResponse.Headers;
httpResponse.StatusCode = (int)HttpStatusCode.Forbidden;

headers[HeaderNames.WWWAuthenticate] = new StringValues($"{Constants.Bearer} {parameterString}");
}

private static bool AcceptedTokenVersionMismatch(MsalUiRequiredException msalSeviceException)
private static bool AcceptedTokenVersionMismatch(MsalUiRequiredException msalServiceException)
{
// Normally app developers should not make decisions based on the internal AAD code
// however until the STS sends sub-error codes for this error, this is the only
// way to distinguish the case.
// This is subject to change in the future
return msalSeviceException.Message.Contains(ErrorCodes.B2CPasswordResetErrorCode, StringComparison.InvariantCulture);
return msalServiceException.Message.Contains(ErrorCodes.B2CPasswordResetErrorCode, StringComparison.InvariantCulture);
}

private async Task<ClaimsPrincipal?> GetAuthenticatedUserAsync(ClaimsPrincipal? user)
Expand Down

0 comments on commit bd0c266

Please sign in to comment.