Luis Valencia
Luis Valencia

Reputation: 34028

Authorization in Cloud Applications using AD Groups issue with new group

I have an asp.net mvc application and my code is based on this article: http://www.dushyantgill.com/blog/2014/12/10/authorization-cloud-applications-using-ad-groups/

and on this sample code: https://github.com/dushyantgill/VipSwapper/tree/master/TrainingPoint

I created a controller for the global admin

public class GlobalAdminController : Controller
    {
        // GET: GlobalAdmin
        [AuthorizeUser(Roles = "admin")]
        public ActionResult Index()
        {
            return View();
        }
    }

and this is the startup.cs

public void ConfigureAuth(IAppBuilder app)
        {
            // configure the authentication type & settings
            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
            app.UseCookieAuthentication(new CookieAuthenticationOptions());

            // configure the OWIN OpenId Connect options
            app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
            {
                ClientId = SettingsHelper.ClientId,
                Authority = SettingsHelper.AzureADAuthority,
                TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
                {
                    // we inject our own multitenant validation logic
                    ValidateIssuer = false,
                    // map the claimsPrincipal's roles to the roles claim
                    RoleClaimType = "roles",
                },
                Notifications = new OpenIdConnectAuthenticationNotifications()
                {
                    RedirectToIdentityProvider = (context) =>
                    {
                        // This ensures that the address used for sign in and sign out is picked up dynamically from the request
                        // this allows you to deploy your app (to Azure Web Sites, for example) without having to change settings
                        // Remember that the base URL of the address used here must be provisioned in Azure AD beforehand.
                        //string appBaseUrl = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase;
                        context.ProtocolMessage.RedirectUri = HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path);
                        context.ProtocolMessage.PostLogoutRedirectUri = new UrlHelper(HttpContext.Current.Request.RequestContext).Action("Index", "Home", null, HttpContext.Current.Request.Url.Scheme);
                        context.ProtocolMessage.Resource = SettingsHelper.GraphResourceId;

                        return Task.FromResult(0);
                    },

                    // when an auth code is received...
                    AuthorizationCodeReceived = (context) => {
                        // get the OpenID Connect code passed from Azure AD on successful auth
                        string code = context.Code;

                        // create the app credentials & get reference to the user
                        ClientCredential creds = new ClientCredential(SettingsHelper.ClientId, SettingsHelper.ClientSecret);
                        string userObjectId = context.AuthenticationTicket.Identity.FindFirst(System.IdentityModel.Claims.ClaimTypes.NameIdentifier).Value;

                        // use the ADAL to obtain access token & refresh token...
                        //  save those in a persistent store...
                        EfAdalTokenCache sampleCache = new EfAdalTokenCache(userObjectId);
                        AuthenticationContext authContext = new AuthenticationContext(SettingsHelper.AzureADAuthority, sampleCache);

                        // obtain access token for the AzureAD graph
                        Uri redirectUri = new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path));
                        AuthenticationResult authResult = authContext.AcquireTokenByAuthorizationCode(code, redirectUri, creds, SettingsHelper.AzureAdGraphResourceId);

                        if (GraphUtil.IsUserAADAdmin(context.AuthenticationTicket.Identity))
                            context.AuthenticationTicket.Identity.AddClaim(new Claim("roles", "admin"));

                        // successful auth
                        return Task.FromResult(0);
                    },
                    AuthenticationFailed = (context) => {
                        context.HandleResponse();
                        return Task.FromResult(0);
                    }
                }
            });
        }
    }

This works perfectly fine if I login with a user which is in the global admin on the organization: http://screencast.com/t/jLVNWGN7MgZR

However I created another group and added a user to that group: The group is called Company Admin, and the user companyadmin@

Group http://screencast.com/t/Y6vueAxjRPo

Group Members http://screencast.com/t/BBRUoOxaD

And I created another controller:

 public class CompanyAdminController : Controller
    {
        [AuthorizeUser(Roles = "company admin")]
        public ActionResult Index()
        {
            return View();
        }
    }

I also have this on my home index controller action

public ActionResult Index()
        {
            if (User.IsInRole("admin"))
            {
                return RedirectToAction("Index", "GlobalAdmin");
            }
            if (User.IsInRole("company admin"))
            {
                return RedirectToAction("Index", "CompanyAdmin");
            }
            return View();
        }

However the User.IsInRole does not return true for company admin. http://screencast.com/t/msVfvUt1g

Update 1

It looks like the group is indeed being returned on the claim, it just looks like the authorize does not work the right way or I am missing some piece of code.

Group id screenshot: http://screencast.com/t/0Doz9DcD

Claim screenshot: http://screencast.com/t/tbRGJPoc

Upvotes: 0

Views: 1372

Answers (2)

Luis Valencia
Luis Valencia

Reputation: 34028

The most important part of the answer due that bluefeet moderator and martij Pieters moderators deleted my answer is here on the owin pipeline

var groups = GraphUtil.GetMemberGroups(context.AuthenticationTicket.Identity).Result;
                        //For each group, we have its, ID, we need to get the display name, and then we have to add the claim
                        foreach(string groupid in groups)
                        {
                            var displayname=GraphUtil.LookupDisplayNameOfAADObject(groupid, context.AuthenticationTicket.Identity);
                            context.AuthenticationTicket.Identity.AddClaim(new Claim("roles", displayname));
                        }

However, Stackoverflow does not allow more than 30,000 characters and the answer is about 45,000 characters, so for the readers you can go here for a full explanation: http://www.luisevalencia.com/2015/06/02/using-azure-aad-graph-office-365-add-in-with-groups-authorization/

Upvotes: 0

Dushyant Gill
Dushyant Gill

Reputation: 4004

groups in Azure AD are a collection of principals (users, services, groups). Whereas app roles in Azure AD represent a collection of permissions on the app. User's group membership doesn't appear in the roles claim. An application declares its roles to Azure AD (e.g. admin, reader, writer). When an organization purchases/deploys the app, the admin of that org can then assign users/groups/services from their organization to roles of the app (e.g. [email protected] -> admin of app, project1team group -> writer of app, all users group -> reader of app). Then when a user signs in to the app, Azure AD issues a roles claim and specifies all app roles assigned to the user (direct assignment or via a group). More details here: http://blogs.technet.com/b/ad/archive/2014/12/18/azure-active-directory-now-with-group-claims-and-application-roles.aspx

So, for your example, it seems that you need to create an app role called company admin and allow the customers of your app to assign users/groups to that role.

Hope that helps.

I'm curious, are you creating an app that helps manage Azure AD identities?

Upvotes: 2

Related Questions