private static async Task <Dictionary <string, string> > PrepareAccessTokensAsync(ProvisioningActionModel model) { // Prepare the variable to hold the result var accessTokens = new Dictionary <string, string>(); // Retrieve the Microsoft Graph Access Token var graphAccessToken = await ProvisioningAppManager.AccessTokenProvider.GetAccessTokenAsync( AuthenticationConfig.GetGraphScopes()); // Retrieve the SPO Access Token var spoAccessToken = await ProvisioningAppManager.AccessTokenProvider.GetAccessTokenAsync( AuthenticationConfig.ClientId, AuthenticationConfig.ClientSecret, AuthenticationConfig.RedirectUri, AuthenticationConfig.GetSpoScopes(model.SPORootSiteUrl)); // Retrieve the SPO URL for the Admin Site var adminSiteUrl = model.SPORootSiteUrl.Replace(".sharepoint.com", "-admin.sharepoint.com"); // Retrieve the SPO Access Token var spoAdminAccessToken = await ProvisioningAppManager.AccessTokenProvider.GetAccessTokenAsync( AuthenticationConfig.ClientId, AuthenticationConfig.ClientSecret, AuthenticationConfig.RedirectUri, AuthenticationConfig.GetSpoScopes(adminSiteUrl)); // Configure the resulting dictionary accessTokens.Add(new Uri(AuthenticationConfig.GraphBaseUrl).Authority, graphAccessToken); accessTokens.Add(new Uri(model.SPORootSiteUrl).Authority, spoAccessToken); accessTokens.Add(new Uri(adminSiteUrl).Authority, spoAdminAccessToken); return(accessTokens); }
private async Task <CanProvisionResult> CanProvisionInternal(CanProvisionModel model) { var canProvisionResult = new CanProvisionResult(); String provisioningScope = ConfigurationManager.AppSettings["SPPA:ProvisioningScope"]; String provisioningEnvironment = ConfigurationManager.AppSettings["SPPA:ProvisioningEnvironment"]; var graphAccessToken = model.AccessTokens != null && model.AccessTokens.ContainsKey("graph.microsoft.com") ? model.AccessTokens["graph.microsoft.com"] : null; if (graphAccessToken == null) { throw new ApplicationException("Invalid request, the request should contain a valid access token!"); } // 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 spoAuthority = new Uri(rootSiteUrl).Authority; var spoAccessToken = model.AccessTokens != null && model.AccessTokens.ContainsKey(spoAuthority) ? model.AccessTokens[spoAuthority] : null; if (string.IsNullOrEmpty(spoAccessToken)) { throw new ApplicationException($"Invalid request, the requested is missing a valid access token for {spoAuthority}!"); } // Store the SPO Access Token for any further context cloning accessTokens.Add(spoAuthority, 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 { var resourceUri = $"https://{r}"; // Try to get a fresh new Access Token var token = await ProvisioningAppManager.AccessTokenProvider.GetAccessTokenAsync( AuthenticationConfig.ClientId, AuthenticationConfig.ClientSecret, AuthenticationConfig.RedirectUri, resourceUri.Equals(AuthenticationConfig.GraphBaseUrl, StringComparison.InvariantCultureIgnoreCase) ? AuthenticationConfig.GetGraphScopes() : AuthenticationConfig.GetSpoScopes(resourceUri)); 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"); var adminSiteAuthority = new Uri(adminSiteUrl).Authority; // Retrieve the SPO Access Token for the Admin Site var spoAdminAccessToken = model.AccessTokens != null && model.AccessTokens.ContainsKey(adminSiteAuthority) ? model.AccessTokens[adminSiteAuthority] : await ProvisioningAppManager.AccessTokenProvider.GetAccessTokenAsync( AuthenticationConfig.ClientId, AuthenticationConfig.ClientSecret, AuthenticationConfig.RedirectUri, AuthenticationConfig.GetSpoScopes(adminSiteUrl)); // Store the SPO Admin Access Token for any further context cloning accessTokens.Add(adminSiteAuthority, spoAdminAccessToken); // Connect to SPO Admin Site and evaluate the CanProvision rules for the hierarchy using (var tenantContext = authManager.GetAccessTokenContext(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.GetAccessTokenContext(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); }
public void ConfigureAuth(IAppBuilder app) { app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType); String provisioningScope = ConfigurationManager.AppSettings["SPPA:ProvisioningScope"]; String provisioningEnvironment = ConfigurationManager.AppSettings["SPPA:ProvisioningEnvironment"]; app.UseCookieAuthentication(new CookieAuthenticationOptions { CookiePath = $"/{provisioningScope}" ?? "/" }); app.UseOAuth2CodeRedeemer( new OAuth2CodeRedeemerOptions { ClientId = AuthenticationConfig.ClientId, ClientSecret = AuthenticationConfig.ClientSecret, RedirectUri = AuthenticationConfig.RedirectUri }); app.UseOpenIdConnectAuthentication( new OpenIdConnectAuthenticationOptions { Authority = AuthenticationConfig.Authority, ClientId = AuthenticationConfig.ClientId, RedirectUri = AuthenticationConfig.RedirectUri, PostLogoutRedirectUri = AuthenticationConfig.RedirectUri, Scope = $"{AuthenticationConfig.BasicSignInScopes} {AuthenticationConfig.GraphScopes}", TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters { // instead of using the default validation (validating against a single issuer value, as we do in line of business apps), // we inject our own multitenant validation logic ValidateIssuer = false, }, Notifications = new OpenIdConnectAuthenticationNotifications() { //SecurityTokenValidated = (context) => //{ // return Task.FromResult(0); //}, AuthorizationCodeReceived = async(context) => { // Upon successful sign in, get the access token & cache it using MSAL IConfidentialClientApplication clientApp = MsalAppBuilder.BuildConfidentialClientApplication(); AuthenticationResult result = await clientApp.AcquireTokenByAuthorizationCode(AuthenticationConfig.GetGraphScopes(), context.Code).ExecuteAsync(); }, AuthenticationFailed = (context) => { var httpContext = (HttpContextBase)context.OwinContext.Environment["System.Web.HttpContextBase"]; var routeData = new RouteData(); routeData.Values["controller"] = "Home"; routeData.Values["action"] = "Error"; routeData.Values["exception"] = context.Exception; IController errorController = DependencyResolver.Current.GetService <HomeController>(); var requestContext = new RequestContext(httpContext, routeData); errorController.Execute(requestContext); // context.OwinContext.Response.Redirect("/Home/Error"); context.HandleResponse(); // Suppress the exception //context.OwinContext.Response.Write(context.Exception.ToString()); return(Task.FromResult(0)); } } }); }