Environment:
Two Azure ADs: Company, Customers
Company publishes an ASP.NET5 web app called Portal, the app is setup to be multi-tenant.
Customers have 2 user: user (who is just a user) and admin (who is a Global Administrator in the directory).
Portal, is initially set up to ask for 1 Application Permission: Read Directory Data
-
Here comes the flow that I went through, and I believe Azure AD misbehaves at multiple steps. Please point out if I am missing something.
- I open the web app, and first try to sign in as admin
- I have to consent to the Read Directory data permission, so I do that
- Application appears (I have no roles assigned yet, which is fine) -- so far everything works.
- I re-open the web-app in a new incognito session, and try to sign in as the user
- Now, I get [
AADSTS90093: This operation can only be performed by an administrator. Sign out and sign in as an administrator or contact one of your organization's administrators.
] -- the admin already consented, so why do I get this?? - I go to Company AD and change the application permissions to include Read & Write Directory data
- I go to Customer AD check the app Portal and the dashboard already shows the new permission listed. No one had to consent! The admin do not see any change even on next login. How is this not a security hole?
My understanding of https://msdn.microsoft.com/en-us/library/azure/dn132599.aspx is that Application Permissions are not deprecated.
UPDATE
My configuration in the WebApp:
app.UseOpenIdConnectAuthentication(options =>
{
options.ClientId = Configuration.Get("ActiveDirectory:ClientId");
options.Authority = String.Format(Configuration.Get("ActiveDirectory:AadInstance"), "common/"); //"AadInstance": "https://login.windows.net/{0}"
options.PostLogoutRedirectUri = Configuration.Get("ActiveDirectory:PostLogoutRedirectUri"); //"PostLogoutRedirectUri": "https://localhost:44300/"
options.TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
{
// The following commented-out line should work according to
// http://stackoverflow.com/questions/29317910/why-does-the-role-claim-have-incorrect-type
// But, it does not work in ASP.NET5 (currently), so see the "Hack." down below
// RoleClaimType = "roles",
ValidIssuers = new[] { "https://sts.windows.net/a1028d9b-bd77-4544-8127-d3d42b9baebb/", "https://sts.windows.net/47b68455-a2e6-4114-90d6-df89d8468abc/" }
};
options.Notifications = new OpenIdConnectAuthenticationNotifications
{
RedirectToIdentityProvider = (context) =>
{
// This ensures that the address used for sign in and sign out is picked up dynamically from the request,
// which is neccessary if we want to deploy the app to different URLs (eg. localhost/immerciti-dev, immerciti.azurewebsites.net/www.immerciti.com)
string appBaseUrl = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase;
context.ProtocolMessage.RedirectUri = appBaseUrl;
context.ProtocolMessage.PostLogoutRedirectUri = appBaseUrl;
return Task.FromResult(0);
},
AuthorizationCodeReceived = async context =>
{
// Get Access Token for User's Directory
try
{
var identity = (ClaimsIdentity)context.AuthenticationTicket.Principal.Identity;
// Hack. TODO: keep an eye on developments around here
foreach (var claim in identity.FindAll("roles"))
{
// Readd each role with the proper claim type
identity.AddClaim(new Claim(identity.RoleClaimType, claim.Value, claim.ValueType, claim.Issuer, claim.OriginalIssuer));
}
}
catch (AdalException)
{
context.HandleResponse();
context.Response.Redirect("/Error/ShowError?errorMessage=Were having trouble signing you in&signIn=true");
}
}
};
};