ChrisW
ChrisW

Reputation: 9399

Using the MVC Authorize attribute with roles using Azure Active Directory + OWIN

I'm building a multi-tenant MVC5 app that follows very closely the sample guidance: https://github.com/AzureADSamples/WebApp-MultiTenant-OpenIdConnect-DotNet/

I'm authenticating against Azure Active Directory and have my own role names that I inject as a Role claim during the SecurityTokenvalidated event:

SecurityTokenValidated = (context) =>
                    {
                        // retriever caller data from the incoming principal
                        string upn = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.Name).Value;
                        string tenantId = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;

                        var databaseConnectionString = RoleEnvironment.GetConfigurationSettingValue("DatabaseConnectionString");

                        AppAnalyzerUser appAnalyzerUser = null;

                        using (CloudContext dbContext = new CloudContext(databaseConnectionString))
                        {
                            if (dbContext.Office365Accounts.FirstOrDefault(x => x.AzureTokenId == tenantId) == null)
                                throw new GeneralErrorException("Account not found", "The domain that you used to authenticate has not registered.");

                            appAnalyzerUser = (from au in dbContext.AppAnalyzerUsers
                                .Include(x => x.Roles)
                                where au.UserPrincipalName == upn && au.AzureTokenId == tenantId
                                select au).FirstOrDefault();

                            if (appAnalyzerUser == null)
                                throw new AccountNotFoundException();                                
                        }

                        foreach (var role in appAnalyzerUser.Roles)
                        {
                            Claim roleClaim = new Claim(ClaimTypes.Role, role.RoleName);
                            context.AuthenticationTicket.Identity.AddClaim(roleClaim);                                
                        }

                        return Task.FromResult(0);
                    },

I've decorated some methods with the Authorize attribute like this:

    [Authorize(Roles = "SystemAdministrator"), HttpGet]
    public ActionResult Index()
    {
        return View();
    }

and the authorize attribute correctly detects that a user is not in that role and sends them back to Azure to authenticate.

However what I see is that the user is already authenticated against Azure AD and is logged in to the app. They don't get the chance to choose a new user account on the Azure screen to log in. So when it bounces them back to Azure AD, Azure AD says "you're already logged in" and sends them right back to the app. The SecurityTokenValidated event fires repeatedly, over and over.

But the user still doesn't have the role required for the method, so they get bounced back to Azure for authentication, and obviously we get stuck in a loop.

Other than writing my own implementation of the Authorize attribute, is there some other approach to solve this problem?

Upvotes: 2

Views: 3304

Answers (1)

vibronet
vibronet

Reputation: 7394

Unfortunately you stumbled on a known issue of [Authorize]. For a description and possible solutions see https://github.com/aspnet/Mvc/issues/634 - at this point writing a custom attribute is probably the most streamlined workaround.

Upvotes: 3

Related Questions