/// <summary> /// Obtain an instance of <see cref="CustomerPrincipal"/> that represents the authenticated user. /// </summary> /// <param name="redirectUri">Address to return to upon receiving a response from the authority.</param> /// <param name="code">The authorization code that was requested.</param> /// <returns>An instance of <see cref="CustomerPrincipal"/> that represents the authenticated user.</returns> /// <exception cref="ArgumentException"> /// <paramref name="code"/> is empty or null. /// </exception> private async Task <CustomerPrincipal> GetCustomerPrincipalAsync(Uri redirectUri, string code) { AuthenticationResult authResult; CustomerPrincipal principal; IGraphClient client; List <RoleModel> roles; code.AssertNotEmpty(nameof(code)); try { authResult = await Provider.AccessToken.AcquireTokenByAuthorizationCodeAsync( $"{Provider.Configuration.ActiveDirectoryEndpoint}/{BotConstants.AuthorityEndpoint}", code, new ApplicationCredential { ApplicationId = Provider.Configuration.ApplicationId, ApplicationSecret = Provider.Configuration.ApplicationSecret, UseCache = true }, redirectUri, Provider.Configuration.GraphEndpoint).ConfigureAwait(false); client = new GraphClient(Provider, authResult.TenantId); roles = await client.GetDirectoryRolesAsync(authResult.UserInfo.UniqueId).ConfigureAwait(false); principal = new CustomerPrincipal { AccessToken = authResult.AccessToken, AvailableIntents = (from intent in Provider.Intent.Intents let roleList = Permissions.GetRoles(intent.Value.Permissions) from r in roleList where roles.SingleOrDefault(x => x.DisplayName.Equals(r)) != null select intent).Distinct().ToDictionary(intent => intent.Key, intent => intent.Value), CustomerId = authResult.TenantId, ExpiresOn = authResult.ExpiresOn, Name = authResult.UserInfo.GivenName, ObjectId = authResult.UserInfo.UniqueId, Roles = roles }; if (!Provider.Configuration.ApplicationTenantId.Equals( authResult.TenantId, StringComparison.CurrentCultureIgnoreCase)) { await Provider.PartnerOperations.GetCustomerAsync(principal, authResult.TenantId).ConfigureAwait(false); } return(principal); } catch (PartnerException ex) { if (ex.ErrorCategory != PartnerErrorCategory.NotFound) { throw; } return(null); } finally { authResult = null; client = null; roles = null; } }
/// <summary> /// Configures authentication for the application. /// </summary> /// <param name="app">The application to be configured.</param> public void ConfigureAuth(IAppBuilder app) { IMigrationService service = MvcApplication.UnityContainer.Resolve <IMigrationService>(); IPartnerOperations operations = MvcApplication.UnityContainer.Resolve <IPartnerOperations>(); app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType); app.UseCookieAuthentication(new CookieAuthenticationOptions()); app.UseOpenIdConnectAuthentication( new OpenIdConnectAuthenticationOptions { ClientId = service.Configuration.ApplicationId, Authority = $"{service.Configuration.ActiveDirectoryEndpoint}/common", Notifications = new OpenIdConnectAuthenticationNotifications { AuthenticationFailed = (context) => { // Track the exceptions using the telemetry provider. service.Telemetry.TrackException(context.Exception); // Pass in the context back to the app context.OwinContext.Response.Redirect("/Home/Error"); // Suppress the exception context.HandleResponse(); return(Task.FromResult(0)); }, AuthorizationCodeReceived = async(context) => { string userTenantId = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value; string signedInUserObjectId = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value; IGraphClient client = new GraphClient(service, userTenantId); List <RoleModel> roles = await client.GetDirectoryRolesAsync(signedInUserObjectId); foreach (RoleModel role in roles) { context.AuthenticationTicket.Identity.AddClaim(new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Role, role.DisplayName)); } bool isPartnerUser = userTenantId.Equals( service.Configuration.PartnerCenterApplicationTenantId, StringComparison.CurrentCultureIgnoreCase); string customerId = string.Empty; string organization = string.Empty; if (!isPartnerUser) { try { Customer c = await operations.GetCustomerAsync(userTenantId); customerId = c.Id; organization = c.CompanyProfile.Domain; } catch (PartnerException ex) { if (ex.ErrorCategory != PartnerErrorCategory.NotFound) { throw; } } } if (isPartnerUser || !string.IsNullOrWhiteSpace(customerId)) { // Add the customer identifier to the claims context.AuthenticationTicket.Identity.AddClaim(new System.Security.Claims.Claim("CustomerId", userTenantId)); context.AuthenticationTicket.Identity.AddClaim(new System.Security.Claims.Claim("Organization", organization)); } }, RedirectToIdentityProvider = (context) => { string appBaseUrl = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase; context.ProtocolMessage.RedirectUri = appBaseUrl + "/"; context.ProtocolMessage.PostLogoutRedirectUri = appBaseUrl; return(Task.FromResult(0)); } }, TokenValidationParameters = new TokenValidationParameters { SaveSigninToken = true, ValidateIssuer = false } }); }
/// <summary> /// Configures application authentication. /// </summary> /// <param name="app">The application to configure.</param> public void ConfigureAuth(IAppBuilder app) { app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType); app.UseCookieAuthentication(new CookieAuthenticationOptions { }); app.UseOpenIdConnectAuthentication( new OpenIdConnectAuthenticationOptions { ClientId = ApplicationConfiguration.ActiveDirectoryClientID, Authority = ApplicationConfiguration.ActiveDirectoryEndPoint + "common", TokenValidationParameters = new 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() { RedirectToIdentityProvider = (context) => { context.ProtocolMessage.Parameters.Add("lc", Resources.Culture.LCID.ToString(CultureInfo.InvariantCulture)); return(Task.FromResult(0)); }, AuthorizationCodeReceived = async(context) => { string userTenantId = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value; string signedInUserObjectId = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value; IGraphClient graphClient = new GraphClient( userTenantId, context.Code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path))); List <RoleModel> roles = await graphClient.GetDirectoryRolesAsync(signedInUserObjectId).ConfigureAwait(false); foreach (RoleModel role in roles) { context.AuthenticationTicket.Identity.AddClaim(new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Role, role.DisplayName)); } if (userTenantId != ApplicationConfiguration.ActiveDirectoryTenantId) { string partnerCenterCustomerId = string.Empty; // Check to see if this login came from the tenant of a customer of the partner PartnerCenter.Models.Customers.Customer customerDetails = await ApplicationDomain.Instance.PartnerCenterClient.Customers.ById(userTenantId).GetAsync().ConfigureAwait(false); // indeed a customer partnerCenterCustomerId = customerDetails.Id; if (!string.IsNullOrWhiteSpace(partnerCenterCustomerId)) { // add the customer ID to the claims context.AuthenticationTicket.Identity.AddClaim(new System.Security.Claims.Claim("PartnerCenterCustomerID", partnerCenterCustomerId)); // fire off call to retrieve this customer's subscriptions and populate the CustomerSubscriptions Repository. } } else { if (context.AuthenticationTicket.Identity.FindFirst(System.Security.Claims.ClaimTypes.Role).Value != Startup.GlobalAdminUserRole) { // this login came from the partner's tenant, only allow admins to access the site, non admins will only // see the unauthenticated experience but they can't configure the portal nor can purchase Trace.TraceInformation("Blocked log in from non admin partner user: {0}", signedInUserObjectId); throw new UnauthorizedException(Resources.NonAdminUnauthorizedMessage, HttpStatusCode.Unauthorized); } } }, AuthenticationFailed = (context) => { // redirect to the error page string errorMessage = (context.Exception.InnerException == null) ? context.Exception.Message : context.Exception.InnerException.Message; context.OwinContext.Response.Redirect($"/Home/Error?errorMessage={errorMessage}"); context.HandleResponse(); return(Task.FromResult(0)); } } }); }