internal bool ShouldEnforceMultiFactorAuthentication(AuthenticateExternalLoginResult result)
        {
            if (result?.Authenticator == null || result.Authentication == null)
            {
                return(false);
            }

            // Enforce multi-factor authentication only if:
            // 1. The authenticator supports multi-factor authentication, otherwise no use.
            // 2. The user has enabled multi-factor authentication for their account.
            // 3. The user authenticated with the personal microsoft account. AAD 2FA policy is controlled by the tenant admins.
            // 4. The user did not use the multi-factor authentication for the session, obviously.
            return(result.Authenticator.SupportsMultiFactorAuthentication() &&
                   result.Authentication.User.EnableMultiFactorAuthentication &&
                   !result.LoginDetails.WasMultiFactorAuthenticated &&
                   result.Authentication.CredentialUsed.IsExternal() &&
                   (CredentialTypes.IsMicrosoftAccount(result.Authentication.CredentialUsed.Type)));
        }
Exemple #2
0
        public static void AddExternalLoginCredentialTypeClaim(List <Claim> claims, string credentialType)
        {
            string claimValue = null;

            if (CredentialTypes.IsMicrosoftAccount(credentialType))
            {
                claimValue = NuGetClaims.ExternalLoginCredentialValues.MicrosoftAccount;
            }
            else if (CredentialTypes.IsAzureActiveDirectoryAccount(credentialType))
            {
                claimValue = NuGetClaims.ExternalLoginCredentialValues.AzureActiveDirectory;
            }

            if (!string.IsNullOrEmpty(claimValue))
            {
                claims.Add(new Claim(NuGetClaims.ExternalLoginCredentialType, claimValue));
            }
        }
        public virtual async Task <ActionResult> LinkExternalAccount(string returnUrl, string error = null, string errorDescription = null)
        {
            // Extract the external login info
            var result = await _authService.AuthenticateExternalLogin(OwinContext);

            if (result.ExternalIdentity == null)
            {
                // User got here without an external login cookie (or an expired one)
                // Send them to the logon action
                string errorMessage = GetAuthenticationFailureMessage(error, errorDescription);
                return(AuthenticationFailureOrExternalLinkExpired(errorMessage));
            }

            if (result.Authentication != null)
            {
                // If we are an administrator and Gallery.EnforcedAuthProviderForAdmin is set
                // to require a specific authentication provider, challenge that provider if needed.
                ActionResult challenge;
                if (ShouldChallengeEnforcedProvider(
                        NuGetContext.Config.Current.EnforcedAuthProviderForAdmin, result.Authentication, returnUrl, out challenge))
                {
                    return(challenge);
                }

                // If we are an administrator and Gallery.EnforcedTenantIdForAdmin is set
                // to require a specific tenant Id, check if the user logged in with the specified tenant.
                if (!SiteAdminHasValidTenant(result.Authentication))
                {
                    string errorMessage = string.Format(Strings.SiteAdminNotLoggedInWithRequiredTenant, NuGetContext.Config.Current.EnforcedTenantIdForAdmin);
                    return(AuthenticationFailureOrExternalLinkExpired(errorMessage));
                }

                if (ShouldEnforceMultiFactorAuthentication(result))
                {
                    // Invoke the authentication again enforcing multi-factor authentication for the same provider.
                    return(ChallengeAuthentication(
                               Url.LinkExternalAccount(returnUrl),
                               result.Authenticator.Name,
                               new AuthenticationPolicy()
                    {
                        Email = result.LoginDetails.EmailUsed, EnforceMultiFactorAuthentication = true
                    }));
                }

                // Remove the password login if the password logins are deprecated and enforced discontinuation.
                if (NuGetContext.Config.Current.DeprecateNuGetPasswordLogins &&
                    _contentObjectService.LoginDiscontinuationConfiguration.IsPasswordLoginDiscontinuedForAll() &&
                    result.Authentication.CredentialUsed.IsExternal() &&
                    result.Authentication.User.HasPasswordCredential())
                {
                    // Remove password logins when a user signs in with an external login.
                    TempData["Message"] = string.Format(Strings.DiscontinuedLogin_PasswordRemoved, NuGetContext.Config.Current.Brand);
                    await RemovePasswordCredential(result.Authentication.User);
                }

                // Create session
                await _authService.CreateSessionAsync(OwinContext,
                                                      result.Authentication,
                                                      wasMultiFactorAuthenticated : result?.LoginDetails?.WasMultiFactorAuthenticated ?? false);

                // Update the 2FA if used during login but user does not have it set on their account. Only for personal microsoft accounts.
                if (result?.LoginDetails != null &&
                    result.LoginDetails.WasMultiFactorAuthenticated &&
                    !result.Authentication.User.EnableMultiFactorAuthentication &&
                    CredentialTypes.IsMicrosoftAccount(result.Credential.Type))
                {
                    await _userService.ChangeMultiFactorAuthentication(result.Authentication.User, enableMultiFactor : true);

                    OwinContext.AddClaim(NuGetClaims.EnabledMultiFactorAuthentication);
                    TempData["Message"] = Strings.MultiFactorAuth_LoginUpdate;
                }

                return(SafeRedirect(returnUrl));
            }
            else
            {
                // Gather data for view model
                string name   = null;
                string email  = null;
                var    authUI = result.Authenticator.GetUI();
                try
                {
                    var userInfo = result.Authenticator.GetIdentityInformation(result.ExternalIdentity);
                    name  = userInfo.Name;
                    email = userInfo.Email;
                }
                catch (Exception)
                {
                    // Consume the exception for now, for backwards compatibility to previous MSA provider.
                    email = result.ExternalIdentity.GetClaimOrDefault(ClaimTypes.Email);
                    name  = result.ExternalIdentity.GetClaimOrDefault(ClaimTypes.Name);
                }

                // Check for a user with this email address
                User existingUser = null;
                if (!string.IsNullOrEmpty(email))
                {
                    existingUser = _userService.FindByEmailAddress(email);
                }

                var foundExistingUser        = existingUser != null;
                var existingUserLinkingError = AssociateExternalAccountViewModel.ExistingUserLinkingErrorType.None;

                if (foundExistingUser)
                {
                    if (existingUser is Organization)
                    {
                        existingUserLinkingError = AssociateExternalAccountViewModel.ExistingUserLinkingErrorType.AccountIsOrganization;
                    }
                    else if (existingUser.Credentials.Any(c => c.IsExternal()) && !existingUser.IsAdministrator)
                    {
                        existingUserLinkingError = AssociateExternalAccountViewModel.ExistingUserLinkingErrorType.AccountIsAlreadyLinked;
                    }
                }

                var external = new AssociateExternalAccountViewModel()
                {
                    ProviderAccountNoun      = authUI.AccountNoun,
                    AccountName              = name,
                    FoundExistingUser        = foundExistingUser,
                    ExistingUserLinkingError = existingUserLinkingError
                };

                var model = new LogOnViewModel
                {
                    External = external,
                    SignIn   = new SignInViewModel
                    {
                        UserNameOrEmail = email
                    },
                    Register = new RegisterViewModel
                    {
                        EmailAddress = email
                    }
                };

                return(LinkExternalView(model));
            }
        }