Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code example does not handle OData error to process the CAE challenge from Microsoft Graph. #754

Open
JakubHromada opened this issue Jan 11, 2024 · 1 comment
Labels
question Further information is requested

Comments

@JakubHromada
Copy link

JakubHromada commented Jan 11, 2024

Microsoft.Identity.Web version

2.16.1

Web app sign-in

Not applicable

Web API (call Graph or downstream APIs)

2-WebApp-graph-user/2-1-Call-MSGraph

Deploy to Azure

Not applicable

Auth Z

Not applicable

Description

The process to handle CAE challenges from MS Graph by catching a ServiceException doesn't work. Upon revoking user session the GraphServiceClient now returns ODataError exception with the requested claims. The code example is not handling this type of exception.

Please update the code example to handle the OData exception to process the CAE challenge from Microsoft Graph.

Reproduction steps

  1. User signs in to web app
  2. Admin revokes all sessions for user in Entra Id
  3. User tries to access Profile page

Error message

ODataError: Continuous access evaluation resulted in challenge with result: InteractionRequired and code: TokenIssuedBeforeRevocationTimestamp

Id Web logs

No response

Relevant code snippets

[AuthorizeForScopes(ScopeKeySection = "DownstreamApi:Scopes")]
public async Task<IActionResult> Profile()
{
    User currentUser = null;

    try
    {
        currentUser = await _graphServiceClient.Me.GetAsync();
    }
    // Catch CAE exception from Graph SDK - This is not ServiceException anymore, the correct exception to catch is ODataError
    catch (ServiceException svcex) when (svcex.Message.Contains("Continuous access evaluation resulted in claims challenge"))
    {
        try
        {
            Console.WriteLine($"{svcex}");
            string claimChallenge = WwwAuthenticateParameters.GetClaimChallengeFromResponseHeaders(svcex.ResponseHeaders);
            _consentHandler.ChallengeUser(_graphScopes, claimChallenge);
            return new EmptyResult();
        }
        catch (Exception ex2)
        {
            _consentHandler.HandleException(ex2);
        }
    }

    try
    {
        // Get user photo
        using (var photoStream = await _graphServiceClient.Me.Photo.Content.GetAsync())
        {
            byte[] photoByte = ((MemoryStream)photoStream).ToArray();
            ViewData["Photo"] = Convert.ToBase64String(photoByte);
        }
    }
    catch (Exception pex)
    {
        Console.WriteLine($"{pex.Message}");
        ViewData["Photo"] = null;
    }

    ViewData["Me"] = currentUser;
    return View();
}

Regression

No response

Expected behavior

Process the CAE challenge from Microsoft Graph.

@JakubHromada JakubHromada added the question Further information is requested label Jan 11, 2024
@anaugust113
Copy link

anaugust113 commented Mar 21, 2024

using Microsoft.Graph.Models.ODataErrors;

To solve the issue, you can update the Profile() function in HomeController.cs to:
public async Task Profile()
{
User currentUser = null;

try
{
    currentUser = await _graphServiceClient.Me.GetAsync();
}
// Catch CAE exception from Graph SDK
catch (ODataError svcex) when (svcex.Message.Contains("Continuous access evaluation resulted in challenge"))
//catch (ServiceException svcex) when (svcex.Message.Contains("Continuous access evaluation resulted in challenge"))
{
    try
    {

        // Assuming svcex.ResponseHeaders is of type IDictionary<string, IEnumerable<string>>
        HttpResponseHeaders httpResponseHeaders = new HttpResponseMessage().Headers;
        foreach (var header in svcex.ResponseHeaders)
        {
            string headerName = header.Key;
            foreach (var headerValue in header.Value)
            {
                httpResponseHeaders.TryAddWithoutValidation(headerName, headerValue);
            }
        }

        Console.WriteLine($"{svcex}");
        string claimChallenge = WwwAuthenticateParameters.GetClaimChallengeFromResponseHeaders(httpResponseHeaders);
        _consentHandler.ChallengeUser(_graphScopes, claimChallenge);
        return new EmptyResult();
    }
    catch (Exception ex2)
    {
        _consentHandler.HandleException(ex2);
    }
}

try
{
    // Get user photo
    using (var photoStream = await _graphServiceClient.Me.Photo.Content.GetAsync())
    {
        byte[] photoByte = ((MemoryStream)photoStream).ToArray();
        ViewData["Photo"] = Convert.ToBase64String(photoByte);
    }
}
catch (Exception pex)
{
    Console.WriteLine($"{pex.Message}");
    ViewData["Photo"] = null;
}

ViewData["Me"] = currentUser;
return View();

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants