public async Task <Application> RegisterClientApplicationAsync( Application serviceApplication, string clientApplicationName, IEnumerable <string> tags = null, CancellationToken cancellationToken = default ) { try { tags ??= new List <string>(); Log.Information("Creating client application registration ..."); // Extract id of Oauth2PermissionScope for user impersonation var saApiOauth2PermissionScopeUserImpersonationList = serviceApplication .Api .Oauth2PermissionScopes .Where(scope => "User" == scope.Type && "user_impersonation" == scope.Value && scope.IsEnabled.GetValueOrDefault(false) ) .ToList(); if (saApiOauth2PermissionScopeUserImpersonationList.Count != 1 || !saApiOauth2PermissionScopeUserImpersonationList.First().Id.HasValue) { throw new Exception("Service appplication does not expose Oauth2PermissionScope for user impersonation."); } var saApiOauth2PermissionScopeUserImpersonationId = saApiOauth2PermissionScopeUserImpersonationList.First().Id.Value; var serviceApplicationUserImpersonationRequiredResourceAccess = new RequiredResourceAccess { ResourceAppId = serviceApplication.AppId, // service application ResourceAccess = new List <ResourceAccess> { new ResourceAccess { Id = saApiOauth2PermissionScopeUserImpersonationId, // "user_impersonation" Type = "Scope" } } }; var microsoftGraphUserReadRequiredResourceAccess = new RequiredResourceAccess { ResourceAppId = AzureAppsConstants.MicrosoftGraph.AppId, ResourceAccess = new List <ResourceAccess> { new ResourceAccess { Id = AzureAppsConstants.MicrosoftGraph.ResourceAccess["User.Read"], Type = "Scope" } } }; var clientApplicationRequiredResourceAccess = new List <RequiredResourceAccess>() { serviceApplicationUserImpersonationRequiredResourceAccess, microsoftGraphUserReadRequiredResourceAccess }; var clientApplicationPublicClientApplication = new Microsoft.Graph.PublicClientApplication { RedirectUris = new List <string> { "urn:ietf:wg:oauth:2.0:oob" } }; // Note: Oauth2AllowImplicitFlow will be enabled automatically since both // EnableIdTokenIssuance and EnableAccessTokenIssuance are set to true. // ODataType = null is a workaround for a bug: // https://github.com/microsoftgraph/msgraph-beta-sdk-dotnet/issues/87 var clientApplicationWebApplication = new WebApplication { //Oauth2AllowImplicitFlow = true, ImplicitGrantSettings = new ImplicitGrantSettings { ODataType = null, EnableIdTokenIssuance = true, EnableAccessTokenIssuance = true } }; var clientApplicationDefinition = new Application { DisplayName = clientApplicationName, IsFallbackPublicClient = true, IdentifierUris = new List <string> { $"https://{_tenantId.ToString()}/{clientApplicationName}" }, Tags = tags, SignInAudience = "AzureADMyOrg", RequiredResourceAccess = clientApplicationRequiredResourceAccess, PublicClient = clientApplicationPublicClientApplication, Web = clientApplicationWebApplication, PasswordCredentials = new List <PasswordCredential> { } }; var clientApplication = await _msGraphServiceClient .CreateApplicationAsync( clientApplicationDefinition, cancellationToken ); // Add Client Key PasswordCredential var clientKeyName = "Client Key"; await _msGraphServiceClient .AddApplication2YPasswordCredentialAsync( clientApplication, clientKeyName, cancellationToken ); // We need to create ServicePrincipal for this application. await _msGraphServiceClient .CreateApplicationServicePrincipalAsync( clientApplication, tags, cancellationToken ); // Get updated definition clientApplication = await _msGraphServiceClient .GetApplicationAsync( new Guid(clientApplication.Id), cancellationToken ); Log.Information("Created client application registration."); return(clientApplication); } catch (Exception) { Log.Error("Failed to created client application registration."); throw; } }
public async Task <Application> RegisterClientApplicationAsync( Application serviceApplication, string clientsApplicationName, string azureWebsiteName, // ToDo: This should be set after App Service is deployed. IEnumerable <string> tags = null, CancellationToken cancellationToken = default ) { tags = tags ?? new List <string>(); // Extract id of Oauth2PermissionScope for user impersonation var saApiOauth2PermissionScopeUserImpersonationList = serviceApplication .Api .Oauth2PermissionScopes .Where(scope => "User" == scope.Type && "user_impersonation" == scope.Value && scope.IsEnabled.GetValueOrDefault(false) ) .ToList(); if (saApiOauth2PermissionScopeUserImpersonationList.Count != 1 || !saApiOauth2PermissionScopeUserImpersonationList.First().Id.HasValue) { throw new Exception("Service appplication does not expose Oauth2PermissionScope for user impersonation."); } var saApiOauth2PermissionScopeUserImpersonationId = saApiOauth2PermissionScopeUserImpersonationList.First().Id.Value; var serviceApplicationUserImpersonationRequiredResourceAccess = new RequiredResourceAccess { ResourceAppId = serviceApplication.AppId, // service application ResourceAccess = new List <ResourceAccess> { new ResourceAccess { Id = saApiOauth2PermissionScopeUserImpersonationId, // "user_impersonation" Type = "Scope" } } }; var microsoftGraphUserReadRequiredResourceAccess = new RequiredResourceAccess { ResourceAppId = AzureAppsConstants.MicrosoftGraph.AppId, ResourceAccess = new List <ResourceAccess> { new ResourceAccess { Id = AzureAppsConstants.MicrosoftGraph.ResourceAccess["User.Read"], Type = "Scope" } } }; var clientApplicationRequiredResourceAccess = new List <RequiredResourceAccess>() { serviceApplicationUserImpersonationRequiredResourceAccess, microsoftGraphUserReadRequiredResourceAccess }; var clientApplicationPublicClientApplication = new Microsoft.Graph.PublicClientApplication { RedirectUris = new List <string> { "urn:ietf:wg:oauth:2.0:oob" } }; // Note: Oauth2AllowImplicitFlow will be enabled automatically since both // EnableIdTokenIssuance and EnableAccessTokenIssuance are set to true. // ToDo: RedirectUris should be set after App Service is deployed. var clientApplicationWebApplicatoin = new WebApplication { RedirectUris = new List <string> { $"https://{azureWebsiteName}.azurewebsites.net/", $"https://{azureWebsiteName}.azurewebsites.net/registry/", $"https://{azureWebsiteName}.azurewebsites.net/twin/", $"https://{azureWebsiteName}.azurewebsites.net/history/", $"https://{azureWebsiteName}.azurewebsites.net/ua/", $"https://{azureWebsiteName}.azurewebsites.net/vault/" }, //Oauth2AllowImplicitFlow = true, ImplicitGrantSettings = new ImplicitGrantSettings { EnableIdTokenIssuance = true, EnableAccessTokenIssuance = true } }; var clientApplicationRequest = new Application { DisplayName = clientsApplicationName, IsFallbackPublicClient = true, Tags = tags, SignInAudience = "AzureADMyOrg", RequiredResourceAccess = clientApplicationRequiredResourceAccess, PublicClient = clientApplicationPublicClientApplication, Web = clientApplicationWebApplicatoin, PasswordCredentials = new List <PasswordCredential> { } }; var clientApplication = await _graphServiceClient .Applications .Request() .AddAsync(clientApplicationRequest, cancellationToken); // Add Client Key PasswordCredential var clientKeyName = "Client Key"; var clientApplicationClientKeyPasswordCredentialDefinition = new PasswordCredential { StartDateTime = DateTimeOffset.UtcNow, EndDateTime = DateTimeOffset.UtcNow.AddYears(2), CustomKeyIdentifier = ToBase64Bytes(clientKeyName), DisplayName = clientKeyName }; await _graphServiceClient .Applications[clientApplication.Id] .AddPassword(clientApplicationClientKeyPasswordCredentialDefinition) .Request() .PostAsync(cancellationToken); // We need to create ServicePrincipal for this application. await CreateServicePrincipalAsync( clientApplication, tags, cancellationToken ); return(clientApplication); }