Rob Lyndon
Rob Lyndon

Reputation: 12651

Azure Active Directory: Consent Framework has stopped granting consent

I have just written an app with Azure Active Directory Single Sign-On.

The consent framework is handled in the AccountController, in the ApplyForConsent action listed below. Until recently, everything has worked seamlessly. I could grant consent as an admin user of an external tenant, then sign out of the app, and sign in again as a non-admin user.

My Azure Active Directory app requires the following delegated permissions:

Now, after I have gone through the consent framework (by POSTing from a form to ApplyForConsent as an admin user), signing in as a non-admin user fails with the error message AADSTS90093 (This operation can only be performed by an administrator). Unhelpfully, the error message doesn't say what "this operation" actually is, but I suspect it is the third one (Access your organisation's directory).

I stress again, this has only recently stopped working. Nothing has changed in this part of the code, although I grant it is possible that other changes elsewhere in the codebase may have had knock-on effects of which I remain blissfully ignorant.

Looking at the documentation, it seems that this use of the consent framework is already considered "Legacy", but I'm having a difficult time finding a more up-to-date implementation.

The requested permissions in the code sample below is the single string "DirectoryReaders".

I have three questions for helping me debug this code:

  1. What is the difference between "Read directory data" and "Access your organisation's directory"? When would I need one rather than another?
  2. Do I need to request more than just "DirectoryReaders"?
  3. Is there now a better way to implement the Consent Framework?

This is the existing code:

private static readonly string ClientId = ConfigurationManager.AppSettings["ida:ClientID"];

[HttpPost]
public ActionResult ApplyForConsent()
{
    string signupToken = Guid.NewGuid().ToString();
    string replyUrl = Url.Action("ConsentCallback", "Account", new { signupToken }, Request.Url.Scheme);
    DatabaseIssuerNameRegistry.CleanUpExpiredSignupTokens();
    DatabaseIssuerNameRegistry.AddSignupToken(signupToken, DateTimeOffset.UtcNow.AddMinutes(5));
    return new RedirectResult(CreateConsentUrl(ClientId, "DirectoryReaders", replyUrl));
}

[HttpGet]
public ActionResult ConsentCallback()
{
    string tenantId = Request.QueryString["TenantId"];
    string signupToken = Request.QueryString["signupToken"];
    if (DatabaseIssuerNameRegistry.ContainsTenant(tenantId))
    {
        return RedirectToAction("Validate");
    }

    string consent = Request.QueryString["Consent"];
    if (!String.IsNullOrEmpty(tenantId) && String.Equals(consent, "Granted", StringComparison.OrdinalIgnoreCase))
    {
        if (DatabaseIssuerNameRegistry.TryAddTenant(tenantId, signupToken))
        {
            return RedirectToAction("Validate");
        }
    }

    const string error = "Consent could not be provided to your Active Directory.  Please contact SharpCloud for assistance.";
    var reply = Request.Url.GetLeftPart(UriPartial.Authority) + Url.Action("Consent", new { error });
    var config = FederatedAuthentication.FederationConfiguration.WsFederationConfiguration;
    var signoutMessage = new SignOutRequestMessage(new Uri(config.Issuer), reply);
    signoutMessage.SetParameter("wtrealm", config.Realm);
    FederatedAuthentication.SessionAuthenticationModule.SignOut();
    return Redirect(signoutMessage.WriteQueryString());
}

private static string CreateConsentUrl(string clientId, string requestedPermissions, string consentReturnUrl)
{
    string consentUrl = String.Format(CultureInfo.InvariantCulture, ConsentUrlFormat, HttpUtility.UrlEncode(clientId));

    if (!String.IsNullOrEmpty(requestedPermissions))
    {
        consentUrl += "&RequestedPermissions=" + HttpUtility.UrlEncode(requestedPermissions);
    }
    if (!String.IsNullOrEmpty(consentReturnUrl))
    {
        consentUrl += "&ConsentReturnURL=" + HttpUtility.UrlEncode(consentReturnUrl);
    }

    return consentUrl;
}

Upvotes: 0

Views: 432

Answers (2)

Rob Lyndon
Rob Lyndon

Reputation: 12651

My suspicion was correct. I was using legacy tech in the question. By moving to Owin and Identity 2.0, all issues were solved.

The new approach is summarised by https://github.com/AzureADSamples/WebApp-GroupClaims-DotNet

Upvotes: 0

Rich Randall
Rich Randall

Reputation: 1982

I think this link addresses your issue:

http://blogs.msdn.com/b/aadgraphteam/archive/2015/03/19/update-to-graph-api-consent-permissions.aspx

The quick summary is that now only admins can grant consent to a web app for '•Access your organisation's directory'.

This change was made back in March. Native apps are not affected by the change.

Upvotes: 1

Related Questions