Пример #1
0
        private async void btnCreateIEFProxyApp_Click(object sender, EventArgs e)
        {
            if (iefApp == null)
            {
                toolStripStatusLabel1.Text = "The IdentityExperienceFramework app must be created first";
                return;
            }
            aniRunning.Visible = true;

            var app = new App
            {
                DisplayName    = "ProxyIdentityExperienceFramework",
                SignInAudience = Audiences.AzureADMyOrg,
            };

            app.PublicClient.RedirectUris.Add("myapp://auth");
            app.IsFallbackPublicClient = true;
            app.Web.ImplicitGrantSettings.EnableIdTokenIssuance     = false;
            app.Web.ImplicitGrantSettings.EnableAccessTokenIssuance = false;

            var acc = new RequiredResourceAccess
            {
                ResourceAppId = "00000003-0000-0000-c000-000000000000",
            };

            acc.ResourceAccess.Add(new ResourceAccess
            {
                Id   = "37f7f235-527c-4136-accd-4a02d197296e",
                Type = "Scope"
            });
            acc.ResourceAccess.Add(new ResourceAccess
            {
                Id   = "7427e0e9-2fba-42fe-b0c0-848c9e6a8182",
                Type = "Scope"
            });
            app.RequiredResourceAccess.Add(acc);

            acc = new RequiredResourceAccess
            {
                ResourceAppId = iefApp.AppId,
            };
            acc.ResourceAccess.Add(new ResourceAccess
            {
                Id   = iefApp.Api.Oauth2PermissionScopes.First().Id,
                Type = "Scope"
            });
            app.RequiredResourceAccess.Add(acc);
            iefProxyApp = await _parent._apps.CreateApp(app);

            if (iefProxyApp == null)
            {
                toolStripStatusLabel1.Text = _parent._policy.LastError;
                return;
            }
            txtIEFProxyApp.Text = GetAppName(iefProxyApp);
            aniRunning.Visible  = false;

            CheckReadiness();
        }
Пример #2
0
        private async Task <RequiredResourceAccess> GetRequiredResourceAccessByDisplayNameAsync(
            string displayName,
            IEnumerable <string> requiredDelegatedPermissions,
            CancellationToken cancellationToken = default
            )
        {
            var displayNameFilterClause = $"DisplayName eq '{displayName}'";

            var servicePrincipals = await _graphServiceClient
                                    .ServicePrincipals
                                    .Request()
                                    .Filter(displayNameFilterClause)
                                    .GetAsync(cancellationToken);

            if (servicePrincipals.Count != 1)
            {
                var msg = $"Could not find ServicePrincipal with '{displayName}' DisplayName";
                throw new SystemException(msg);
            }

            var servicePrincipal = servicePrincipals.First();

            var resourceAccesses = new List <ResourceAccess>();

            foreach (var requiredDelegatedPermission in requiredDelegatedPermissions)
            {
                var oauth2Permissions = servicePrincipal
                                        .Oauth2Permissions
                                        .Where(permission => permission.Value == requiredDelegatedPermission)
                                        .ToList();

                if (oauth2Permissions.Count != 1)
                {
                    var msg = $"Could not  find Oauth2Permission with '{requiredDelegatedPermission}' Value";
                    throw new System.Exception(msg);
                }

                var oauth2Permission = oauth2Permissions.First();

                var resourceAccess = new ResourceAccess {
                    Type = "Scope",
                    Id   = oauth2Permission.Id
                };

                resourceAccesses.Add(resourceAccess);
            }

            var requiredResourceAccess = new RequiredResourceAccess {
                ResourceAppId  = servicePrincipal.AppId,
                ResourceAccess = resourceAccesses
            };

            return(requiredResourceAccess);
        }
Пример #3
0
        private async void btnCreateIEFProxyApp_Click(object sender, EventArgs e)
        {
            aniRunning.Visible = true;

            var app = new App
            {
                DisplayName    = "ProxyIdentityExperienceFramework",
                SignInAudience = Audiences.AzureADMultipleOrgs
            };
            var baseTenant = _parent._settings.B2CTenant.Split('.')[0];

            app.Web.RedirectUris.Add(string.Format("https://{0}.b2clogin.com/{0}.onmicrosoft.com", baseTenant));
            app.Web.ImplicitGrantSettings.EnableIdTokenIssuance     = true;
            app.Web.ImplicitGrantSettings.EnableAccessTokenIssuance = false;
            var acc = new RequiredResourceAccess
            {
                ResourceAppId = "00000002-0000-0000-c000-000000000000",
            };

            acc.ResourceAccess.Add(new ResourceAccess
            {
                Id   = "311a71cc-e848-46a1-bdf8-97ff7156d8e6",
                Type = "Scope"
            });
            app.RequiredResourceAccess.Add(acc);

            acc = new RequiredResourceAccess
            {
                ResourceAppId = "882098ce-cb58-449b-bbb3-e00ddf5f7a3b",
            };
            acc.ResourceAccess.Add(new ResourceAccess
            {
                Id   = iefApp.AppId,
                Type = "Scope"
            });
            app.RequiredResourceAccess.Add(acc);
            iefProxyApp = await _parent._apps.CreateApp(app);

            if (iefProxyApp == null)
            {
                toolStripStatusLabel1.Text = _parent._policy.LastError;
                return;
            }
            txtIEFProxyApp.Text = GetAppName(app);
            aniRunning.Visible  = false;

            CheckReadiness();
        }
Пример #4
0
        public static RequiredResourceAccess GetActiveDirectoryPermissions()
        {
            RequiredResourceAccess permissions = new RequiredResourceAccess()
            {
                // id for Azure Active Directory
                ResourceAppId = "00000002-0000-0000-c000-000000000000"
            };

            ResourceAccess ra2 = new ResourceAccess()
            {
                // id for Permission AAD Sign in and read user profile
                Id   = new Guid("311a71cc-e848-46a1-bdf8-97ff7156d8e6"),
                Type = "Scope"
            };

            permissions.ResourceAccess.Add(ra2);
            return(permissions);
        }
        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;
            }
        }
        protected async Task <Application> RegisterServiceApplicationAsync(
            string serviceApplicationName,
            DirectoryObject owner,
            IEnumerable <string> tags           = null,
            CancellationToken cancellationToken = default
            )
        {
            try {
                tags ??= new List <string>();

                Log.Information("Creating service application registration ...");

                // Setup AppRoles for service application
                var serviceApplicationAppRoles = new List <AppRole>();

                var serviceApplicationApproverRoleId = Guid.NewGuid();
                serviceApplicationAppRoles.Add(new AppRole {
                    DisplayName        = "Approver",
                    Value              = "Sign",
                    Description        = "Approvers have the ability to issue certificates.",
                    AllowedMemberTypes = new List <string> {
                        "User", "Application"
                    },
                    Id = serviceApplicationApproverRoleId
                });

                var serviceApplicationWriterRoleId = Guid.NewGuid();
                serviceApplicationAppRoles.Add(new AppRole {
                    DisplayName        = "Writer",
                    Value              = "Write",
                    Description        = "Writers Have the ability to change entities.",
                    AllowedMemberTypes = new List <string> {
                        "User", "Application"
                    },
                    Id = serviceApplicationWriterRoleId
                });

                var serviceApplicationAdministratorRoleId = Guid.NewGuid();
                serviceApplicationAppRoles.Add(new AppRole {
                    DisplayName        = "Administrator",
                    Value              = "Admin",
                    Description        = "Admins can access advanced features.",
                    AllowedMemberTypes = new List <string> {
                        "User", "Application"
                    },
                    Id = serviceApplicationAdministratorRoleId
                });

                // Setup RequiredResourceAccess for service application

                var keyVaultUserImpersonationRequiredResourceAccess = new RequiredResourceAccess {
                    ResourceAppId  = AzureAppsConstants.AzureKeyVault.AppId,
                    ResourceAccess = new List <ResourceAccess> {
                        new ResourceAccess {
                            Id   = AzureAppsConstants.AzureKeyVault.ResourceAccess["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 serviceApplicationRequiredResourceAccess = new List <RequiredResourceAccess>()
                {
                    keyVaultUserImpersonationRequiredResourceAccess,
                    microsoftGraphUserReadRequiredResourceAccess
                };

                // Add OAuth2Permissions
                var oauth2Permissions = new List <PermissionScope> {
                    new PermissionScope {
                        AdminConsentDescription = $"Allow the app to access {serviceApplicationName} on behalf of the signed-in user.",
                        AdminConsentDisplayName = $"Access {serviceApplicationName}",
                        Id        = Guid.NewGuid(),
                        IsEnabled = true,
                        Type      = "User",
                        UserConsentDescription = $"Allow the application to access {serviceApplicationName} on your behalf.",
                        UserConsentDisplayName = $"Access {serviceApplicationName}",
                        Value = "user_impersonation"
                    }
                };

                var serviceApplicationApiApplication = new ApiApplication {
                    Oauth2PermissionScopes = oauth2Permissions
                };

                // ODataType = null is a workaround for a bug:
                // https://github.com/microsoftgraph/msgraph-beta-sdk-dotnet/issues/87
                var serviceApplicationWebApplication = new WebApplication {
                    ImplicitGrantSettings = new ImplicitGrantSettings {
                        ODataType             = null,
                        EnableIdTokenIssuance = true
                    }
                };

                var serviceApplicationDefinition = new Application {
                    DisplayName            = serviceApplicationName,
                    IsFallbackPublicClient = false,
                    IdentifierUris         = new List <string> {
                        $"https://{_tenantId.ToString()}/{serviceApplicationName}"
                    },
                    Tags                   = tags,
                    SignInAudience         = "AzureADMyOrg",
                    AppRoles               = serviceApplicationAppRoles,
                    RequiredResourceAccess = serviceApplicationRequiredResourceAccess,
                    Api = serviceApplicationApiApplication,
                    Web = serviceApplicationWebApplication,
                    PasswordCredentials = new List <PasswordCredential> {
                    }
                };

                var serviceApplication = await _msGraphServiceClient
                                         .CreateApplicationAsync(
                    serviceApplicationDefinition,
                    cancellationToken
                    );

                // Add Service Key PasswordCredential
                var serviceKeyName = "Service Key";
                await _msGraphServiceClient
                .AddApplication2YPasswordCredentialAsync(
                    serviceApplication,
                    serviceKeyName,
                    cancellationToken
                    );

                // We need to create ServicePrincipal for this application.
                var serviceApplicationSP = await _msGraphServiceClient
                                           .CreateApplicationServicePrincipalAsync(
                    serviceApplication,
                    tags,
                    cancellationToken
                    );

                // Add app role assignment to owner as Approver, Writer and Administrator.
                string PrincipalType;

                if (owner is User)
                {
                    PrincipalType = "User";
                }
                else if (owner is ServicePrincipal)
                {
                    PrincipalType = "ServicePrincipal";
                }
                else if (owner is Group)
                {
                    PrincipalType = "Group";
                }
                else
                {
                    throw new ArgumentException($"Owner is of unknown type: {owner.GetType()}", "owner");
                }

                var approverAppRoleAssignmentDefinition = new AppRoleAssignment {
                    PrincipalType       = PrincipalType,
                    PrincipalId         = new Guid(owner.Id),
                    ResourceId          = new Guid(serviceApplicationSP.Id),
                    ResourceDisplayName = "Approver",
                    Id        = serviceApplicationApproverRoleId.ToString(),
                    AppRoleId = serviceApplicationApproverRoleId
                };

                var writerAppRoleAssignmentDefinition = new AppRoleAssignment {
                    PrincipalType       = PrincipalType,
                    PrincipalId         = new Guid(owner.Id),
                    ResourceId          = new Guid(serviceApplicationSP.Id),
                    ResourceDisplayName = "Writer",
                    Id        = serviceApplicationWriterRoleId.ToString(),
                    AppRoleId = serviceApplicationWriterRoleId
                };

                var administratorAppRoleAssignmentDefinition = new AppRoleAssignment {
                    PrincipalType       = PrincipalType,
                    PrincipalId         = new Guid(owner.Id),
                    ResourceId          = new Guid(serviceApplicationSP.Id),
                    ResourceDisplayName = "Administrator",
                    Id        = serviceApplicationAdministratorRoleId.ToString(),
                    AppRoleId = serviceApplicationAdministratorRoleId
                };

                await _msGraphServiceClient
                .AddServicePrincipalAppRoleAssignmentAsync(
                    serviceApplicationSP,
                    approverAppRoleAssignmentDefinition,
                    cancellationToken
                    );

                await _msGraphServiceClient
                .AddServicePrincipalAppRoleAssignmentAsync(
                    serviceApplicationSP,
                    writerAppRoleAssignmentDefinition,
                    cancellationToken
                    );

                await _msGraphServiceClient
                .AddServicePrincipalAppRoleAssignmentAsync(
                    serviceApplicationSP,
                    administratorAppRoleAssignmentDefinition,
                    cancellationToken
                    );

                // Get updated definition
                serviceApplication = await _msGraphServiceClient
                                     .GetApplicationAsync(
                    new Guid(serviceApplication.Id),
                    cancellationToken
                    );

                Log.Information("Created service application registration.");

                return(serviceApplication);
            }
            catch (Exception) {
                Log.Error("Failed to create service application registration.");
                throw;
            }
        }
Пример #7
0
        public async Task <Application> RegisterServiceApplicationAsync(
            string servicesApplicationName,
            IEnumerable <string> tags           = null,
            CancellationToken cancellationToken = default
            )
        {
            tags = tags ?? new List <string>();

            // Setup AppRoles for service application
            var serviceApplicationAppRoles = new List <AppRole>();

            var serviceApplicationApproverRoleIdGuid = Guid.NewGuid();

            serviceApplicationAppRoles.Add(new AppRole {
                DisplayName        = "Approver",
                Value              = "Sign",
                Description        = "Approvers have the ability to issue certificates.",
                AllowedMemberTypes = new List <string> {
                    "User"
                },
                Id = serviceApplicationApproverRoleIdGuid
            });

            var serviceApplicationWriterRoleIdGuid = Guid.NewGuid();

            serviceApplicationAppRoles.Add(new AppRole {
                DisplayName        = "Writer",
                Value              = "Write",
                Description        = "Writers Have the ability to change entities.",
                AllowedMemberTypes = new List <string> {
                    "User"
                },
                Id = serviceApplicationWriterRoleIdGuid
            });

            var serviceApplicationAdministratorRoleIdGuid = Guid.NewGuid();

            serviceApplicationAppRoles.Add(new AppRole {
                DisplayName        = "Administrator",
                Value              = "Admin",
                Description        = "Admins can access advanced features.",
                AllowedMemberTypes = new List <string> {
                    "User"
                },
                Id = serviceApplicationAdministratorRoleIdGuid
            });

            // Setup RequiredResourceAccess for service application

            //// This flow is not supported yet.
            //var keyVaultUserImpersonationRequiredResourceAccess =
            //    await GetRequiredResourceAccessByDisplayNameAsync(
            //        "Azure Key Vault",
            //        new List<string> { "user_impersonation" },
            //        cancellationToken
            //    );

            var keyVaultUserImpersonationRequiredResourceAccess = new RequiredResourceAccess {
                ResourceAppId  = AzureAppsConstants.AzureKeyVault.AppId,
                ResourceAccess = new List <ResourceAccess> {
                    new ResourceAccess {
                        Id   = AzureAppsConstants.AzureKeyVault.ResourceAccess["user_impersonation"],
                        Type = "Scope"
                    }
                }
            };

            //// This flow is not supported yet.
            //var microsoftGraphUserReadRequiredResourceAccess =
            //    await GetRequiredResourceAccessByDisplayNameAsync(
            //        "Microsoft Graph",
            //        new List<string> { "User.Read" },
            //        cancellationToken
            //    );

            var microsoftGraphUserReadRequiredResourceAccess = new RequiredResourceAccess {
                ResourceAppId  = AzureAppsConstants.MicrosoftGraph.AppId,
                ResourceAccess = new List <ResourceAccess> {
                    new ResourceAccess {
                        Id   = AzureAppsConstants.MicrosoftGraph.ResourceAccess["User.Read"],
                        Type = "Scope"
                    }
                }
            };

            var serviceApplicationRequiredResourceAccess = new List <RequiredResourceAccess>()
            {
                keyVaultUserImpersonationRequiredResourceAccess,
                microsoftGraphUserReadRequiredResourceAccess
            };

            // Add OAuth2Permissions
            var oauth2Permissions = new List <PermissionScope> {
                new PermissionScope {
                    AdminConsentDescription = $"Allow the app to access {servicesApplicationName} on behalf of the signed-in user.",
                    AdminConsentDisplayName = $"Access {servicesApplicationName}",
                    Id        = Guid.NewGuid(),
                    IsEnabled = true,
                    Type      = "User",
                    UserConsentDescription = $"Allow the application to access {servicesApplicationName} on your behalf.",
                    UserConsentDisplayName = $"Access {servicesApplicationName}",
                    Value = "user_impersonation"
                }
            };

            var serviceApplicationApiApplication = new ApiApplication {
                Oauth2PermissionScopes = oauth2Permissions
            };

            var serviceApplicationWebApplication = new WebApplication {
                ImplicitGrantSettings = new ImplicitGrantSettings {
                    EnableIdTokenIssuance = true
                }
            };

            var serviceApplicationIdentifierUri = $"https://{_tenantGuid.ToString()}/{servicesApplicationName}";

            var serviceApplicationRequest = new Application {
                DisplayName            = servicesApplicationName,
                IsFallbackPublicClient = false,
                IdentifierUris         = new List <string> {
                    serviceApplicationIdentifierUri
                },
                Tags                   = tags,
                SignInAudience         = "AzureADMyOrg",
                AppRoles               = serviceApplicationAppRoles,
                RequiredResourceAccess = serviceApplicationRequiredResourceAccess,
                Api = serviceApplicationApiApplication,
                Web = serviceApplicationWebApplication,
                PasswordCredentials = new List <PasswordCredential> {
                }
            };

            var serviceApplication = await _graphServiceClient
                                     .Applications
                                     .Request()
                                     .AddAsync(serviceApplicationRequest, cancellationToken);

            // Add Service Key PasswordCredential
            var serviceKeyName = "Service Key";

            var serviceApplicationServiceKeyPasswordCredentialDefinition = new PasswordCredential {
                StartDateTime       = DateTimeOffset.UtcNow,
                EndDateTime         = DateTimeOffset.UtcNow.AddYears(2),
                CustomKeyIdentifier = ToBase64Bytes(serviceKeyName),
                DisplayName         = serviceKeyName
            };

            await _graphServiceClient
            .Applications[serviceApplication.Id]
            .AddPassword(serviceApplicationServiceKeyPasswordCredentialDefinition)
            .Request()
            .PostAsync(cancellationToken);

            // We need to create ServicePrincipal for this application.
            var serviceApplicationSP = await CreateServicePrincipalAsync(
                serviceApplication,
                tags,
                cancellationToken
                );

            var me = Me(cancellationToken);

            var approverAppRoleAssignmentRequest = new AppRoleAssignment {
                //PrincipalDisplayName = "",
                PrincipalType       = "User",
                PrincipalId         = new Guid(me.Id),
                ResourceId          = new Guid(serviceApplicationSP.Id),
                ResourceDisplayName = "Approver",
                Id        = serviceApplicationApproverRoleIdGuid.ToString(),
                AppRoleId = serviceApplicationApproverRoleIdGuid
            };

            var writerAppRoleAssignmentRequest = new AppRoleAssignment {
                //PrincipalDisplayName = "",
                PrincipalType       = "User",
                PrincipalId         = new Guid(me.Id),
                ResourceId          = new Guid(serviceApplicationSP.Id),
                ResourceDisplayName = "Writer",
                Id        = serviceApplicationWriterRoleIdGuid.ToString(),
                AppRoleId = serviceApplicationWriterRoleIdGuid
            };

            var adminAppRoleAssignmentRequest = new AppRoleAssignment {
                //PrincipalDisplayName = "",
                PrincipalType       = "User",
                PrincipalId         = new Guid(me.Id),
                ResourceId          = new Guid(serviceApplicationSP.Id),
                ResourceDisplayName = "Admin",
                Id        = serviceApplicationAdministratorRoleIdGuid.ToString(),
                AppRoleId = serviceApplicationAdministratorRoleIdGuid
            };

            //// ToDo: Use AddAsync() instead of the workaround bellow
            //// when AddAsync() is added.
            //var appRoleAssignment = _graphServiceClient
            //    .ServicePrincipals[serviceApplicationSP.Id]
            //    .AppRoleAssignments
            //    .Request()
            //    .AddAsync(appRoleAssignmentRequest);

            // Workaround using HttpClient
            await AddAppRoleAssignmentAsync(serviceApplicationSP, approverAppRoleAssignmentRequest);
            await AddAppRoleAssignmentAsync(serviceApplicationSP, writerAppRoleAssignmentRequest);
            await AddAppRoleAssignmentAsync(serviceApplicationSP, adminAppRoleAssignmentRequest);

            return(serviceApplication);
        }
Пример #8
0
        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);
        }
        /// <summary>
        /// Register Application to Azure AD
        /// </summary>
        /// <returns>registered application's clientid</returns>
        public string RegisterApp()
        {
            authContext = new AuthenticationContext(props.Authority);

            // Application Name
            string appName = "CRM for LINQPad";

            ActiveDirectoryClient activeDirectoryClient;

            int i = 0;

            while (true)
            {
                // Instantiate ActiveDirectoryClient
                activeDirectoryClient = GetActiveDirectoryClientAsApplication(useCurrentUser);

                if (CheckAzureAdPrivilege(activeDirectoryClient))
                {
                    break;
                }
                else
                {
                    MessageBox.Show("Current login user does not have privilege to register an applicaiton to the Azure AD. You need to login as Company Admin so that it can reigster an applicaiton, or cancel the wizard, then enter ClientId/RedirectUri manually.");
                    // Clear the ADAL cache.
                    authContext.TokenCache.Clear();
                    useCurrentUser = false;
                    if (i == 1)
                    {
                        return(null);
                    }
                    else
                    {
                        i++;
                    }
                }
            }

            // Check if same name application already exists.
            var existingApp = activeDirectoryClient.Applications
                              .Where(x => x.DisplayName == appName)
                              .ExecuteAsync().Result.CurrentPage.FirstOrDefault();

            // If it is already registered, then return existing clientid.
            if (existingApp != null && existingApp.RequiredResourceAccess.Count() == 2)
            {
                return(existingApp.AppId);
            }
            else
            {
                existingApp.DeleteAsync().Wait();
            }

            // Instantiate Application to Azure AD.
            IApplication myapp = new Microsoft.Azure.ActiveDirectory.GraphClient.Application();

            myapp.DisplayName = appName;
            var redirectUri = "http://localhost/linqpad";

            myapp.ReplyUrls.Add(redirectUri);
            props.RedirectUri  = redirectUri;
            myapp.PublicClient = true;
            // Mark this only to this tenant
            myapp.AvailableToOtherTenants = false;

            // Create the Application to Azure AD.
            activeDirectoryClient.Applications.AddApplicationAsync(myapp).Wait();

            // Obtain the created Application.
            var createdApp = activeDirectoryClient.Applications
                             .Where(x => x.DisplayName == appName)
                             .ExecuteAsync().Result.CurrentPage.FirstOrDefault();

            // Instantiate Service regarding to the application.
            IServicePrincipal myservice = new ServicePrincipal();

            myservice.AppId = createdApp.AppId;
            myservice.Tags.Add("WindowsAzureActiveDirectoryIntegratedApp");

            // Create the Service.
            activeDirectoryClient.ServicePrincipals.AddServicePrincipalAsync(myservice).Wait();

            // Obtain the created Service.
            var createdService = activeDirectoryClient.ServicePrincipals
                                 .Where(x => x.DisplayName == appName)
                                 .ExecuteAsync().Result.CurrentPage.FirstOrDefault();

            // Set permissions.
            // Get Microsoft.Azure.ActiveDirectory Service.
            var service1 = activeDirectoryClient.ServicePrincipals
                           .Where(x => x.AppId == "00000002-0000-0000-c000-000000000000")
                           .ExecuteAsync().Result.CurrentPage.FirstOrDefault();

            // Instantiate UserProfile.Read OAuth2PermissionGrant for the Service
            OAuth2PermissionGrant grant0 = new OAuth2PermissionGrant();

            grant0.ClientId    = createdService.ObjectId;
            grant0.ResourceId  = service1.ObjectId;
            grant0.ConsentType = "AllPrincipals";
            grant0.Scope       = "User.Read";
            grant0.ExpiryTime  = DateTime.Now.AddYears(1);

            // Create the OAuth2PermissionGrant
            activeDirectoryClient.Oauth2PermissionGrants.AddOAuth2PermissionGrantAsync(grant0).Wait();

            // Get Microsoft.CRM Service.
            var service2 = activeDirectoryClient.ServicePrincipals
                           .Where(x => x.AppId == "00000007-0000-0000-c000-000000000000")
                           .ExecuteAsync().Result.CurrentPage.FirstOrDefault();

            // Instantiate user_impersonation OAuth2PermissionGrant for the Service
            OAuth2PermissionGrant grant = new OAuth2PermissionGrant();

            grant.ClientId    = createdService.ObjectId;
            grant.ResourceId  = service2.ObjectId;
            grant.ConsentType = "AllPrincipals";
            grant.Scope       = "user_impersonation";
            grant.ExpiryTime  = DateTime.Now.AddYears(1);

            // Create the OAuth2PermissionGrant
            activeDirectoryClient.Oauth2PermissionGrants.AddOAuth2PermissionGrantAsync(grant).Wait();

            // Create RequiredResourceAccess
            // Instantiate ResourceAccess for Microsoft.Azure.ActiveDirectory/UserProfile.Read permission.
            ResourceAccess resourceAccess1 = new ResourceAccess();

            resourceAccess1.Id   = service1.Oauth2Permissions.Where(x => x.Value == "User.Read").First().Id;
            resourceAccess1.Type = "Scope";
            // Instantiate RequiredResourceAccess and assign the ResourceAccess
            RequiredResourceAccess requiredresourceAccess1 = new RequiredResourceAccess();

            requiredresourceAccess1.ResourceAppId = service1.AppId;
            requiredresourceAccess1.ResourceAccess.Add(resourceAccess1);

            // Instantiate ResourceAccess for Microsoft.CRM/user_impersonation.Read permission.
            ResourceAccess resourceAccess2 = new ResourceAccess();

            resourceAccess2.Id   = service2.Oauth2Permissions.Where(x => x.Value == "user_impersonation").First().Id;
            resourceAccess2.Type = "Scope";
            // Instantiate RequiredResourceAccess and assign the ResourceAccess
            RequiredResourceAccess requiredResourceAccess2 = new RequiredResourceAccess();

            requiredResourceAccess2.ResourceAppId = service2.AppId;
            requiredResourceAccess2.ResourceAccess.Add(resourceAccess2);

            // Add RequiredResourceAccess information to the Application
            createdApp.RequiredResourceAccess.Add(requiredresourceAccess1);
            createdApp.RequiredResourceAccess.Add(requiredResourceAccess2);

            // Update the Application
            createdApp.UpdateAsync().Wait();

            // Once all Azure AD work done, clear ADAL cache again in case user logged in as different user.
            authContext.TokenCache.Clear();

            // Return AppId (ClientId)
            return(createdApp.AppId);
        }
        // GET api/<controller>/5
        public async Task <HttpResponseMessage> Get(string id)
        {
            HttpResponseMessage result = new HttpResponseMessage();

            List <KeyValuePair <string, string> > queryString = Request.GetQueryNameValuePairs().ToList();
            string objectId  = queryString.FirstOrDefault(q => q.Key == "objectId").Value;
            string email     = queryString.FirstOrDefault(q => q.Key == "email").Value;
            string firstName = queryString.FirstOrDefault(q => q.Key == "firstName").Value;
            string lastName  = queryString.FirstOrDefault(q => q.Key == "lastName").Value;

            if (string.IsNullOrEmpty(id) ||
                string.IsNullOrEmpty(objectId) ||
                string.IsNullOrEmpty(email) ||
                string.IsNullOrEmpty(firstName) ||
                string.IsNullOrEmpty(lastName))
            {
                result.StatusCode = HttpStatusCode.BadRequest;
                result.Content    = new StringContent("Please pass an id, objectId, email, firstName, and lastName on the querystring");
            }
            else
            {
                string partitionKey = id.Substring(0, 1).ToLower();
                OrganizationSubscription subscription = await _registrationService.GetOrganizationSubscription(partitionKey, id);

                if (subscription == null)
                {
                    // Create Azure AD Application Registration for the Organization
                    Guid        uniqueId    = Guid.NewGuid();
                    Application application = new Application();
                    application.DisplayName    = $"AAD - {id} Client Application";
                    application.IdentifierUris = new List <string>();
                    application.IdentifierUris.Add($"https://{ConfigurationManager.AppSettings["TENANT"]}/{uniqueId}");
                    application.PasswordCredentials = new List <PasswordCredential>();
                    var    startDate = DateTime.Now;
                    Byte[] bytes     = new Byte[32];
                    using (var rand = System.Security.Cryptography.RandomNumberGenerator.Create())
                    {
                        rand.GetBytes(bytes);
                    }
                    string clientSecret = Convert.ToBase64String(bytes);
                    application.PasswordCredentials.Add(new PasswordCredential()
                    {
                        CustomKeyIdentifier = null,
                        StartDate           = startDate,
                        EndDate             = new DateTime(2299, 12, 31, 5, 0, 0, 0),
                        KeyId = Guid.NewGuid(),
                        Value = clientSecret
                    });
                    application.RequiredResourceAccess = new List <RequiredResourceAccess>();
                    RequiredResourceAccess graphResourceAccess = new RequiredResourceAccess()
                    {
                        ResourceAccess = new List <ResourceAccess>(),
                        ResourceAppId  = "00000003-0000-0000-c000-000000000000"
                    };
                    graphResourceAccess.ResourceAccess.Add(new ResourceAccess()
                    {
                        Id   = new Guid("37f7f235-527c-4136-accd-4a02d197296e"),
                        Type = "Scope"
                    });
                    graphResourceAccess.ResourceAccess.Add(new ResourceAccess()
                    {
                        Id   = new Guid("7427e0e9-2fba-42fe-b0c0-848c9e6a8182"),
                        Type = "Scope"
                    });
                    RequiredResourceAccess apimResourceAccess = new RequiredResourceAccess()
                    {
                        ResourceAccess = new List <ResourceAccess>(),
                        ResourceAppId  = "30fe3279-fbb4-4a13-b1f8-7c5f2ea9e6df"
                    };
                    apimResourceAccess.ResourceAccess.Add(new ResourceAccess()
                    {
                        Id   = new Guid("f9bcce35-145a-4199-bf1b-948467774061"),
                        Type = "Role"
                    });
                    application.RequiredResourceAccess.Add(graphResourceAccess);
                    application.RequiredResourceAccess.Add(apimResourceAccess);
                    application.ReplyUrls = new List <string>();
                    application.ReplyUrls.Add($"msapp://{uniqueId}");
                    string clientId = await _appService.Create(application);

                    // Create APIM subscription key for the organization
                    Guid             primaryKey       = Guid.NewGuid();
                    Guid             secondaryKey     = Guid.NewGuid();
                    APIMSubscription apimSubscription = await _subscriptionService.CreateOrgSubscription($"APIM {id} Subscription", "/products/starter", primaryKey, secondaryKey, $"{id}@{_orgEmailDomain}", id, id);

                    // Store subscription information in Table Storage
                    OrganizationSubscription organizationSubscription = new OrganizationSubscription()
                    {
                        Organization             = id,
                        PrimarySubscriptionKey   = apimSubscription.properties.primaryKey,
                        SecondarySubscriptionKey = apimSubscription.properties.secondaryKey,
                        Scope        = apimSubscription.properties.scope,
                        ClientId     = clientId,
                        ClientSecret = clientSecret
                    };
                    OrganizationEntity organizationEntity = new OrganizationEntity(organizationSubscription);
                    await _registrationService.CreateOrganizationSubscription(organizationEntity);

                    // Create pending APIM subscription for the user
                    APIMSubscription apimUserSubscription = await _subscriptionService.CreateSubscription($"APIM {id} Subscription", "/products/starter", Guid.NewGuid(), Guid.NewGuid(), objectId, email, firstName, lastName);

                    // No user subscriptions have been approved yet so return masked values
                    ResponseContent responseContent = new ResponseContent
                    {
                        version                  = "1.0.0",
                        status                   = (int)HttpStatusCode.OK,
                        organization             = id,
                        primarySubscriptionKey   = MASKED_VALUE,
                        secondarySubscriptionKey = MASKED_VALUE,
                        clientId                 = MASKED_VALUE,
                        clientSecret             = MASKED_VALUE
                    };
                    result.StatusCode = HttpStatusCode.OK;
                    result.Content    = new StringContent(JsonConvert.SerializeObject(responseContent), Encoding.UTF8, "application/json");
                }
                else
                {
                    string            state = string.Empty;
                    bool              userHasSubscription = false;
                    UserSubscriptions userSubscriptions   = await _subscriptionService.GetUserSubscriptions(email);

                    if (userSubscriptions != null && userSubscriptions.count > 0)
                    {
                        foreach (UserSubscription userSubscription in userSubscriptions.value)
                        {
                            if (userSubscription.properties.scope.EndsWith(subscription.Scope, StringComparison.InvariantCultureIgnoreCase))
                            {
                                state = userSubscription.properties.state;
                                userHasSubscription = true;
                                break;
                            }
                        }
                    }

                    if (!userHasSubscription)
                    {
                        APIMSubscription apimSubscription = await _subscriptionService.CreateSubscription($"APIM {id} Subscription", "/products/starter", Guid.NewGuid(), Guid.NewGuid(), objectId, email, firstName, lastName);

                        state = apimSubscription.properties.state;
                    }

                    ResponseContent responseContent = null;
                    if (state == "active") // User has an approved subscription - share the organization values
                    {
                        responseContent = new ResponseContent
                        {
                            version                  = "1.0.0",
                            status                   = (int)HttpStatusCode.OK,
                            organization             = id,
                            primarySubscriptionKey   = subscription.PrimarySubscriptionKey,
                            secondarySubscriptionKey = subscription.SecondarySubscriptionKey,
                            clientId                 = subscription.ClientId,
                            clientSecret             = subscription.ClientSecret
                        };
                    }
                    else // User has a pending subscription - return masked values
                    {
                        responseContent = new ResponseContent
                        {
                            version                  = "1.0.0",
                            status                   = (int)HttpStatusCode.OK,
                            organization             = id,
                            primarySubscriptionKey   = MASKED_VALUE,
                            secondarySubscriptionKey = MASKED_VALUE,
                            clientId                 = MASKED_VALUE,
                            clientSecret             = MASKED_VALUE
                        };
                    }

                    result.StatusCode = HttpStatusCode.OK;
                    result.Content    = new StringContent(JsonConvert.SerializeObject(responseContent), Encoding.UTF8, "application/json");
                }
            }

            return(result);
        }