public async Task <JsonResult> CanProvisionPackage(CanProvisionModel model)
        {
            if (String.IsNullOrEmpty(model.PackageId))
            {
                throw new ArgumentNullException("PackageId");
            }

            if (String.IsNullOrEmpty(model.TenantId))
            {
                throw new ArgumentNullException("TenantId");
            }

            if (String.IsNullOrEmpty(model.UserPrincipalName))
            {
                throw new ArgumentNullException("UserPrincipalName");
            }

            CanProvisionResult canProvisionResult = await CanProvisionInternal(model);

            return(Json(canProvisionResult));
        }
示例#2
0
        private async Task <CanProvisionResult> CanProvisionInternal(CanProvisionModel model)
        {
            var canProvisionResult = new CanProvisionResult();

            String provisioningScope       = ConfigurationManager.AppSettings["SPPA:ProvisioningScope"];
            String provisioningEnvironment = ConfigurationManager.AppSettings["SPPA:ProvisioningEnvironment"];

            var tokenId          = $"{model.TenantId}-{model.UserPrincipalName.ToLower().GetHashCode()}-{provisioningScope}-{provisioningEnvironment}";
            var graphAccessToken = await ProvisioningAppManager.AccessTokenProvider.GetAccessTokenAsync(
                tokenId, "https://graph.microsoft.com/");

            // Retrieve the provisioning package from the database and from the Blob Storage
            var context = dbContext;

            DomainModel.Package package = null;

            // Get the package
            if (ProvisioningAppManager.IsTestingEnvironment)
            {
                // Process all packages in the test environment
                package = context.Packages.FirstOrDefault(p => p.Id == new Guid(model.PackageId));
            }
            else
            {
                // Process not-preview packages in the production environment
                package = context.Packages.FirstOrDefault(p => p.Id == new Guid(model.PackageId) && p.Preview == false);
            }

            if (package != null)
            {
                // Retrieve parameters from the package/template definition
                var packageFileUrl     = new Uri(package.PackageUrl);
                var packageLocalFolder = packageFileUrl.AbsolutePath.Substring(1,
                                                                               packageFileUrl.AbsolutePath.LastIndexOf('/') - 1);
                var packageFileName = packageFileUrl.AbsolutePath.Substring(packageLocalFolder.Length + 2);

                ProvisioningHierarchy hierarchy = GetHierarchyFromStorage(packageLocalFolder, packageFileName);

                // If we have the hierarchy
                if (hierarchy != null)
                {
                    var accessTokens = new Dictionary <String, String>();

                    AuthenticationManager authManager = new AuthenticationManager();
                    var ptai = new ProvisioningTemplateApplyingInformation();

                    // Retrieve the SPO URL for the Admin Site
                    var rootSiteUrl = model.SPORootSiteUrl;

                    // Retrieve the SPO Access Token for SPO
                    var spoAccessToken = await ProvisioningAppManager.AccessTokenProvider.GetAccessTokenAsync(
                        tokenId, rootSiteUrl,
                        ConfigurationManager.AppSettings["ida:ClientId"],
                        ConfigurationManager.AppSettings["ida:ClientSecret"],
                        ConfigurationManager.AppSettings["ida:AppUrl"]);

                    // Store the SPO Access Token for any further context cloning
                    accessTokens.Add(new Uri(rootSiteUrl).Authority, spoAccessToken);

                    // Define a PnPProvisioningContext scope to share the security context across calls
                    using (var pnpProvisioningContext = new PnPProvisioningContext(async(r, s) =>
                    {
                        if (accessTokens.ContainsKey(r))
                        {
                            // In this scenario we just use the dictionary of access tokens
                            // in fact the overall operation for sure will take less than 1 hour
                            // (in fact, it's a matter of few seconds)
                            return(await Task.FromResult(accessTokens[r]));
                        }
                        else
                        {
                            // Try to get a fresh new Access Token
                            var token = await ProvisioningAppManager.AccessTokenProvider.GetAccessTokenAsync(
                                tokenId, $"https://{r}",
                                ConfigurationManager.AppSettings["ida:ClientId"],
                                ConfigurationManager.AppSettings["ida:ClientSecret"],
                                ConfigurationManager.AppSettings["ida:AppUrl"]);

                            accessTokens.Add(r, token);

                            return(token);
                        }
                    }))
                    {
                        // If the user is an admin (SPO or Tenant) we run the Tenant level CanProvision rules
                        if (model.UserIsSPOAdmin || model.UserIsTenantAdmin)
                        {
                            // Retrieve the SPO URL for the Admin Site
                            var adminSiteUrl = model.SPORootSiteUrl.Replace(".sharepoint.com", "-admin.sharepoint.com");

                            // Retrieve the SPO Access Token for the Admin Site
                            var spoAdminAccessToken = await ProvisioningAppManager.AccessTokenProvider.GetAccessTokenAsync(
                                tokenId, adminSiteUrl,
                                ConfigurationManager.AppSettings["ida:ClientId"],
                                ConfigurationManager.AppSettings["ida:ClientSecret"],
                                ConfigurationManager.AppSettings["ida:AppUrl"]);

                            // Store the SPO Admin Access Token for any further context cloning
                            accessTokens.Add(new Uri(adminSiteUrl).Authority, spoAdminAccessToken);

                            // Connect to SPO Admin Site and evaluate the CanProvision rules for the hierarchy
                            using (var tenantContext = authManager.GetAzureADAccessTokenAuthenticatedContext(adminSiteUrl, spoAdminAccessToken))
                            {
                                using (var pnpTenantContext = PnPClientContext.ConvertFrom(tenantContext))
                                {
                                    // Creat the Tenant object for the current SPO Admin Site context
                                    TenantAdmin.Tenant tenant = new TenantAdmin.Tenant(pnpTenantContext);

                                    // Run the CanProvision rules against the current tenant
                                    canProvisionResult = CanProvisionRulesManager.CanProvision(tenant, hierarchy, null, ptai);
                                }
                            }
                        }
                        else
                        {
                            // Otherwise we run the Site level CanProvision rules

                            // Connect to SPO Root Site and evaluate the CanProvision rules for the hierarchy
                            using (var clientContext = authManager.GetAzureADAccessTokenAuthenticatedContext(rootSiteUrl, spoAccessToken))
                            {
                                using (var pnpContext = PnPClientContext.ConvertFrom(clientContext))
                                {
                                    // Run the CanProvision rules against the root site
                                    canProvisionResult = CanProvisionRulesManager.CanProvision(pnpContext.Web, hierarchy.Templates[0], ptai);
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                throw new ApplicationException("Invalid request, the requested package/template is not available!");
            }

            return(canProvisionResult);
        }