private async static Task RegisterAzureADApplication(SetupInformation info) { // Fix the App URL if (!info.AzureWebAppUrl.EndsWith("/")) { info.AzureWebAppUrl = info.AzureWebAppUrl + "/"; } // Load the App Manifest template Stream stream = typeof(SetupManager) .Assembly .GetManifestResourceStream("OfficeDevPnP.PartnerPack.Setup.Resources.azure-ad-app-manifest.json"); using (StreamReader sr = new StreamReader(stream)) { // Get the JSON manifest var jsonApplication = sr.ReadToEnd(); var application = JsonConvert.DeserializeObject <AzureAdApplication>(jsonApplication); var keyCredential = JsonConvert.DeserializeObject <KeyCredential>(info.AzureAppKeyCredential); application.displayName = info.ApplicationName; application.homepage = info.AzureWebAppUrl; application.identifierUris = new List <String>(); application.identifierUris.Add(info.ApplicationUniqueUri); application.keyCredentials = new List <KeyCredential>(); application.keyCredentials.Add(keyCredential); application.replyUrls = new List <String>(); application.replyUrls.Add(info.AzureWebAppUrl); // Generate the Application Shared Secret var startDate = DateTime.Now; Byte[] bytes = new Byte[32]; using (var rand = System.Security.Cryptography.RandomNumberGenerator.Create()) { rand.GetBytes(bytes); } info.AzureAppSharedSecret = System.Convert.ToBase64String(bytes); application.passwordCredentials = new List <object>(); application.passwordCredentials.Add(new AzureAdApplicationPasswordCredential { CustomKeyIdentifier = null, StartDate = startDate.ToString("o"), EndDate = startDate.AddYears(2).ToString("o"), KeyId = Guid.NewGuid().ToString(), Value = info.AzureAppSharedSecret, }); // Get an Access Token to create the application via Microsoft Graph var office365AzureADAccessToken = await AzureManagementUtility.GetAccessTokenSilentAsync( AzureManagementUtility.MicrosoftGraphResourceId, ConfigurationManager.AppSettings["O365:ClientId"]); var azureAdApplicationCreated = false; // Create the Azure AD Application try { await CreateAzureADApplication(info, application, office365AzureADAccessToken); azureAdApplicationCreated = true; } catch (ApplicationException ex) { var graphError = JsonConvert.DeserializeObject <GraphError>(((HttpException)ex.InnerException).Message); if (graphError != null && graphError.error.code == "Request_BadRequest" && graphError.error.message.Contains("identifierUris already exists")) { // We need to remove the existing application // Thus, retrieve it String jsonApplications = await HttpHelper.MakeGetRequestForStringAsync( String.Format("{0}applications?$filter=identifierUris/any(c:c+eq+'{1}')", AzureManagementUtility.MicrosoftGraphBetaBaseUri, HttpUtility.UrlEncode(info.ApplicationUniqueUri)), office365AzureADAccessToken); var applications = JsonConvert.DeserializeObject <AzureAdApplications>(jsonApplications); var applicationToUpdate = applications.Applications.FirstOrDefault(); if (applicationToUpdate != null) { // Remove it await HttpHelper.MakeDeleteRequestAsync( String.Format("{0}applications/{1}", AzureManagementUtility.MicrosoftGraphBetaBaseUri, applicationToUpdate.Id), office365AzureADAccessToken); // And add it again await CreateAzureADApplication(info, application, office365AzureADAccessToken); azureAdApplicationCreated = true; } } } if (azureAdApplicationCreated) { // TODO: We should upload the logo // property mainLogo: stream of the application via PATCH } } }
private async static Task CreateInfrastructuralSiteCollectionAsync(SetupInformation info) { Uri infrastructureSiteUri = new Uri(info.InfrastructuralSiteUrl); Uri tenantAdminUri = new Uri(infrastructureSiteUri.Scheme + "://" + infrastructureSiteUri.Host.Replace(".sharepoint.com", "-admin.sharepoint.com")); Uri sharepointUri = new Uri(infrastructureSiteUri.Scheme + "://" + infrastructureSiteUri.Host + "/"); var siteUrl = info.InfrastructuralSiteUrl.Substring(info.InfrastructuralSiteUrl.IndexOf("sharepoint.com/") + 14); var siteCreated = false; var siteAlreadyExists = false; var accessToken = await AzureManagementUtility.GetAccessTokenSilentAsync( tenantAdminUri.ToString(), ConfigurationManager.AppSettings["O365:ClientId"]); AuthenticationManager am = new AuthenticationManager(); using (var adminContext = am.GetAzureADAccessTokenAuthenticatedContext( tenantAdminUri.ToString(), accessToken)) { adminContext.RequestTimeout = Timeout.Infinite; var tenant = new Tenant(adminContext); // Check if the site already exists, and eventually removes it from the Recycle Bin if (tenant.CheckIfSiteExists(info.InfrastructuralSiteUrl, "Recycled")) { tenant.DeleteSiteCollectionFromRecycleBin(info.InfrastructuralSiteUrl); } siteAlreadyExists = tenant.SiteExists(info.InfrastructuralSiteUrl); if (!siteAlreadyExists) { // Configure the Site Collection properties SiteEntity newSite = new SiteEntity(); newSite.Description = "PnP Partner Pack - Infrastructural Site Collection"; newSite.Lcid = (uint)info.InfrastructuralSiteLCID; newSite.Title = newSite.Description; newSite.Url = info.InfrastructuralSiteUrl; newSite.SiteOwnerLogin = info.InfrastructuralSitePrimaryAdmin; newSite.StorageMaximumLevel = 1000; newSite.StorageWarningLevel = 900; newSite.Template = "STS#0"; newSite.TimeZoneId = info.InfrastructuralSiteTimeZone; newSite.UserCodeMaximumLevel = 0; newSite.UserCodeWarningLevel = 0; // Create the Site Collection and wait for its creation (we're asynchronous) tenant.CreateSiteCollection(newSite, true, true, (top) => { if (top == TenantOperationMessage.CreatingSiteCollection) { var maxProgress = (100 / (Int32)SetupStep.Completed); info.ViewModel.SetupProgress += 1; if (info.ViewModel.SetupProgress >= maxProgress) { info.ViewModel.SetupProgress = maxProgress; } } return(false); }); } } await Task.Delay(5000); using (var adminContext = am.GetAzureADAccessTokenAuthenticatedContext( tenantAdminUri.ToString(), accessToken)) { adminContext.RequestTimeout = Timeout.Infinite; var tenant = new Tenant(adminContext); Site site = tenant.GetSiteByUrl(info.InfrastructuralSiteUrl); Web web = site.RootWeb; adminContext.Load(site, s => s.Url); adminContext.Load(web, w => w.Url); adminContext.ExecuteQueryRetry(); // Enable Secondary Site Collection Administrator if (!String.IsNullOrEmpty(info.InfrastructuralSiteSecondaryAdmin)) { Microsoft.SharePoint.Client.User secondaryOwner = web.EnsureUser(info.InfrastructuralSiteSecondaryAdmin); secondaryOwner.IsSiteAdmin = true; secondaryOwner.Update(); web.SiteUsers.AddUser(secondaryOwner); adminContext.ExecuteQueryRetry(); } siteCreated = true; } if (siteAlreadyExists || siteCreated) { accessToken = await AzureManagementUtility.GetAccessTokenSilentAsync( sharepointUri.ToString(), ConfigurationManager.AppSettings["O365:ClientId"]); using (ClientContext clientContext = am.GetAzureADAccessTokenAuthenticatedContext( info.InfrastructuralSiteUrl, accessToken)) { clientContext.RequestTimeout = Timeout.Infinite; Site site = clientContext.Site; Web web = site.RootWeb; clientContext.Load(site, s => s.Url); clientContext.Load(web, w => w.Url); clientContext.ExecuteQueryRetry(); // Override settings within templates, before uploading them UpdateProvisioningTemplateParameter("Responsive", "SPO-Responsive.xml", "AzureWebSiteUrl", info.AzureWebAppUrl); UpdateProvisioningTemplateParameter("Overrides", "PnP-Partner-Pack-Overrides.xml", "AzureWebSiteUrl", info.AzureWebAppUrl); // Apply the templates to the target site ApplyProvisioningTemplate(web, "Infrastructure", "PnP-Partner-Pack-Infrastructure-Jobs.xml"); ApplyProvisioningTemplate(web, "Infrastructure", "PnP-Partner-Pack-Infrastructure-Templates.xml"); ApplyProvisioningTemplate(web, "", "PnP-Partner-Pack-Infrastructure-Contents.xml"); // We to it twice to force the content types, due to a small bug in the provisioning engine ApplyProvisioningTemplate(web, "", "PnP-Partner-Pack-Infrastructure-Contents.xml"); } } else { // TODO: Handle some kind of exception ... } }