Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Throw an ArgumentException if tenant is 'common' or 'organizations' for acquire token for app scenarios #795

Merged
merged 5 commits into from
Dec 2, 2020

Conversation

hajekj
Copy link
Contributor

@hajekj hajekj commented Dec 1, 2020

  • Added common tenant to meta tenant identifiers since client_credentials flow cannot be used without explicit tenant.
  • Check TenantId value against the above list as well, like with explicitly passed tenant.

Fixes #793

Add support for tenant selection when using AppOnly Microsoft Graph. …
…ot to match when obtaining token via client_credentials flow.

Fixes AzureAD#793
Copy link
Collaborator

@jmprieur jmprieur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your PR, @hajekj
actually, I believe that Consumers should be allowed (for some first party scenarios)

@hajekj
Copy link
Contributor Author

hajekj commented Dec 1, 2020

So what would be the best way to approach this? It's the first time I hear, that it's possible with consumers endpoint. So you think it would be the best to skip the validation for Consumers endpoint? Because right now, the check is being done against Consumers and Organizations and Common was skipped out (https://github.com/AzureAD/microsoft-identity-web/blob/master/src/Microsoft.Identity.Web/TokenAcquisition.cs#L86).

@bgavrilMS
Copy link
Member

consumers is essentially a single (huge) tenant, while organizations and common are not tenants, they are descriptors to tell AAD "I don't know what tenant I want, you figure it out for me". These 2 descriptors should not be used in conjunction with client_creds grant.

@hajekj
Copy link
Contributor Author

hajekj commented Dec 1, 2020

Gotcha, makes sense! I have updated the code to omit the consumers endpoint from validation. Would that be okay now?

@jmprieur
Copy link
Collaborator

jmprieur commented Dec 1, 2020

Thanks @hajekj. I think this is ok.
Let's have @jennyf19 review and merge.

@@ -276,6 +276,11 @@ internal class TokenAcquisition : ITokenAcquisitionInternal
throw new ArgumentException(IDWebErrorMessage.ClientCredentialTenantShouldBeTenanted, nameof(tenant));
}

if (!string.IsNullOrEmpty(_microsoftIdentityOptions.TenantId) && _metaTenantIdentifiers.Contains(_microsoftIdentityOptions.TenantId))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't needed. We already are checking the tenant in the lines above (starting line 274), and the developer needs to specifically pass in the tenant in this method, so it doesn't matter what the tenant is with the options. They could even be different tenants, we just care about the one passed in.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not 100% sure about that, since it either takes the provided tenant or uses the Authority (https://github.com/AzureAD/microsoft-identity-web/blob/master/src/Microsoft.Identity.Web/TokenAcquisition.cs#L703) passed from within the options passed to MSAL, that's why I added this part.

The reason is to cover a scenario, where someone sets up the authority in settings as common for example, and would then call GetAccessTokenForAppAsync(scope) without explicitly provided tenant which won't work and AAD will return an error, so this check prevents the request reaching AAD at all.

I am perfectly fine with removing it of course. Please let me know, what makes more sense.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hajekj I see. thanks for the explanation. I would propose something like this starting on line 274:

if (string.IsNullOrEmpty(tenant))
{
        tenant = _applicationOptions.TenantId ?? _microsoftIdentityOptions.TenantId;
}

if (!string.IsNullOrEmpty(tenant) && _metaTenantIdentifiers.Contains(tenant))
{
       throw new ArgumentException(IDWebErrorMessage.ClientCredentialTenantShouldBeTenanted, nameof(tenant));
}

then we'll always have a value for the tenant, or not, and it will be handled before we create the authority. and the authority will have the tenanted value.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PS...i haven't tested it, just a thought.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. I have added the change and tested locally with very limited scenario. Seems to work fine, but would be great to hook it up with some more tests, especially when the application is configured as multi-tenant with TenantId set to common or organizations in configuration.

@@ -86,8 +86,8 @@ internal class TokenAcquisition : ITokenAcquisitionInternal
private readonly ISet<string> _metaTenantIdentifiers = new HashSet<string>(
new[]
{
Constants.Common,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the only fix that is needed. Can you add a test as well? or modify an existing test?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure! Will add it tomorrow.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hajekj Actually, nevermind on the tests, you'll need access to our KeyVault to run the tests that would cover this. If you can take a look at the comment above, and then once we merge this, i will add the test(s). If you can test manually though and share the results (assuming it works), that would be helpful.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a branch with some additional tests for the work you have here. will merge after we merge this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!

…obtaining token via client_credentials. Streamline argument validation.
Copy link
Collaborator

@jennyf19 jennyf19 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you so much for all your work in this area @hajekj much appreciated.

@jennyf19 jennyf19 merged commit d566dca into AzureAD:master Dec 2, 2020
@hajekj hajekj deleted the 793 branch December 3, 2020 10:17
@jennyf19
Copy link
Collaborator

@hajekj nice blog post! mind if we link to it from our wiki?

@jennyf19
Copy link
Collaborator

@hajekj also, in regards to this...
image
if you got it to work, we'll help support it (what a great surprise for us). just open issues here if you need help w/anything. we'll probably try it out in the coming weeks. thanks again!

@hajekj
Copy link
Contributor Author

hajekj commented Dec 13, 2020

@jennyf19 Feel free to link or re-use in any way you want! I will update the blog post later today to update the information about the support!

Update: Article updated. Thank you for this. I have put this repo on my watch list, so if there are any issues, I will try to take a look into those as well!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Bug] throw an ArgumentException if tenant is 'common' or 'organizations' for acquire token for app scenarios
4 participants