4
votes

We have an Azure web-app which is authenticated via Azure Multifactor authentication and accesses Graph API and Power BI. We have setup the required permissions on Azure App registration. We are using Redis cache to store the Token details in NaiveSessionCache. For few users, we are getting the following error when the user tries to log in.

AADSTS50079: The user is required to use multi-factor authentication

"AADSTS50079: The user is required to use multi-factor authentication.\r\nTrace ID: 63c180a9-6951-4a8a-96ca-e1ff38fc4400\r\nCorrelation ID: 3f12d4b1-d401-4d99-be30-36bf972d74a5\r\nTimestamp: 2017-08-21 14:21:59Z","parsedStack":[{"assembly":"Microsoft.IdentityModel.Clients.ActiveDirectory, Version=3.13.9.1126, Culture=neutral, PublicKeyToken=31bf3856ad364e35","method":"Microsoft.IdentityModel.Clients.ActiveDirectory.AdalHttpClient+d__211.MoveNext","level":0,"line":0},{"assembly":"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089","method":"System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess","level":1,"line":0},{"assembly":"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089","method":"System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification","level":2,"line":0},{"assembly":"Microsoft.IdentityModel.Clients.ActiveDirectory, Version=3.13.9.1126, Culture=neutral, PublicKeyToken=31bf3856ad364e35","method":"Microsoft.IdentityModel.Clients.ActiveDirectory.AdalHttpClient+<GetResponseAsync>d__201.MoveNext","level":3,"line":0},{"assembly":"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089","method":"System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess","level":4,"line":0},{"assembly":"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089","method":"System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification","level":5,"line":0},{"assembly":"Microsoft.IdentityModel.Clients.ActiveDirectory, Version=3.13.9.1126, Culture=neutral, PublicKeyToken=31bf3856ad364e35","method":"Microsoft.IdentityModel.Clients.ActiveDirectory.AcquireTokenHandlerBase+d__67.MoveNext","level":6,"line":0},{"assembly":"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089","method":"System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess","level":7,"line":0},{"assembly":"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089","method":"System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification","level":8,"line":0},{"assembly":"Microsoft.IdentityModel.Clients.ActiveDirectory, Version=3.13.9.1126, Culture=neutral, PublicKeyToken=31bf3856ad364e35","method":"Microsoft.IdentityModel.Clients.ActiveDirectory.AcquireTokenHandlerBase+d__64.MoveNext","level":9,"line":0},{"assembly":"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089","method":"System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess","level":10,"line":0},{"assembly":"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089","method":"System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification","level":11,"line":0},{"assembly":"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089","method":"System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd","level":12,"line":0},{"assembly":"Microsoft.IdentityModel.Clients.ActiveDirectory, Version=3.13.9.1126, Culture=neutral, PublicKeyToken=31bf3856ad364e35","method":"Microsoft.IdentityModel.Clients.ActiveDirectory.AcquireTokenHandlerBase+d__55.MoveNext","level":13,"line":0},{"assembly":"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089","method":"System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess","level":14,"line":0},{"assembly":"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089","method":"System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification","level":15,"line":0},{"assembly":"Microsoft.IdentityModel.Clients.ActiveDirectory, Version=3.13.9.1126, Culture=neutral, PublicKeyToken=31bf3856ad364e35","method":"Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext+d__48.MoveNext","level":16,"line":0},{"assembly":"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089","method":"System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess","level":17,"line":0},{"assembly":"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089","method":"System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification","level":18,"line":0},{"assembly":"Microsoft.IdentityModel.Clients.ActiveDirectory, Version=3.13.9.1126, Culture=neutral, PublicKeyToken=31bf3856ad364e35","method":"Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext+d__30.MoveNext","level":19,"line":0},{"assembly":"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089","method":"System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess","level":20,"line":0},{"assembly":"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089","method":"System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification","level":21,"line":0},{"assembly":"Assembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null","method":"Startup+<>c+<b__8_0>d.MoveNext","level":22,"line":68,"fileName":"App_Start\Startup.Auth.cs"}],"type":"Microsoft.IdentityModel.Clients.ActiveDirectory.AdalServiceException","id":"52129856"

Here is the startup.cs file used for recieveing the authorization code.

public void ConfigureAuth(IAppBuilder app){ try {

            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

            app.UseCookieAuthentication(new CookieAuthenticationOptions());

            app.UseOpenIdConnectAuthentication(
                new OpenIdConnectAuthenticationOptions
                {
                    ClientId = clientId,
                    Authority = Authority,
                    PostLogoutRedirectUri = postLogoutRedirectUri,
                    AuthenticationMode = AuthenticationMode.Active,
                    Notifications = new OpenIdConnectAuthenticationNotifications()
                    {
                        // If there is a code in the OpenID Connect response, redeem it for an access token and refresh token, and store those away.
                        AuthorizationCodeReceived = async (context) =>
                        {
                            try {
                                IConnectionString _connectionString = new RedisConnectionString(ConfigurationReader.RedisCacheConfig as string);

                                ICacheManager cacheManager = new RedisCacheManager(_connectionString);
                                var code = context.Code;
                                ClientCredential credential = new ClientCredential(clientId, appKey);
                                string signedInUserID = context.AuthenticationTicket.Identity.FindFirst(Constants.OBJECT_IDENTIFIER).Value;

                                AuthenticationContext authContext = new AuthenticationContext(Authority, new NaiveSessionCache(signedInUserID));
                                //Getting Power BI token
                                AuthenticationResult result = await authContext.AcquireTokenByAuthorizationCodeAsync(
                                    code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, pbiResourceID);

                                //Getting Graph token
                                AuthenticationResult graphResult = await authContext.AcquireTokenByAuthorizationCodeAsync(
                                    code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, graphResourceId);
                                UserTokenCache cache = new UserTokenCache
                                {
                                    GraphAccessToken = graphResult.AccessToken,
                                    PBIAccessToken = result.AccessToken,
                                    PBITokenExpires = result.ExpiresOn,
                                    GraphTokenExpires = graphResult.ExpiresOn
                                };

                                string encryptedCache = CryptographyUtility.Encrypt(JsonConvert.SerializeObject(cache));

                                cacheManager.set(signedInUserID, encryptedCache);
                            } catch (Exception ex)
                            {
                                ExceptionLogger.LogInApplicationInsight(ex);
                            }
                        },
                        AuthenticationFailed = async (context) =>
                        {
                            ExceptionLogger.LogInApplicationInsight(context.Exception);
                            await Task.FromResult(0);
                        }

                    }
                });
        }
        catch (SystemException sx)
        {
            ExceptionLogger.LogInApplicationInsight(sx);
        }
        catch (ApplicationException ax)
        {
            ExceptionLogger.LogInApplicationInsight(ax);
        }
        catch (Exception ex)
        {
            ExceptionLogger.LogInApplicationInsight(ex);
        }
    }

Am I missing something here? Few users are not able to get the tokens due to this and embedded Power BI reports are not loading

1

1 Answers

5
votes

This error indicates the user needs to enroll or perform multi-factor authentication.

500079: Enroll in MFA

500076: User must perform MFA

To resolve both of these it's the same protocol. Your app needs to perform an interactive request specifying the resource that failed.

Let's say your trying to get a token for the Microsoft Graph which requires MFA. You may already have a refresh token granted for another resource (or have signed in without requesting a resource), then you ask Azure AD for a new token for the Microsoft Graph. This request is on the /token endpoint which is a POST and cannot perform MFA. Your app should then catch this error, and perform a new request (with either an AcquireToken or OWIN OpenId Connect Challenge) asking for resource=https://graph.microsoft.com or whatever resource failed.