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

Add support for the AzureSDK #542

Merged
merged 3 commits into from
Mar 31, 2021
Merged

Add support for the AzureSDK #542

merged 3 commits into from
Mar 31, 2021

Conversation

jmprieur
Copy link
Collaborator

@jmprieur jmprieur commented Sep 3, 2020

See https://github.com/tamram/storage-dotnet-azure-ad-msal/tree/tamram-0818

        [AuthorizeForScopes(Scopes = new string[] { "https://storage.azure.com/user_impersonation" })]
        public async Task<IActionResult> Blob()
        {
            var scopes = new string[] { "https://storage.azure.com/user_impersonation" }; // I guess the Blob SDK knows already?
            ViewData["Message"] = await CreateBlob(new TokenAcquisitionTokenCredential(_tokenAcquisition),);
            return View();
        }

        private static async Task<string> CreateBlob(TokenAcquisitionTokenCredential tokenCredential)
        {
            // Replace the URL below with the URL to your blob.
            Uri blobUri = new Uri("https://storagesamples.blob.core.windows.net/sample-container/blob1.txt");
            BlobClient blobClient = new BlobClient(blobUri, tokenCredential);

            // Create a blob on behalf of the user.
            string blobContents = "Blob created by Azure AD authenticated user.";
            byte[] byteArray = Encoding.ASCII.GetBytes(blobContents);

            using (MemoryStream stream = new MemoryStream(byteArray))
            {
                await blobClient.UploadAsync(stream);
            }
            return "Blob successfully created";
        }

See https://github.com/tamram/storage-dotnet-azure-ad-msal/tree/tamram-0818

```
[AuthorizeForScopes(Scopes = new string[] { "https://storage.azure.com/user_impersonation" })]
        public async Task<IActionResult> Blob()
        {
            var scopes = new string[] { "https://storage.azure.com/user_impersonation" }; // I guess the Blob SDK knows already?
            ViewData["Message"] = await CreateBlob(new TokenAcquisitionTokenCredential(_tokenAcquisition),);
            return View();
        }

        private static async Task<string> CreateBlob(TokenAcquisitionTokenCredential tokenCredential)
        {
            // Replace the URL below with the URL to your blob.
            Uri blobUri = new Uri("https://storagesamples.blob.core.windows.net/sample-container/blob1.txt");
            BlobClient blobClient = new BlobClient(blobUri, tokenCredential);

            // Create a blob on behalf of the user.
            string blobContents = "Blob created by Azure AD authenticated user.";
            byte[] byteArray = Encoding.ASCII.GetBytes(blobContents);

            using (MemoryStream stream = new MemoryStream(byteArray))
            {
                await blobClient.UploadAsync(stream);
            }
            return "Blob successfully created";
        }
```
@jmprieur
Copy link
Collaborator Author

@schaabs : do you want to have a look?

@jmprieur jmprieur marked this pull request as ready for review March 9, 2021 20:49
@jmprieur jmprieur added this to the 1.9.0 milestone Mar 9, 2021
@jmprieur
Copy link
Collaborator Author

jmprieur commented Mar 10, 2021

@jennyf19
I met with @schaabs yesterday night and he likes this.

cc: @henrik-me : we are going to take this PR

AuthenticationResult result = _tokenAcquisition.GetAuthenticationResultForUserAsync(requestContext.Scopes)
.GetAwaiter()
.GetResult();
return new AccessToken(result.AccessToken, result.ExpiresOn);
Copy link
Collaborator

Choose a reason for hiding this comment

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

could result be null?

public override async ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
{
AuthenticationResult result = await _tokenAcquisition.GetAuthenticationResultForUserAsync(requestContext.Scopes).ConfigureAwait(false);
return new AccessToken(result.AccessToken, result.ExpiresOn);
Copy link
Collaborator

Choose a reason for hiding this comment

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

same as above, and how do we test this?

@jennyf19 jennyf19 merged commit 9dc6f8d into master Mar 31, 2021
@jennyf19 jennyf19 deleted the jmprieur/supportAzureSdk branch March 31, 2021 16:12
@jennyf19
Copy link
Collaborator

Included in 1.9.0 release

@harris-boyce
Copy link

@jmprieur What would it look like when developing a multi-tenant application with requirements to authenticate as an application/service principal? Would it be best to use Client[Secret|Certificate]Credential and let Azure.Identity handle token cache?

@maliksahil
Copy link
Contributor

@harris-boyce please see this for authenticating using managed identity. Note that SPs currently do not work cross-tenant in the way you describe. https://docs.microsoft.com/en-us/azure/storage/blobs/authorize-managed-identity

@jmprieur
Copy link
Collaborator Author

Microsoft.Identity.Web leverages Azure.Identity to get the client certs and decrypt certs from keyvault.
What else would you need. @harris-boyce ?

@harris-boyce
Copy link

Microsoft.Identity.Web leverages Azure.Identity to get the client certs and decrypt certs from keyvault. What else would you need. @harris-boyce ?

@jmprieur My scenarios cover the need to leverage the Azure SDK management libraries to operate against Azure resources as both the app principal and on-behalf-of the signed in user. For example:

  • User -> OBO token (tokenAcquisition.GetAccessTokenForUserAsync(tenantId)) -> GET https://mgmt.az.com/subscriptions -> PUT https://mgmt.az.com/subs/rg/Ms.Authz/roleAssignment
  • App -> App token (tokenAcquisition.GetAccessTokenForAppAsync(tenantId)) -> GET https://mgmt.az.com/subscriptions

In both cases above, tenantId is intended to be the home tenant of the signed in user and the Web App is registered as a multi-tenant application (SaaS scenario).

I have worked around this thus far by creating my own implementations of TokenAcquisitionTokenCredential that call GetAuthenticationResultFor[User|App]Async(), where appropriate, and supply the tenant Id explicitly in GetToken.

I would be willing to contribute this code to the project as it feels like this could be a valid use case beyond my scenarios. Thoughts?

@harris-boyce please see this for authenticating using managed identity. Note that SPs currently do not work cross-tenant in the way you describe. https://docs.microsoft.com/en-us/azure/storage/blobs/authorize-managed-identity

@maliksahil I'm not sure why this would be the case; my understanding is that managed identities are simply special implementations of Service Principals, so why wouldn't I be able to grant RBAC Data Reader rights to a service principal and use it to perform operations against a storage account?

@jmprieur
Copy link
Collaborator Author

@harris-boyce : sure, feel free to contribute. Would it be a change on TokenAcquisitionTokenCredential?

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.

4 participants