/// <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
                }
            });
        }
Example #3
0
        /// <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));
                    }
                }
            });
        }