Reputation: 34028
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
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
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