Exemplo n.º 1
0
        public async Task <IActionResult> Login(LoginInputModel model, string button)
        {
            // check if we are in the context of an authorization request
            var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);

            // the user clicked the "cancel" button
            if (button != "login")
            {
                if (context != null)
                {
                    // if the user cancels, send a result back into IdentityServer as if they
                    // denied the consent (even if this client does not require consent).
                    // this will send back an access denied OIDC error response to the client.
                    await _interaction.GrantConsentAsync(context, ConsentResponse.Denied);

                    // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                    if (await _clientStore.IsPkceClientAsync(context.ClientId))
                    {
                        // if the client is PKCE then we assume it's native, so this change in how to
                        // return the response is for better UX for the end user.
                        return(View("Redirect", new RedirectViewModel {
                            RedirectUrl = model.ReturnUrl
                        }));
                    }

                    return(Redirect(model.ReturnUrl));
                }
                else
                {
                    // since we don't have a valid context, then we just go back to the home page
                    return(Redirect("~/"));
                }
            }

            if (ModelState.IsValid)
            {
                // validate username/password against in-memory store
                if (_users.ValidateCredentials(model.Username, model.Password))
                {
                    var user = _users.FindByUsername(model.Username);
                    await _events.RaiseAsync(new UserLoginSuccessEvent(user.Username, user.SubjectId, user.Username, clientId : context?.ClientId));

                    // write a temp, encrypted cookie with values required for delegation.  Cookie gets cleared on effective signin.
                    var cookieModel = new DelegationDataBag()
                    {
                        Subject       = user.SubjectId,
                        UserName      = user.Username,
                        ReturnUrl     = model.ReturnUrl ?? "",
                        RememberLogin = model.RememberLogin
                    };
                    var cookieDataInJson = JsonConvert.SerializeObject(cookieModel);
                    var protectedData    = _protector.Protect(cookieDataInJson);
                    var options          = new CookieOptions
                    {
                        Expires = DateTime.Now.AddMinutes(15)
                    };

                    Response.Cookies.Append("DelegationDataBagCookie", protectedData, options);

                    return(await ExecuteDelegationWhenApplicable(user.SubjectId, user.Username, model.ReturnUrl, model.RememberLogin));

                    // rest of code removed - is now handled after the delegation screen
                }

                await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials", clientId : context?.ClientId));

                ModelState.AddModelError(string.Empty, AccountOptions.InvalidCredentialsErrorMessage);
            }

            // something went wrong, show form with error
            var vm = await BuildLoginViewModelAsync(model);

            return(View(vm));
        }
        public async Task <IActionResult> Callback()
        {
            // read external identity from the temporary cookie
            var result = await HttpContext.AuthenticateAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);

            if (result?.Succeeded != true)
            {
                throw new Exception("External authentication error");
            }

            if (_logger.IsEnabled(LogLevel.Debug))
            {
                var externalClaims = result.Principal.Claims.Select(c => $"{c.Type}: {c.Value}");
                _logger.LogDebug("External claims: {@claims}", externalClaims);
            }

            BaseAuthProvider authProvider = ProviderFactory.CreateProvider(result);

            var subject = authProvider.GetSubject();

            if (string.IsNullOrEmpty(subject))
            {
                throw new Exception("External authentication error");
            }

            // lookup our user and external provider info
            var(user, provider, providerUserId, claims) = await FindUserFromExternalProvider(result, subject);

            if (user == null)
            {
                string email    = authProvider.GetEmail();
                var    fullName = result.Principal.Identity.Name;

                user = await _userService.RegisterUserAsync(new UserDto
                {
                    FullName   = fullName,
                    Position   = "",
                    Email      = email,
                    RoleId     = (int)Roles.Spectator,
                    ExternalId = subject
                });
            }

            // this allows us to collect any additional claims or properties
            // for the specific protocols used and store them in the local auth cookie.
            // this is typically used to store data needed for signout from those protocols.
            var additionalLocalClaims = new List <Claim>();
            var localSignInProps      = new AuthenticationProperties();


            ProcessLoginCallbackForOidc(result, additionalLocalClaims, localSignInProps, user);

            // issue authentication cookie for user
            var isuser = new IdentityServerUser(subject)
            {
                DisplayName      = user.FullName,
                IdentityProvider = provider,
                AdditionalClaims = additionalLocalClaims,
            };

            await HttpContext.SignInAsync(isuser, localSignInProps);

            // delete temporary cookie used during external authentication
            await HttpContext.SignOutAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);

            // retrieve return URL
            var returnUrl = result.Properties.Items["returnUrl"] ?? "~/";

            // check if external login is in the context of an OIDC request
            var context = await _interaction.GetAuthorizationContextAsync(returnUrl);

            await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, subject, user.FullName, true, context?.ClientId));

            if (context != null)
            {
                if (await _clientStore.IsPkceClientAsync(context.ClientId))
                {
                    // if the client is PKCE then we assume it's native, so this change in how to
                    // return the response is for better UX for the end user.
                    return(this.LoadingPage("Redirect", returnUrl));
                }
            }

            return(Redirect(returnUrl));
        }
Exemplo n.º 3
0
        public async Task <IActionResult> Login(LoginInputModel model, string button)
        {
            // check if we are in the context of an authorization request
            var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);

            // the user clicked the "cancel" button
            if (button != "login")
            {
                if (context != null)
                {
                    // if the user cancels, send a result back into IdentityServer as if they
                    // denied the consent (even if this client does not require consent).
                    // this will send back an access denied OIDC error response to the client.
                    await _interaction.GrantConsentAsync(context, ConsentResponse.Denied);

                    // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                    if (await _clientStore.IsPkceClientAsync(context.ClientId))
                    {
                        // if the client is PKCE then we assume it's native, so this change in how to
                        // return the response is for better UX for the end user.
                        return(View("Redirect", new RedirectViewModel {
                            RedirectUrl = model.ReturnUrl
                        }));
                    }

                    return(Redirect(model.ReturnUrl));
                }
                else
                {
                    // since we don't have a valid context, then we just go back to the home page
                    return(Redirect("~/"));
                }
            }

            if (ModelState.IsValid)
            {
                var result = await _signInManager.PasswordSignInAsync(model.Username, model.Password, model.RememberLogin, lockoutOnFailure : true);

                if (result.Succeeded)
                {
                    var user = await _userManager.FindByNameAsync(model.Username);

                    await _events.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id, user.UserName, clientId : context?.ClientId));

                    if (context != null)
                    {
                        if (await _clientStore.IsPkceClientAsync(context.ClientId))
                        {
                            // if the client is PKCE then we assume it's native, so this change in how to
                            // return the response is for better UX for the end user.
                            return(View("Redirect", new RedirectViewModel {
                                RedirectUrl = model.ReturnUrl
                            }));
                        }

                        // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                        return(Redirect(model.ReturnUrl));
                    }

                    // request for a local page
                    if (Url.IsLocalUrl(model.ReturnUrl))
                    {
                        return(Redirect(model.ReturnUrl));
                    }
                    else if (string.IsNullOrEmpty(model.ReturnUrl))
                    {
                        return(Redirect("~/"));
                    }
                    else
                    {
                        // user might have clicked on a malicious link - should be logged
                        throw new Exception("invalid return URL");
                    }
                }

                await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials", clientId : context?.ClientId));

                ModelState.AddModelError(string.Empty, AccountOptions.InvalidCredentialsErrorMessage);
            }

            // something went wrong, show form with error
            var vm = await BuildLoginViewModelAsync(model);

            return(View(vm));
        }
        public async Task <IActionResult> Callback()
        {
            // read external identity from the temporary cookie
            var result = await HttpContext.AuthenticateAsync(
                IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);

            if (result?.Succeeded != true)
            {
                throw new Exception("External authentication error");
            }

            if (_logger.IsEnabled(LogLevel.Debug))
            {
                var externalClaims = result.Principal.Claims.Select(c => $"{c.Type}: {c.Value}");
                _logger.LogDebug("External claims: {@claims}", externalClaims);
            }

            // lookup our user and external provider info
            var(user, provider, providerUserId, claims) = await FindUserFromExternalProvider(result);

            if (user == null)
            {
                // this might be where you might initiate a custom workflow for user registration
                // in this sample we don't show how that would be done, as our sample implementation
                // simply auto-provisions new external user
                if (provider == "Facebook")
                {
                    // redirect to the RegisterUserFromFacebook view.
                    return(RedirectToAction(
                               "RegisterUserFromFacebook",
                               "UserRegistration",
                               new RegisterUserFromFacebookInputViewModel()
                    {
                        Email = claims.FirstOrDefault(c =>
                                                      c.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress")?.Value,
                        GivenName = claims.FirstOrDefault(c =>
                                                          c.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname")?.Value,
                        FamilyName = claims.FirstOrDefault(c =>
                                                           c.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname")?.Value,
                        Provider = provider,
                        ProviderUserId = providerUserId
                    }));
                }
                else
                {
                    user = await AutoProvisionWindowsUser(provider, providerUserId, claims);
                }
            }

            // this allows us to collect any additonal claims or properties
            // for the specific prtotocols used and store them in the local auth cookie.
            // this is typically used to store data needed for signout from those protocols.
            var additionalLocalClaims = new List <Claim>();
            var localSignInProps      = new AuthenticationProperties();

            ProcessLoginCallbackForOidc(result, additionalLocalClaims, localSignInProps);
            ProcessLoginCallbackForWsFed(result, additionalLocalClaims, localSignInProps);
            ProcessLoginCallbackForSaml2p(result, additionalLocalClaims, localSignInProps);

            // issue authentication cookie for user
            await HttpContext.SignInAsync(user.Subject, user.Username,
                                          provider, localSignInProps, additionalLocalClaims.ToArray());

            // delete temporary cookie used during external authentication
            await HttpContext.SignOutAsync(
                IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);

            // retrieve return URL
            var returnUrl = result.Properties.Items["returnUrl"] ?? "~/";

            // check if external login is in the context of an OIDC request
            var context = await _interaction.GetAuthorizationContextAsync(returnUrl);

            await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId,
                                                               user.Subject, user.Username, true, context?.ClientId));

            if (context != null)
            {
                if (await _clientStore.IsPkceClientAsync(context.ClientId))
                {
                    // if the client is PKCE then we assume it's native, so this change in how to
                    // return the response is for better UX for the end user.
                    return(View("Redirect", new RedirectViewModel {
                        RedirectUrl = returnUrl
                    }));
                }
            }

            return(Redirect(returnUrl));
        }
Exemplo n.º 5
0
        public async Task <IActionResult> Callback()
        {
            // read external identity from the temporary cookie
            var result = await HttpContext.AuthenticateAsync(IdentityConstants.ExternalScheme);

            if (result?.Succeeded != true)
            {
                throw new Exception("External authentication error");
            }

            var externalUser = result.Principal;
            var claims       = externalUser.Claims.ToList();

            var userIdClaim = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Subject);

            if (userIdClaim == null)
            {
                userIdClaim = claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier);
            }

            if (userIdClaim == null)
            {
                throw new Exception("Unknown userid");
            }

            claims.Remove(userIdClaim);

            if (_logger.IsEnabled(LogLevel.Debug))
            {
                var externalClaims = result.Principal.Claims.Select(c => $"{c.Type}: {c.Value}");
                _logger.LogDebug("External claims: {@claims}", externalClaims);
            }

            var provider = result.Properties.Items["scheme"];
            var userId   = userIdClaim.Value;

            var user = await _userManager.FindByLoginAsync(provider, userId);

            if (user == null)
            {
                user = new IdentityUser {
                    UserName = Guid.NewGuid().ToString()
                };
                await _userManager.CreateAsync(user);

                await _userManager.AddLoginAsync(user, new UserLoginInfo(provider, userId, provider));
            }
            // this allows us to collect any additonal claims or properties
            // for the specific prtotocols used and store them in the local auth cookie.
            // this is typically used to store data needed for signout from those protocols.
            var additionalLocalClaims = new List <Claim>();
            var localSignInProps      = new AuthenticationProperties();

            ProcessLoginCallbackForOidc(result, additionalLocalClaims, localSignInProps);
            ProcessLoginCallbackForWsFed(result, additionalLocalClaims, localSignInProps);
            ProcessLoginCallbackForSaml2p(result, additionalLocalClaims, localSignInProps);

            // issue authentication cookie for user
            await HttpContext.SignInAsync(user.Id, user.UserName, provider, localSignInProps, additionalLocalClaims.ToArray());

            // delete temporary cookie used during external authentication
            await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);

            // retrieve return URL
            var returnUrl = result.Properties.Items["returnUrl"] ?? "~/";

            // check if external login is in the context of an OIDC request
            var context = await _interaction.GetAuthorizationContextAsync(returnUrl);

            await _events.RaiseAsync(new UserLoginSuccessEvent(provider, userIdClaim.Value, user.Id, user.UserName, true, context?.ClientId));

            if (context != null)
            {
                if (await _clientStore.IsPkceClientAsync(context.ClientId))
                {
                    // if the client is PKCE then we assume it's native, so this change in how to
                    // return the response is for better UX for the end user.
                    return(View("Redirect", new RedirectViewModel {
                        RedirectUrl = returnUrl
                    }));
                }
            }

            return(Redirect(returnUrl));
        }
Exemplo n.º 6
0
        public async Task <IActionResult> Login(LoginInputModel model, string button)
        {
            // the user clicked the "cancel" button
            if (button != "login")
            {
                return(await CancelTokenRequest(model.ReturnUrl));
            }

            if (ModelState.IsValid)
            {
                // check if we are in the context of an authorization request
                var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);

                var result = await _signInManager.PasswordSignInAsync(model.Username, model.Password, model.RememberLogin, lockoutOnFailure : true);

                if (result.RequiresTwoFactor)
                {
                    return(await RedirectTo2FA(model.ReturnUrl, model.Username));
                }

                if (result.Succeeded)
                {
                    var user = await _userManager.FindByNameAsync(model.Username);

                    // Redirect to 2fa offer screen if any options are available
                    if (TwoFACompulsary())
                    {
                        if (context != null)
                        {
                            await _interaction.GrantConsentAsync(context, ConsentResponse.Denied);
                        }

                        return(RedirectToAction("Register2FA", new { redirectUrl = model.ReturnUrl }));
                    }

                    // Redirect to 2fa offer screen if any options are available
                    if (Any2FAEnabled())
                    {
                        return(RedirectToAction("LoginSuccessful", new { redirectUrl = model.ReturnUrl, show2FARegMessage = true }));
                    }

                    await _events.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id, user.UserName));

                    if (context != null)
                    {
                        if (await _clientStore.IsPkceClientAsync(context.ClientId))
                        {
                            // if the client is PKCE then we assume it's native, so this change in how to
                            // return the response is for better UX for the end user.
                            return(View("Redirect", new RedirectViewModel {
                                RedirectUrl = model.ReturnUrl
                            }));
                        }

                        // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                        return(Redirect(model.ReturnUrl));
                    }

                    // request for a local page
                    if (Url.IsLocalUrl(model.ReturnUrl))
                    {
                        return(Redirect(model.ReturnUrl));
                    }
                    else if (string.IsNullOrEmpty(model.ReturnUrl))
                    {
                        return(Redirect("~/"));
                    }
                    else
                    {
                        // user might have clicked on a malicious link - should be logged
                        throw new Exception("invalid return URL");
                    }
                }
                else
                {
                    if (result.IsLockedOut)
                    {
                        await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "account locked out"));

                        ModelState.AddModelError(string.Empty, AccountOptions.AccountLockedOutErrorMessage);
                    }
                    else
                    {
                        await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials"));

                        ModelState.AddModelError(string.Empty, AccountOptions.InvalidCredentialsErrorMessage);
                    }
                }
            }

            // something went wrong, show form with error
            var vm = await BuildLoginViewModelAsync(model);

            return(View(vm));
        }
Exemplo n.º 7
0
        public async Task <IActionResult> Callback()
        {
            // read external identity from the temporary cookie
            var result = await HttpContext.AuthenticateAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);

            if (result?.Succeeded != true)
            {
                throw new Exception("External authentication error");
            }

            var extPrincipal  = result.Principal;
            var expProperties = result.Properties;
            var claims        = extPrincipal.Claims.ToList();

            var userIdClaim = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Subject);

            if (userIdClaim == null)
            {
                userIdClaim = claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier);
            }
            if (userIdClaim == null)
            {
                throw new Exception("Unknown userid");
            }

            claims.Remove(userIdClaim);
            var provider = expProperties.Items["scheme"];
            var userId   = userIdClaim.Value;

            var user = await _userManager.FindByLoginAsync(provider, userId);

            if (user == null)
            {
                var candidateId = Guid.NewGuid();
                user = new ApplicationUser();
                var emailClaim = claims.FirstOrDefault(x => x.Type == ClaimTypes.Email);
                if (emailClaim != null)
                {
                    user.UserName       = emailClaim.Value;
                    user.Email          = emailClaim.Value;
                    user.EmailConfirmed = true;
                }
                var firstNameClaim = claims.FirstOrDefault(x => x.Type == ClaimTypes.GivenName);
                if (firstNameClaim != null)
                {
                    user.FirstName = firstNameClaim.Value;
                }
                var lastNameClaim = claims.FirstOrDefault(x => x.Type == ClaimTypes.Surname);
                if (lastNameClaim != null)
                {
                    user.LastName = lastNameClaim.Value;
                }
                user.UserType = EnumUserType.Audience;
                var createResult = await _userManager.CreateAsync(user);

                if (createResult.Succeeded)
                {
                    var loginResult = await _userManager.AddLoginAsync(user, new UserLoginInfo(provider, userId, provider));

                    if (loginResult.Succeeded)
                    {
                        // Update Tokens to AspNet Identity
                        var externalLoginInfo = new ExternalLoginInfo(extPrincipal, provider, userId, provider)
                        {
                            AuthenticationTokens = expProperties.GetTokens()
                        };
                        await _signInManager.UpdateExternalAuthenticationTokensAsync(externalLoginInfo);
                    }
                }
            }

            // this allows us to collect any additonal claims or properties
            // for the specific prtotocols used and store them in the local auth cookie.
            // this is typically used to store data needed for signout from those protocols.
            var additionalLocalClaims = new List <Claim>();
            var localSignInProps      = new AuthenticationProperties();

            ProcessLoginCallbackForOidc(result, additionalLocalClaims, localSignInProps);
            ProcessLoginCallbackForWsFed(result, additionalLocalClaims, localSignInProps);
            ProcessLoginCallbackForSaml2p(result, additionalLocalClaims, localSignInProps);

            // issue authentication cookie for user
            await _events.RaiseAsync(new UserLoginSuccessEvent(provider, userId, user.Id, user.UserName));

            await HttpContext.SignInAsync(
                user.Id, user.UserName, provider, localSignInProps, additionalLocalClaims.ToArray()
                );

            // delete temporary cookie used during external authentication
            await HttpContext.SignOutAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);

            // retrieve return URL
            var returnUrl = result.Properties.Items["returnUrl"] ?? "~/";

            // check if external login is in the context of an OIDC request
            var context = await _interaction.GetAuthorizationContextAsync(returnUrl);

            if (context != null)
            {
                if (await _clientStore.IsPkceClientAsync(context.ClientId))
                {
                    // if the client is PKCE then we assume it's native, so this change in how to
                    // return the response is for better UX for the end user.
                    return(View("Redirect", new RedirectViewModel {
                        RedirectUrl = returnUrl
                    }));
                }
            }

            return(Redirect(returnUrl));
        }
Exemplo n.º 8
0
        public async Task <IActionResult> Callback()
        {
            // read external identity from the temporary cookie
            var result = await HttpContext.AuthenticateAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);

            if (result?.Succeeded != true)
            {
                throw new Exception("External authentication error");
            }

            var externalUser = result.Principal;

            // try to determine the unique id of the external user (issued by the provider)
            // the most common claim type for that are the sub claim and the NameIdentifier
            // depending on the external provider, some other claim type might be used
            var userIdClaim = externalUser.FindFirst(JwtClaimTypes.Subject) ??
                              externalUser.FindFirst(ClaimTypes.NameIdentifier) ??
                              throw new Exception("Unknown userid");

            // this allows us to collect any additonal claims or properties
            // for the specific prtotocols used and store them in the local auth cookie.
            // this is typically used to store data needed for signout from those protocols.
            var additionalLocalClaims = new List <Claim>();
            var localSignInProps      = new AuthenticationProperties();
            var googleData            = ProcessLoginCallbackForOidc(result, additionalLocalClaims, localSignInProps);

            // remove the user id claim so we don't include it as an extra claim if/when we provision the user
            var claims = externalUser.Claims.ToList();

            claims.Remove(userIdClaim);

            var provider       = result.Properties.Items["scheme"];
            var providerUserId = userIdClaim.Value;

            // find external user
            //var user = _users.FindByExternalProvider(provider, providerUserId);

            var user = _context.Users.FirstOrDefault(f => f.NameIdentifier == providerUserId);

            //user doesnt exist so we want to add him/her
            if (user == null)
            {
                user = new AppUser()
                {
                    Email          = googleData.Email,
                    FirstName      = googleData.FirstName,
                    LastName       = googleData.Surname,
                    Id             = DateTime.Now.Ticks.ToString(),
                    NameIdentifier = googleData.NameIdentifier,
                    UserName       = googleData.Name,
                    PictureUrl     = googleData.Image
                };

                _context.Users.Add(user);

                _context.SaveChanges();
            }

            var token = new Token()
            {
                Expires  = googleData.Expires,
                Issued   = googleData.Issued,
                Name     = googleData.TokenName,
                UserId   = user.Id,
                Provider = provider,
                Type     = googleData.TokenType,
                Value    = googleData.AccessToken,
                Refresh  = googleData.Refresh,
                ImageUrl = googleData.Image,
                Locale   = googleData.Locale
            };

            _context.Tokens.Add(token);
            _context.SaveChanges();



            // issue authentication cookie for user
            await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.Id, user.UserName));

            await HttpContext.SignInAsync(user.NameIdentifier, user.UserName, provider, localSignInProps, additionalLocalClaims.ToArray());

            // delete temporary cookie used during external authentication
            await HttpContext.SignOutAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);

            // retrieve return URL
            var returnUrl = result.Properties.Items["returnUrl"] ?? "~/";

            // check if external login is in the context of an OIDC request
            var context = await _interaction.GetAuthorizationContextAsync(returnUrl);


            if (context != null)
            {
                if (await _clientStore.IsPkceClientAsync(context.ClientId))
                {
                    // if the client is PKCE then we assume it's native, so this change in how to
                    // return the response is for better UX for the end user.
                    Debug.WriteLine("ret url : " + returnUrl);
                    return(View("Redirect", new RedirectViewModel {
                        RedirectUrl = returnUrl
                    }));
                }
            }

            Debug.WriteLine("ret url : " + returnUrl);
            return(Redirect(returnUrl));
        }
        public async Task <IActionResult> Login(LoginInputModel model, string button)
        {
            // check if we are in the context of an authorization request
            var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);

            var redirectDomain = HelperUrl.GetRedirectDomain(model.ReturnUrl);
            var ReturnUrl      = HelperUrl.GetRedirectUrl(model.ReturnUrl);
            var clientId       = HelperUrl.GetClientId(model.ReturnUrl);


            if (ModelState.IsValid)
            {
                model.RememberLogin = true;
                // validate username/password against in-memory store
                var user = await _usersServices.Auth(model.Username, model.Password);

                if (user.IsNull())
                {
                    await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials"));

                    ModelState.AddModelError("", AccountOptions.InvalidCredentialsErrorMessage);
                }
                else if (user.Error.IsNotNullOrEmpty())
                {
                    await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials"));

                    ModelState.AddModelError("", user.Error);
                }
                else
                {
                    if (user.ChangePassword)
                    {
                        model.ReturnUrl = "/ChangePassword?ReturnUrl=" + ReturnUrl;
                    }

                    await _events.RaiseAsync(new UserLoginSuccessEvent(user.Username, user.SubjectId, user.Username));

                    // only set explicit expiration here if user chooses "remember me".
                    // otherwise we rely upon expiration configured in cookie middleware.
                    AuthenticationProperties props = null;
                    if (AccountOptions.AllowRememberLogin && model.RememberLogin)
                    {
                        props = new AuthenticationProperties
                        {
                            IsPersistent = true,
                            ExpiresUtc   = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
                        };
                    }
                    ;

                    // issue authentication cookie with subject ID and username
                    await HttpContext.SignInAsync(user.SubjectId, user.Username, props, user.Claims.ToArray());

                    if (context != null)
                    {
                        if (await _clientStore.IsPkceClientAsync(context.ClientId))
                        {
                            // if the client is PKCE then we assume it's native, so this change in how to
                            // return the response is for better UX for the end user.
                            return(View("Redirect", new RedirectViewModel {
                                RedirectUrl = model.ReturnUrl
                            }));
                        }

                        // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                        return(Redirect(model.ReturnUrl));
                    }

                    // request for a local page
                    if (Url.IsLocalUrl(model.ReturnUrl))
                    {
                        return(Redirect(model.ReturnUrl));
                    }
                    else if (string.IsNullOrEmpty(model.ReturnUrl))
                    {
                        return(Redirect("~/"));
                    }
                    else
                    {
                        // user might have clicked on a malicious link - should be logged
                        throw new Exception("invalid return URL");
                    }
                }
            }

            // something went wrong, show form with error
            var vm = await BuildLoginViewModelAsync(model);

            return(View(vm));
        }
        public async Task <IActionResult> Login(LoginInputModel model, string button)
        {
            // check if we are in the context of an authorization request
            // unutar ovog projekta u Config.cs postavljen je RedirectUri
            // GetAuthorizedContext provjerava da li je returnUri s kojeg je dosao request unutar jedan od onih unutar Configa.cs
            // Ovo sprecava druge ljude da rucno odu na nas localhost:5000/Account/Login i da dobiju pristup

            var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);

            // the user clicked the "cancel" button
            // ovaj citav IF je jeben za skontat, al nece se nama ovo desavat
            // i da se desi postavljeno je ovo sve defaultno od Identity Servera da ih vraca odakle su dosli
            if (button != "login")
            {
                if (context != null)
                {
                    // if the user cancels, send a result back into IdentityServer as if they
                    // denied the consent (even if this client does not require consent).
                    // this will send back an access denied OIDC error response to the client.
                    await _interaction.GrantConsentAsync(context, ConsentResponse.Denied);

                    // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                    if (await _clientStore.IsPkceClientAsync(context.ClientId))
                    {
                        // if the client is PKCE then we assume it's native, so this change in how to
                        // return the response is for better UX for the end user.
                        return(this.LoadingPage("Redirect", model.ReturnUrl));
                    }

                    return(Redirect(model.ReturnUrl));
                }
                else
                {
                    // since we don't have a valid context, then we just go back to the home page
                    return(Redirect("~/"));
                }
            }


            // Ova if petlja ako je izvor uredu i ako nema gresaka validacijskih unutar ViewModela
            if (ModelState.IsValid)
            {
                // Ova funkcija je bukvalno za login od strane Microsoft Identitya
                var result = await _signInManager.PasswordSignInAsync(model.Username, model.Password, model.RememberLogin, lockoutOnFailure : true);

                if (result.Succeeded)
                {
                    // Microsoft Identity funkcija koja vraca ApplicationUser objekat lika koji se ulogovao
                    var user = await _userManager.FindByNameAsync(model.Username);

                    //Ovo je od Identity Servera 4 da ga obavjestimo da je User uspjesno logovan i da mu da Token ili Cookies ili sta vec
                    await _events.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id, user.UserName, clientId : context?.ClientId));

                    //Ista provjera ko gora na prvom velikom ifu
                    // Provjeravamo da li je request pravi, validan
                    if (context != null)
                    {
                        // Kod nas nece bit PKCE klijenata ovdje nece nikad uci
                        if (await _clientStore.IsPkceClientAsync(context.ClientId))
                        {
                            // if the client is PKCE then we assume it's native, so this change in how to
                            // return the response is for better UX for the end user.
                            return(this.LoadingPage("Redirect", model.ReturnUrl));
                        }

                        // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                        // Uspjesno smo loginovali korisnika, dali mu Access Token i mozemo ga redirectat na Festival
                        return(Redirect(model.ReturnUrl));
                    }

                    // request for a local page
                    // ovo je ako je los autorizaciji request tj. ako je context == null
                    // vracamo ga odakle je dosao
                    if (Url.IsLocalUrl(model.ReturnUrl))
                    {
                        return(Redirect(model.ReturnUrl));
                    }
                    // Ako user nema return url vracamo ga na pocetnu stranicu nasu
                    // u ovom slucaju pocetnu od identity servera
                    else if (string.IsNullOrEmpty(model.ReturnUrl))
                    {
                        var roles = await _userManager.GetRolesAsync(user);

                        if (roles.Contains("Admin"))
                        {
                            return(Redirect("https://127.0.0.1:44330/Admin"));
                        }
                        else
                        {
                            return(Redirect("https://127.0.0.1:44330/"));
                        }
                    }
                    // ako skripta, bot ili slicno pokusaju nam loginovat throwa exception
                    else
                    {
                        // user might have clicked on a malicious link - should be logged
                        throw new Exception("invalid return URL");
                    }
                }
                // Ako malo bolje se zagledas ovo je bukvalno Else od onog gore Result.Succeded tj ako je pogresne kredencijale ukucao
                await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials", clientId : context?.ClientId));

                ModelState.AddModelError(string.Empty, AccountOptions.InvalidCredentialsErrorMessage);
            }

            // something went wrong, show form with error
            // Vracamo ga na nas Login View gdje mu izbacujemo Invalid username or passowrd
            // Pokusaj jednom pogresno ukucat i vidjeces da ce ti ovaj dio bacit
            var vm = await BuildLoginViewModelAsync(model);

            return(View(vm));
        }
Exemplo n.º 11
0
        public async Task <IActionResult> Login(LoginInputModel model, string button)
        {
            // check if we are in the context of an authorization request
            var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);

            // the user clicked the "cancel" button
            if (button != "login")
            {
                if (context != null)
                {
                    // if the user cancels, send a result back into IdentityServer as if they
                    // denied the consent (even if this client does not require consent).
                    // this will send back an access denied OIDC error response to the client.
                    await _interaction.GrantConsentAsync(context, ConsentResponse.Denied);

                    // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                    if (await _clientStore.IsPkceClientAsync(context.ClientId))
                    {
                        // if the client is PKCE then we assume it's native, so this change in how to
                        // return the response is for better UX for the end user.
                        return(View("Redirect", new RedirectViewModel {
                            RedirectUrl = model.ReturnUrl
                        }));
                    }

                    return(Redirect(model.ReturnUrl));
                }
                else
                {
                    // since we don't have a valid context, then we just go back to the home page
                    return(Redirect("~/"));
                }
            }

            if (ModelState.IsValid)
            {
                HttpClient client = _httpClientFactory.CreateClient();
                var        disco  = await client.GetDiscoveryDocumentAsync(new DiscoveryDocumentRequest
                {
                    Address = Configuration["IdentityService:Authority"],
                    Policy  =
                    {
                        RequireHttps = false
                    }
                });

                if (disco.IsError)
                {
                    throw new Exception(disco.Error);
                }
                var tokenResponse = await client.RequestPasswordTokenAsync(new PasswordTokenRequest
                {
                    Address      = disco.TokenEndpoint,
                    ClientId     = "GeneralApiClient",
                    ClientSecret = "P@ssw0rd",
                    UserName     = model.Username,
                    Password     = model.Password,
                    Scope        = "GeneralServiceApi offline_access"
                });

                if (!tokenResponse.IsError)
                {
                    await _events.RaiseAsync(new UserLoginSuccessEvent("", model.Username, ""));

                    // only set explicit expiration here if user chooses "remember me".
                    // otherwise we rely upon expiration configured in cookie middleware.
                    AuthenticationProperties props = null;
                    if (AccountOptions.AllowRememberLogin && model.RememberLogin)
                    {
                        props = new AuthenticationProperties
                        {
                            IsPersistent = true,
                            ExpiresUtc   = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
                        };
                    }
                    ;

                    GeneralApiToken generalApiToken = new GeneralApiToken()
                    {
                        ExpiresAt    = DateTime.UtcNow.AddSeconds(tokenResponse.ExpiresIn),
                        AccessToken  = tokenResponse.AccessToken,
                        RefreshToken = tokenResponse.RefreshToken
                    };
                    Claim        tokenClaim = new Claim("general_api_token", JsonConvert.SerializeObject(generalApiToken));
                    List <Claim> listClaim  = new List <Claim>()
                    {
                        tokenClaim
                    };
                    // issue authentication cookie with subject ID and username
                    await HttpContext.SignInAsync(model.Username, props, listClaim.ToArray());

                    if (context != null)
                    {
                        if (await _clientStore.IsPkceClientAsync(context.ClientId))
                        {
                            // if the client is PKCE then we assume it's native, so this change in how to
                            // return the response is for better UX for the end user.
                            return(View("Redirect", new RedirectViewModel {
                                RedirectUrl = model.ReturnUrl
                            }));
                        }

                        // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                        return(Redirect(model.ReturnUrl));
                    }

                    // request for a local page
                    if (Url.IsLocalUrl(model.ReturnUrl))
                    {
                        return(Redirect(model.ReturnUrl));
                    }
                    else if (string.IsNullOrEmpty(model.ReturnUrl))
                    {
                        return(Redirect("~/"));
                    }
                    else
                    {
                        // user might have clicked on a malicious link - should be logged
                        throw new Exception("invalid return URL");
                    }
                }
                else
                {
                    await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials"));

                    string errMsg = tokenResponse.Error + ":" + (string.IsNullOrEmpty(tokenResponse.ErrorDescription) ? "" : tokenResponse.ErrorDescription);
                    ModelState.AddModelError(string.Empty, errMsg);
                }
            }

            // something went wrong, show form with error
            var vm = await BuildLoginViewModelAsync(model);

            return(View(vm));
        }
Exemplo n.º 12
0
        public async Task <IActionResult> Callback()
        {
            // read external identity from the temporary cookie
            var result = await HttpContext.AuthenticateAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);

            if (result?.Succeeded != true)
            {
                throw new Exception("External authentication error");
            }

            var externalUser = result.Principal;

            string FullName  = externalUser.FindFirst(ClaimTypes.Name)?.Value ?? " ";
            string GivenName = externalUser.FindFirst(ClaimTypes.GivenName)?.Value ?? " ";
            string Surname   = externalUser.FindFirst(ClaimTypes.Surname)?.Value ?? " ";
            string Email     = externalUser.FindFirst(ClaimTypes.Email)?.Value;

            // lookup our user and external provider info
            var(user, provider, providerUserId, claims) = FindUserFromExternalProvider(result);
            if (user == null)
            {
                var newUser = new User
                {
                    Name           = GivenName,
                    Username       = Email,
                    Password       = "",
                    Profile        = "Everyone",
                    Email          = Email,
                    Provider       = provider,
                    UserProviderId = providerUserId
                };

                _userRepository.Add(newUser);

                user = newUser;
            }
            else
            {
                user.UserProviderId = providerUserId;
                user.Provider       = provider;

                _userRepository.Update(user);
                _userRepository.Save();
            }

            // this allows us to collect any additonal claims or properties
            // for the specific prtotocols used and store them in the local auth cookie.
            // this is typically used to store data needed for signout from those protocols.
            var additionalLocalClaims = new List <Claim>();
            var localSignInProps      = new AuthenticationProperties();

            ProcessLoginCallbackForOidc(result, additionalLocalClaims, localSignInProps);
            ProcessLoginCallbackForWsFed(result, additionalLocalClaims, localSignInProps);
            ProcessLoginCallbackForSaml2p(result, additionalLocalClaims, localSignInProps);

            // issue authentication cookie for user
            await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.UsersId.ToString(), user.Username));


            var isuser = new IdentityServerUser(user.UsersId.ToString())
            {
                DisplayName      = user.Username,
                IdentityProvider = provider,
                AdditionalClaims = additionalLocalClaims
            };
            await HttpContext.SignInAsync(isuser, localSignInProps);

            // delete temporary cookie used during external authentication
            await HttpContext.SignOutAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);

            // retrieve return URL
            var returnUrl = result.Properties.Items["returnUrl"] ?? "~/";

            // check if external login is in the context of an OIDC request
            var context = await _interaction.GetAuthorizationContextAsync(returnUrl);

            if (context != null)
            {
                if (await _clientStore.IsPkceClientAsync(context.Client.ClientId))
                {
                    // if the client is PKCE then we assume it's native, so this change in how to
                    // return the response is for better UX for the end user.
                    return(View("Redirect", new RedirectViewModel {
                        RedirectUrl = returnUrl
                    }));
                }
            }

            return(Redirect(returnUrl));
        }
Exemplo n.º 13
0
        public async Task <IActionResult> Login(LoginInputModel model, string button)
        {
            // check if we are in the context of an authorization request
            AuthorizationRequest context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);

            // the user clicked the "cancel" button
            if (button != "login")
            {
                if (context != null)
                {
                    // if the user cancels, send a result back into IdentityServer as if they
                    // denied the consent (even if this client does not require consent).
                    // this will send back an access denied OIDC error response to the client.
                    await _interaction.GrantConsentAsync(context, ConsentResponse.Denied);

                    // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                    if (await _clientStore.IsPkceClientAsync(context.ClientId))
                    {
                        // if the client is PKCE then we assume it's native, so this change in how to
                        // return the response is for better UX for the end user.
                        return(View("Redirect", new RedirectViewModel {
                            RedirectUrl = model.ReturnUrl
                        }));
                    }

                    return(Redirect(model.ReturnUrl));
                }
                else
                {
                    // since we don't have a valid context, then we just go back to the home page
                    return(Redirect("~/"));
                }
            }

            if (ModelState.IsValid)
            {
                DiscoveryResponse disco = await DiscoveryClient.GetAsync("http://localhost:5000");

                TokenClient tokenClient   = new TokenClient(disco.TokenEndpoint, "MvcServer", "secret");
                var         tokenResponse = await tokenClient.RequestClientCredentialsAsync("api1");

                var client = new HttpClient();
                client.SetBearerToken(tokenResponse.AccessToken);
                try
                {
                    var response = await client.GetAsync("http://localhost:5001/api/values/" + model.Username + "/" + model.Password);

                    if (!response.IsSuccessStatusCode)
                    {
                        throw new Exception("Resource server is not working!");
                    }
                    else
                    {
                        var content = await response.Content.ReadAsStringAsync();

                        User user = JsonConvert.DeserializeObject <User>(content);
                        if (user != null)
                        {
                            await _events.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.UserId, user.UserName));

                            // only set explicit expiration here if user chooses "remember me".
                            // otherwise we rely upon expiration configured in cookie middleware.
                            AuthenticationProperties props = null;
                            if (AccountOptions.AllowRememberLogin && model.RememberLogin)
                            {
                                props = new AuthenticationProperties
                                {
                                    IsPersistent = true,
                                    ExpiresUtc   = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
                                };
                            }
                            ;

                            //             context.Result = new GrantValidationResult(
                            //user.SubjectId ?? throw new ArgumentException("Subject ID not set", nameof(user.SubjectId)),
                            //OidcConstants.AuthenticationMethods.Password, _clock.UtcNow.UtcDateTime,
                            //user.Claims);

                            // issue authentication cookie with subject ID and username
                            await HttpContext.SignInAsync(user.UserId, user.UserName, props);

                            if (context != null)
                            {
                                if (await _clientStore.IsPkceClientAsync(context.ClientId))
                                {
                                    // if the client is PKCE then we assume it's native, so this change in how to
                                    // return the response is for better UX for the end user.
                                    return(View("Redirect", new RedirectViewModel {
                                        RedirectUrl = model.ReturnUrl
                                    }));
                                }

                                // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                                return(Redirect(model.ReturnUrl));
                            }

                            // request for a local page
                            if (Url.IsLocalUrl(model.ReturnUrl))
                            {
                                return(Redirect(model.ReturnUrl));
                            }
                            else if (string.IsNullOrEmpty(model.ReturnUrl))
                            {
                                return(Redirect("~/"));
                            }
                            else
                            {
                                // user might have clicked on a malicious link - should be logged
                                throw new Exception("invalid return URL");
                            }
                        }

                        await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials"));

                        ModelState.AddModelError("", AccountOptions.InvalidCredentialsErrorMessage);
                    }
                }
                catch (Exception ex)
                {
                    await _events.RaiseAsync(new UserLoginFailureEvent("Resource server", "is not working!"));

                    ModelState.AddModelError("", "Resource server is not working");
                }
            }

            // something went wrong, show form with error
            var vm = await BuildLoginViewModelAsync(model);

            return(View(vm));
        }
        public async Task <IActionResult> Login(LoginInputModel model, string button)
        {
            // check if we are in the context of an authorization request
            //检查我们是否在授权请求的上下文中
            var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);

            // the user clicked the "cancel" button
            // 用户点击了取消按钮
            if (button != "login")
            {
                if (context != null)
                {
                    // if the user cancels, send a result back into IdentityServer as if they
                    // denied the consent (even if this client does not require consent).
                    // this will send back an access denied OIDC error response to the client.
                    //如果用户取消,则将结果发送回IdentityServer,如同他们拒绝同意一样(即使此客户端不需要同意)。
                    //这将向客户端发送拒绝访问的OIDC错误响应。
                    await _interaction.GrantConsentAsync(context, ConsentResponse.Denied);

                    // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                    //我们可以信任Model.ReturnURL,因为GetAuthorizationContextAsync返回非空值
                    if (await _clientStore.IsPkceClientAsync(context.ClientId))
                    {
                        // if the client is PKCE then we assume it's native, so this change in how to
                        // return the response is for better UX for the end user.
                        //如果客户机是pkce,那么我们假设它是本机的,所以如何返回响应的这种更改是为了更好地为最终用户提供UX。
                        return(View("Redirect", new RedirectViewModel {
                            RedirectUrl = model.ReturnUrl
                        }));
                    }

                    return(Redirect(model.ReturnUrl));
                }
                else
                {
                    // since we don't have a valid context, then we just go back to the home page
                    //因为我们没有有效的上下文,所以我们只需返回主页
                    return(Redirect("~/"));
                }
            }

            if (ModelState.IsValid)
            {
                // validate username/password against in-memory store

                /*
                 * if (_users.ValidateCredentials(model.Username, model.Password))
                 * {
                 *  var user = _users.FindByUsername(model.Username);
                 *  await _events.RaiseAsync(new UserLoginSuccessEvent(user.Username, user.SubjectId, user.Username));
                 *
                 *  // only set explicit expiration here if user chooses "remember me".
                 *  // otherwise we rely upon expiration configured in cookie middleware.
                 *  AuthenticationProperties props = null;
                 *  if (AccountOptions.AllowRememberLogin && model.RememberLogin)
                 *  {
                 *      props = new AuthenticationProperties
                 *      {
                 *          IsPersistent = true,
                 *          ExpiresUtc = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
                 *      };
                 *  };
                 *
                 *  // issue authentication cookie with subject ID and username
                 *  await HttpContext.SignInAsync(user.SubjectId, user.Username, props);
                 *
                 *  if (context != null)
                 *  {
                 *      if (await _clientStore.IsPkceClientAsync(context.ClientId))
                 *      {
                 *          // if the client is PKCE then we assume it's native, so this change in how to
                 *          // return the response is for better UX for the end user.
                 *          return View("Redirect", new RedirectViewModel { RedirectUrl = model.ReturnUrl });
                 *      }
                 *
                 *      // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                 *      return Redirect(model.ReturnUrl);
                 *  }
                 *
                 *  // request for a local page
                 *  if (Url.IsLocalUrl(model.ReturnUrl))
                 *  {
                 *      return Redirect(model.ReturnUrl);
                 *  }
                 *  else if (string.IsNullOrEmpty(model.ReturnUrl))
                 *  {
                 *      return Redirect("~/");
                 *  }
                 *  else
                 *  {
                 *      // user might have clicked on a malicious link - should be logged
                 *      throw new Exception("invalid return URL");
                 *  }
                 * }
                 */

                var user = _userDbContext.Users.Where(x => x.Name == model.Username && x.Password == model.Password).FirstOrDefault();
                if (user != null)
                {
                    //var user = _users.FindByUsername(model.Username);

                    // RaiseAsync 引发指定的事件。
                    // 引发用户登录成功的事件
                    await _events.RaiseAsync(new UserLoginSuccessEvent(user.Name, user.Id.ToString(), user.Name));

                    // only set explicit expiration here if user chooses "remember me".
                    // otherwise we rely upon expiration configured in cookie middleware.
                    //仅当用户选择“记住我”时才在此处设置显式过期。
                    //否则,我们依赖于在cookie中间件中配置的过期。
                    AuthenticationProperties props = null; // 用于存储有关身份验证会话的状态值的字典
                    //记住登录
                    if (AccountOptions.AllowRememberLogin && model.RememberLogin)
                    {
                        props = new AuthenticationProperties
                        {
                            IsPersistent = true,//获取或设置是否跨多个请求持久化身份验证会话
                            //获取或设置身份验证票证过期的时间。 默认30天?
                            ExpiresUtc = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
                        };
                    }
                    ;

                    // issue authentication cookie with subject ID and username
                    //颁发具有使用者ID和用户名的身份验证cookie
                    await HttpContext.SignInAsync(user.Id.ToString(), user.Name, props);

                    if (context != null)
                    {
                        if (await _clientStore.IsPkceClientAsync(context.ClientId))
                        {
                            // if the client is PKCE then we assume it's native, so this change in how to
                            // return the response is for better UX for the end user.
                            return(View("Redirect", new RedirectViewModel {
                                RedirectUrl = model.ReturnUrl
                            }));
                        }

                        // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                        return(Redirect(model.ReturnUrl));
                    }

                    // request for a local page
                    if (Url.IsLocalUrl(model.ReturnUrl))
                    {
                        return(Redirect(model.ReturnUrl));
                    }
                    else if (string.IsNullOrEmpty(model.ReturnUrl))
                    {
                        return(Redirect("~/"));
                    }
                    else
                    {
                        // user might have clicked on a malicious link - should be logged
                        //用户可能单击了恶意链接-应记录
                        throw new Exception("invalid return URL");
                    }
                }

                //引发登录失败的事件
                await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials"));

                ModelState.AddModelError(string.Empty, AccountOptions.InvalidCredentialsErrorMessage);
            }

            // something went wrong, show form with error
            //出错,表单显示错误内容
            var vm = await BuildLoginViewModelAsync(model);

            return(View(vm));
        }
Exemplo n.º 15
0
        public async Task <IActionResult> Callback()
        {
            // read external identity from the temporary cookie
            var result = await HttpContext.AuthenticateAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);

            if (result?.Succeeded != true)
            {
                throw new Exception("External authentication error");
            }
            var retrnurl = result.Properties.Items["returnUrl"];

            // lookup our user and external provider info
            var(user, provider, providerUserId, claims) = await FindUserFromExternalProviderAsync(result);

            if (user == null)
            {
                // this might be where you might initiate a custom workflow for user registration
                // in this sample we don't show how that would be done, as our sample implementation
                // simply auto-provisions new external user
                //user = _userManager.FindByEmailAsync(claim)
                var email = claims.FirstOrDefault(x => x.Value.Contains("@"))?.Value;
                if (!string.IsNullOrWhiteSpace(email))
                {
                    var tentativeUser = await _userManager.FindByEmailAsync(email);

                    if (tentativeUser != null)
                    {
                        //var retrnurl = result.Properties.Items["returnUrl"];
                        var m = new ExternalLoginAssociationViewModel {
                            Email               = email,
                            Provider            = provider,
                            ProviderKey         = providerUserId,
                            ProviderDisplayName = provider,
                            ReturnUrl           = retrnurl
                        };
                        return(View("ExternalLoginAssociation", m));
                    }
                }
                else
                {
                    email = "None";
                }

                //await HttpContext.SignOutAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);
                return(View("ExternalLoginFailure", new ExternalLoginFailureViewModel {
                    Email = email, RedirectUri = retrnurl, ClientName = ""
                }));                                                                                                                               //RedirectToAction(nameof(AccountController.Login));

                //user = AutoProvisionUser(provider, providerUserId, claims);
                //return RedirectToAction(nameof(AccountController.Login));
            }

            // this allows us to collect any additonal claims or properties
            // for the specific prtotocols used and store them in the local auth cookie.
            // this is typically used to store data needed for signout from those protocols.
            var additionalLocalClaims = new List <Claim>();

            var localSignInProps = new AuthenticationProperties()
            {
                IsPersistent = true,
                ExpiresUtc   = DateTimeOffset.UtcNow.Add(AccountOptions.ExternalProviderLoginDurationOverride)
            };

            ProcessLoginCallbackForOidc(result, additionalLocalClaims, localSignInProps);
            ProcessLoginCallbackForWsFed(result, additionalLocalClaims, localSignInProps);
            ProcessLoginCallbackForSaml2p(result, additionalLocalClaims, localSignInProps);

            // issue authentication cookie for user
            await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.Id, user.UserName));

            await _signInManager.SignInAsync(user, localSignInProps, provider);

            //await HttpContext.SignInAsync(user.Id, user.UserName, provider, localSignInProps, additionalLocalClaims.ToArray());

            // delete temporary cookie used during external authentication
            await HttpContext.SignOutAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);


            // retrieve return URL
            var returnUrl = result.Properties.Items["returnUrl"] ?? "~/";

            // check if external login is in the context of an OIDC request
            var context = await _interaction.GetAuthorizationContextAsync(returnUrl);

            if (context != null)
            {
                if (await _clientStore.IsPkceClientAsync(context.ClientId))
                {
                    // if the client is PKCE then we assume it's native, so this change in how to
                    // return the response is for better UX for the end user.
                    return(View("Redirect", new RedirectViewModel {
                        RedirectUrl = returnUrl
                    }));
                }
            }

            return(Redirect(returnUrl));
        }
Exemplo n.º 16
0
        public async Task <IActionResult> Callback()
        {
            var result = await HttpContext.AuthenticateAsync(
                IdentityServerConstants.ExternalCookieAuthenticationScheme
                );

            if (false == result?.Succeeded)
            {
                logger.LogError($"[ExternalController.Callback] {result.Failure}");
                throw result.Failure ?? new Exception();
            }

            var(user, provider, providerUserId, claims) = await FindCustomerFromExternalProviderAsync(result);

            if (null == user)
            {
                //user = await AutoProvisionCustomerAsync(provider, providerUserId, claims);
                return(await AutoProvisionCustomerAsync(provider, providerUserId, claims));
            }

            var localClaims     = new List <Claim>();
            var localProperties = new AuthenticationProperties();

            ProcessLoginCallbackForOidc(result, localClaims, localProperties);
            //ProcessLoginCallbackForWsFed(result, localClaims, localProperties);
            //ProcessLoginCallbackForSaml2p(result, localClaims, localProperties);

            // issue authentication cookie for user
            await eventService.RaiseAsync(new UserLoginSuccessEvent(
                                              provider,
                                              providerUserId,
                                              user.Id.ToString(),
                                              user.UserName)
                                          );

            var signin = await signInManager.ExternalLoginSignInAsync(provider, providerUserId, true);

            if (false == signin.Succeeded)
            {
                return(BadRequest());
            }

            // delete temporary cookie used during external authentication
            await HttpContext.SignOutAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);

            // retrieve return URL
            var returnUrl = result.Properties.Items["returnUrl"] ?? "~/";
            // check if external login is in the context of an OIDC request
            var context = await interaction.GetAuthorizationContextAsync(returnUrl);

            if (null != context)
            {
                if (await clientStore.IsPkceClientAsync(context.ClientId))
                {
                    // if the client is PKCE then we assume it's native, so this change in how to
                    // return the response is for better UX for the end user.
                    return(View("Redirect", new RedirectModel {
                        RedirectUrl = returnUrl
                    }));
                }
            }

            return(Redirect(returnUrl));
        }
Exemplo n.º 17
0
        public async Task <IActionResult> Callback()
        {
            // read external identity from the temporary cookie
            var result = await HttpContext.AuthenticateAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);

            if (result?.Succeeded != true)
            {
                throw new Exception("External authentication error");
            }

            if (_logger.IsEnabled(LogLevel.Debug))
            {
                var externalClaims = result.Principal.Claims.Select(c => $"{c.Type}: {c.Value}");
                _logger.LogDebug("External claims: {@claims}", externalClaims);
            }

            // lookup our user and external provider info
            var(user, provider, providerUserId, claims) = await FindUserFromExternalProvider(result);

            if (user == null)
            {
                // Aqui se podría empezar un flow de registro para indicar campos para registrar el usuario
                // Por ahora se crea el usuario con la información básica usando los claims recibidos
                user = await AutoProvisionUser(provider, providerUserId, claims);
            }

            // this allows us to collect any additonal claims or properties for the specific
            // prtotocols used and store them in the local auth cookie. this is typically used to
            // store data needed for signout from those protocols.
            var additionalLocalClaims = new List <Claim>();
            var localSignInProps      = new AuthenticationProperties();

            ProcessLoginCallbackForOidc(result, additionalLocalClaims, localSignInProps);
            ProcessLoginCallbackForWsFed(result, additionalLocalClaims, localSignInProps);
            ProcessLoginCallbackForSaml2p(result, additionalLocalClaims, localSignInProps);

            // issue authentication cookie for user
            await HttpContext.SignInAsync(user.Id.ToString(), user.UserName, provider, localSignInProps, additionalLocalClaims.ToArray());

            // delete temporary cookie used during external authentication
            await HttpContext.SignOutAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);

            // retrieve return URL
            var returnUrl = result.Properties.Items["returnUrl"] ?? "~/";

            // check if external login is in the context of an OIDC request
            var context = await _interaction.GetAuthorizationContextAsync(returnUrl);

            await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.Id.ToString(), user.UserName, true, context?.ClientId));

            if (context != null)
            {
                if (await _clientStore.IsPkceClientAsync(context.ClientId))
                {
                    // if the client is PKCE then we assume it's native, so this change in how to
                    // return the response is for better UX for the end user.
                    return(View("Redirect", new RedirectViewModel {
                        RedirectUrl = returnUrl
                    }));
                }
            }

            return(Redirect(returnUrl));
        }
Exemplo n.º 18
0
        public async Task <IActionResult> Login(LoginInputModel model, string button)
        {
            // check if we are in the context of an authorization request
            var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);

            // the user clicked the "cancel" button
            if (button != "login")
            {
                if (context != null)
                {
                    // if the user cancels, send a result back into IdentityServer as if they
                    // denied the consent (even if this client does not require consent).
                    // this will send back an access denied OIDC error response to the client.
                    await _interaction.GrantConsentAsync(context, ConsentResponse.Denied);

                    // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                    if (await _clientStore.IsPkceClientAsync(context.ClientId))
                    {
                        // if the client is PKCE then we assume it's native, so this change in how to
                        // return the response is for better UX for the end user.
                        return(View("Redirect", new RedirectViewModel {
                            RedirectUrl = model.ReturnUrl
                        }));
                    }

                    return(Redirect(model.ReturnUrl));
                }
                else
                {
                    // since we don't have a valid context, then we just go back to the home page
                    return(Redirect("~/"));
                }
            }

            if (ModelState.IsValid)
            {
                //var result = await _signInManager.PasswordSignInAsync(model.Username, model.Password, model.RememberLogin, lockoutOnFailure: true);

                ApplicationUser user = await GetUserByUsernameOrEmail(model.Username);

                if (user == null || user.PasswordHash == null)
                {
                    await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials"));

                    ModelState.AddModelError("", AccountOptions.InvalidCredentialsErrorMessage);
                    var vm1 = await BuildLoginViewModelAsync(model);

                    return(View(vm1));
                }

                var isLockedOut = await _userManager.IsLockedOutAsync(user);

                if (isLockedOut)
                {
                    await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "user is locked out"));

                    ModelState.AddModelError("", AccountOptions.InvalidCredentialsErrorMessage);
                    var vm1 = await BuildLoginViewModelAsync(model);

                    return(View(vm1));
                }

                var result = _userManager.PasswordHasher.VerifyHashedPassword(user, user.PasswordHash, model.Password);

                //if (result.Succeeded)
                //{
                if (result != PasswordVerificationResult.Failed) //result is either Success or SuccessRehashNeeded
                {
                    //var user = await _userManager.FindByNameAsync(model.Username);
                    await _events.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id, user.UserName));

                    if (result == PasswordVerificationResult.SuccessRehashNeeded)
                    {
                        //update passwordHash from old to new encryption
                        user.PasswordHash = _userManager.PasswordHasher.HashPassword(user, model.Password);
                    }
                    user.AccessFailedCount = 0;
                    await _userManager.UpdateAsync(user);

                    AuthenticationProperties props = null;
                    if (AccountOptions.AllowRememberLogin && model.RememberLogin)
                    {
                        props = new AuthenticationProperties
                        {
                            IsPersistent = true,
                            ExpiresUtc   = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
                        };
                    }
                    ;

                    await _signInManager.SignInAsync(user, props);

                    if (context != null)
                    {
                        if (await _clientStore.IsPkceClientAsync(context.ClientId))
                        {
                            // if the client is PKCE then we assume it's native, so this change in how to
                            // return the response is for better UX for the end user.
                            return(View("Redirect", new RedirectViewModel {
                                RedirectUrl = model.ReturnUrl
                            }));
                        }

                        // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                        return(Redirect(model.ReturnUrl));
                    }

                    // request for a local page
                    if (Url.IsLocalUrl(model.ReturnUrl))
                    {
                        return(Redirect(model.ReturnUrl));
                    }
                    else if (string.IsNullOrEmpty(model.ReturnUrl))
                    {
                        return(Redirect("~/"));
                    }
                    else
                    {
                        // user might have clicked on a malicious link - should be logged
                        throw new Exception("invalid return URL");
                    }
                }

                await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials"));

                ModelState.AddModelError("", AccountOptions.InvalidCredentialsErrorMessage);
            }

            // something went wrong, show form with error
            var vm = await BuildLoginViewModelAsync(model);

            return(View(vm));
        }
Exemplo n.º 19
0
        public async Task <IActionResult> Login(LoginInputModel model, string button)
        {
            // check if we are in the context of an authorization request
            var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);

            // the user clicked the "cancel" button
            if (button != "login")
            {
                if (context != null)
                {
                    // if the user cancels, send a result back into IdentityServer as if they
                    // denied the consent (even if this client does not require consent).
                    // this will send back an access denied OIDC error response to the client.
                    await _interaction.GrantConsentAsync(context, ConsentResponse.Denied);

                    // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                    if (await _clientStore.IsPkceClientAsync(context.ClientId))
                    {
                        // if the client is PKCE then we assume it's native, so this change in how to
                        // return the response is for better UX for the end user.
                        return(View("Redirect", new RedirectViewModel {
                            RedirectUrl = model.ReturnUrl
                        }));
                    }

                    return(Redirect(model.ReturnUrl));
                }
                else
                {
                    // since we don't have a valid context, then we just go back to the home page
                    return(Redirect("~/"));
                }
            }

            if (ModelState.IsValid)
            {
                var user = await _loginService.FindByUsername(model.Username);

                bool rememberMe = AccountOptions.AllowRememberLogin && model.RememberLogin;
                // validate username/password against in-memory store

                var result = await _loginService.PasswordSignInAsync(user, model.Password, rememberMe);

                if (result.Succeeded || result.RequiresTwoFactor)
                {
                    var tokenLifetime = _configuration.GetValue("TokenLifetimeMinutes", 120);
                    await _events.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id, user.UserName));

                    //// only set explicit expiration here if user chooses "remember me".
                    //// otherwise we rely upon expiration configured in cookie middleware.
                    //AuthenticationProperties props = new AuthenticationProperties
                    //{
                    //    ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(tokenLifetime),
                    //    AllowRefresh = true,
                    //    RedirectUri = model.ReturnUrl
                    //};

                    //if (AccountOptions.AllowRememberLogin && model.RememberLogin)
                    //{
                    //    var permanentTokenLifetime = _configuration.GetValue("PermanentTokenLifetimeDays", 365);
                    //    props.ExpiresUtc = DateTimeOffset.UtcNow.AddDays(permanentTokenLifetime);
                    //    props.IsPersistent = true;
                    //};

                    //await _loginService.SignInAsync(user, props);

                    // issue authentication cookie with subject ID and username
                    //await HttpContext.SignInAsync(user.SubjectId, user.Username, props);

                    if (result.RequiresTwoFactor)
                    {
                        return(RedirectToAction("SendCode", "Authority", new { ReturnUrl = model.ReturnUrl, RememberMe = model.RememberLogin }));
                    }

                    if (context != null)
                    {
                        if (await _clientStore.IsPkceClientAsync(context.ClientId))
                        {
                            // if the client is PKCE then we assume it's native, so this change in how to
                            // return the response is for better UX for the end user.
                            return(View("Redirect", new RedirectViewModel {
                                RedirectUrl = model.ReturnUrl
                            }));
                        }

                        // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                        return(Redirect(model.ReturnUrl));
                    }

                    // request for a local page
                    if (Url.IsLocalUrl(model.ReturnUrl))
                    {
                        return(Redirect(model.ReturnUrl));
                    }
                    else if (string.IsNullOrEmpty(model.ReturnUrl))
                    {
                        return(Redirect("~/"));
                    }
                    else
                    {
                        // user might have clicked on a malicious link - should be logged
                        throw new Exception("invalid return URL");
                    }
                }

                if (result.IsLockedOut)
                {
                    _logger.LogWarning(2, "User account locked out.");
                    return(View("Lockout"));
                }

                await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials"));

                ModelState.AddModelError(string.Empty, _sharedLocalizer["INVALID_LOGIN_ATTEMPT"]);
            }


            // something went wrong, show form with error
            var vm = await BuildLoginViewModelAsync(model);

            return(View(vm));
        }
Exemplo n.º 20
0
        public async Task <IActionResult> Login(LoginInputModel model, string button)
        {
            var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);

            if (button != "login")
            {
                if (context != null)
                {
                    await _interaction.GrantConsentAsync(context, ConsentResponse.Denied);

                    if (await _clientStore.IsPkceClientAsync(context.ClientId))
                    {
                        return(View("Redirect", new RedirectViewModel {
                            RedirectUrl = model.ReturnUrl
                        }));
                    }

                    return(Redirect(model.ReturnUrl));
                }
                else
                {
                    return(Redirect("~/"));
                }
            }

            if (ModelState.IsValid)
            {
                var result = await _signInManager.PasswordSignInAsync(model.Username, model.Password, model.RememberLogin, lockoutOnFailure : true);

                if (result.Succeeded)
                {
                    var user = await _userManager.FindByNameAsync(model.Username);

                    await _events.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id, user.UserName, clientId : context?.ClientId));

                    if (context != null)
                    {
                        if (await _clientStore.IsPkceClientAsync(context.ClientId))
                        {
                            return(View("Redirect", new RedirectViewModel {
                                RedirectUrl = model.ReturnUrl
                            }));
                        }

                        return(Redirect(model.ReturnUrl));
                    }

                    if (Url.IsLocalUrl(model.ReturnUrl))
                    {
                        return(Redirect(model.ReturnUrl));
                    }
                    else if (string.IsNullOrEmpty(model.ReturnUrl))
                    {
                        return(Redirect("~/"));
                    }
                    else
                    {
                        throw new Exception("invalid return URL");
                    }
                }

                await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials", clientId : context?.ClientId));

                ModelState.AddModelError(string.Empty, AccountOptions.InvalidCredentialsErrorMessage);
            }

            var vm = await BuildLoginViewModelAsync(model);

            return(View(vm));
        }
Exemplo n.º 21
0
        public async Task <IActionResult> Callback()
        {
            // read external identity from the temporary cookie
            var result = await HttpContext.AuthenticateAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);

            if (result?.Succeeded != true)
            {
                throw new Exception("External authentication error");
            }

            // lookup our user and external provider info
            var(user, provider, providerUserId, claims) = await FindUserFromExternalProvider(result);

            user = await IntegrateExternalUser(provider, providerUserId, claims, user);

            // if (user == null)
            // {
            //     // this might be where you might initiate a custom workflow for user registration
            //     // in this sample we don't show how that would be done, as our sample implementation
            //     // simply auto-provisions new external user
            //     user = await IntegrateExternalUser(provider, providerUserId, claims);
            // }

            // this allows us to collect any additonal claims or properties
            // for the specific prtotocols used and store them in the local auth cookie.
            // this is typically used to store data needed for signout from those protocols.
            var additionalLocalClaims = new List <Claim>();
            var localSignInProps      = new AuthenticationProperties();

            ProcessLoginCallbackForOidc(result, additionalLocalClaims, localSignInProps);
            ProcessLoginCallbackForWsFed(result, additionalLocalClaims, localSignInProps);
            ProcessLoginCallbackForSaml2p(result, additionalLocalClaims, localSignInProps);

            // issue authentication cookie for user
            await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.Id, user.UserName));

            //await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.SubjectId, user.Username));
            await HttpContext.SignInAsync(user.Id, user.UserName, provider, localSignInProps, additionalLocalClaims.ToArray());

            //await HttpContext.SignInAsync(user.SubjectId, user.Username, provider, localSignInProps, additionalLocalClaims.ToArray());

            // delete temporary cookie used during external authentication
            await HttpContext.SignOutAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);

            // retrieve return URL
            var returnUrl = result.Properties.Items["returnUrl"] ?? "~/";

            // check if external login is in the context of an OIDC request
            var context = await _interaction.GetAuthorizationContextAsync(returnUrl);

            if (context != null)
            {
                if (await _clientStore.IsPkceClientAsync(context.ClientId))
                {
                    // if the client is PKCE then we assume it's native, so this change in how to
                    // return the response is for better UX for the end user.
                    return(View("Redirect", new RedirectViewModel {
                        RedirectUrl = returnUrl
                    }));
                }
            }

            return(Redirect(returnUrl));
        }
Exemplo n.º 22
0
        public async Task <IActionResult> Login(LoginInputModel model, string button)
        {
            var context = await identityService.GetAuthorizationContextAsync(model.ReturnUrl);

            if (button != "login")
            {
                if (context != null)
                {
                    // User has cancelled, pretend they denied the consent to IdentityServer4
                    // This will return access_denied OIDC error.
                    await identityService.GrantConsentAsync(context, ConsentResponse.Denied);

                    if (await clientStore.IsPkceClientAsync(context.ClientId))
                    {
                        return(View("Redirect", new RedirectViewModel {
                            RedirectUrl = model.ReturnUrl
                        }));
                    }

                    return(Redirect(model.ReturnUrl));
                }
                else
                {
                    // No valid context. Go home
                    return(Redirect("~/"));
                }
            }

            if (ModelState.IsValid)
            {
                var user = QueryProcessor.Process(new GAME_AuthenticateAndGetUserDetailsQuery {
                    Email = model.Username, EncryptedPassword = model.Password.ToLegacyShaString()
                });

                if (user != UserModel.Default)
                {
                    await eventService.RaiseAsync(new UserLoginSuccessEvent(user.Email, user.AccountId.ToString(), $"{user.FirstName} {user.LastName}"));

                    // Only set explicit expiration if user chooses "remember me"
                    AuthenticationProperties props = null;
                    if (AccountOptions.AllowRememberLogin && model.RememberLogin)
                    {
                        props = new AuthenticationProperties
                        {
                            IsPersistent = true,
                            ExpiresUtc   = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
                        };
                    }

                    await HttpContext.SignInAsync(user.AccountId.ToString(), user.Email, props);

                    if (context != null)
                    {
                        if (await clientStore.IsPkceClientAsync(context.ClientId))
                        {
                            return(View("Redirect", new RedirectViewModel {
                                RedirectUrl = model.ReturnUrl
                            }));
                        }

                        return(Redirect(model.ReturnUrl));
                    }


                    if (Url.IsLocalUrl(model.ReturnUrl))
                    {
                        return(Redirect(model.ReturnUrl));
                    }
                    else if (string.IsNullOrEmpty(model.ReturnUrl))
                    {
                        return(Redirect("~/"));
                    }
                    else
                    {
                        throw new InvalidOperationException("Invalid return URL");
                    }
                }

                await eventService.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials"));

                ModelState.AddModelError("", AccountOptions.InvalidCredentialsErrorMessage);
            }

            // Something went wrong to get here
            var vm = await BuildLoginViewModelAsync(model);

            return(View(vm));
        }
Exemplo n.º 23
0
        public async Task <IActionResult> Login([FromBody] LoginInputModel model)
        {
            // check if we are in the context of an authorization request
            var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);

            //the user clicked the "cancel" button
            if (model.ConfigInfo != "login")
            {
                if (context != null)
                {
                    // if the user cancels, send a result back into IdentityServer as if they
                    // denied the consent (even if this client does not require consent).
                    // this will send back an access denied OIDC error response to the client.
                    await _interaction.GrantConsentAsync(context, ConsentResponse.Denied);

                    // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                    if (await _clientStore.IsPkceClientAsync(context.ClientId))
                    {
                        // if the client is PKCE then we assume it's native, so this change in how to
                        // return the response is for better UX for the end user.
                        return(View("Redirect", new RedirectViewModel {
                            RedirectUrl = model.ReturnUrl
                        }));
                    }

                    return(Redirect(model.ReturnUrl));
                }
            }

            // validate username/password
            var user = await _userManager.FindByNameAsync(model.Username);

            if (user != null && await _userManager.CheckPasswordAsync(user, model.Password))
            {
                await _events.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id, user.Name));

                // only set explicit expiration here if user chooses "remember me".
                // otherwise we rely upon expiration configured in cookie middleware.
                AuthenticationProperties props = null;
                if (AccountOptions.AllowRememberLogin && model.RememberLogin)
                {
                    props = new AuthenticationProperties
                    {
                        IsPersistent = true,
                        ExpiresUtc   = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
                    };
                }
                ;

                // issue authentication cookie with subject ID and username
                await HttpContext.SignInAsync(user.Id, user.UserName, props);

                //return Redirect(model.ReturnUrl);

                if (context != null)
                {
                    if (await _clientStore.IsPkceClientAsync(context.ClientId))
                    {
                        // if the client is PKCE then we assume it's native, so this change in how to
                        // return the response is for better UX for the end user.
                        return(View("Redirect", new RedirectViewModel {
                            RedirectUrl = model.ReturnUrl
                        }));
                    }

                    // wedd can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                    //return Redirect(model.ReturnUrl);
                }
            }

            await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials"));

            ModelState.AddModelError(string.Empty, AccountOptions.InvalidCredentialsErrorMessage);

            // something went wrong, show form with error
            var vm = await BuildLoginViewModelAsync(model);

            return(View(vm));
        }
Exemplo n.º 24
0
        public async Task <IActionResult> OnPostAsync(string button, string returnUrl = null)
        {
            // check if we are in the context of an authorization request
            var context = await _interaction.GetAuthorizationContextAsync(returnUrl);

            // the user clicked the "cancel" button
            if (button != "login")
            {
                if (context != null)
                {
                    // if the user cancels, send a result back into IdentityServer as if they
                    // denied the consent (even if this client does not require consent).
                    // this will send back an access denied OIDC error response to the client.
                    await _interaction.GrantConsentAsync(context, ConsentResponse.Denied);

                    // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                    if (await _clientStore.IsPkceClientAsync(context.ClientId))
                    {
                        // if the client is PKCE then we assume it's native, so this change in how to
                        // return the response is for better UX for the end user.
                        return(View("Redirect", new RedirectViewModel {
                            RedirectUrl = model.ReturnUrl
                        }));
                    }

                    return(Redirect(model.ReturnUrl));
                }
                else
                {
                    // since we don't have a valid context, then we just go back to the home page
                    return(Redirect("~/"));
                }
            }
            returnUrl = returnUrl ?? Url.Content("~/");

            if (ModelState.IsValid)
            {
                // This doesn't count login failures towards account lockout
                // To enable password failures to trigger account lockout, set lockoutOnFailure: true
                var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure : true);

                if (result.Succeeded)
                {
                    _logger.LogInformation("User logged in.");
                    return(LocalRedirect(returnUrl));
                }
                if (result.RequiresTwoFactor)
                {
                    return(RedirectToPage("./LoginWith2fa", new
                    {
                        ReturnUrl = returnUrl,
                        RememberMe = Input.RememberMe
                    }));
                }
                if (result.IsLockedOut)
                {
                    _logger.LogWarning("User account locked out.");
                    return(RedirectToPage("./Lockout"));
                }
                else
                {
                    ModelState.AddModelError(string.Empty, "Invalid login attempt.");
                    return(Page());
                }
            }

            // If we got this far, something failed, redisplay form
            return(Page());
        }
Exemplo n.º 25
0
        public async Task <IActionResult> Callback()
        {
            // read external identity from the temporary cookie
            var result = await HttpContext.AuthenticateAsync(IdentityConstants.ExternalScheme);

            if (result?.Succeeded != true)
            {
                throw new Exception("External authentication error");
            }

            if (_logger.IsEnabled(LogLevel.Debug))
            {
                var externalClaims = result.Principal.Claims.Select(c => $"{c.Type}: {c.Value}");
                _logger.LogDebug("External claims: {@claims}", externalClaims);
            }

            // lookup our user and external provider info
            var(user, provider, providerUserId, claims) = await FindUserFromExternalProviderAsync(result);

            if (user == null)
            {
                // this might be where you might initiate a custom workflow for user registration
                // in this sample we don't show how that would be done, as our sample implementation
                // simply auto-provisions new external user
                user = await AutoProvisionUserAsync(provider, providerUserId, claims);
            }

            // this allows us to collect any additonal claims or properties
            // for the specific prtotocols used and store them in the local auth cookie.
            // this is typically used to store data needed for signout from those protocols.
            var additionalLocalClaims = new List <Claim>();
            var localSignInProps      = new AuthenticationProperties();

            ProcessLoginCallbackForOidc(result, additionalLocalClaims, localSignInProps);
            ProcessLoginCallbackForWsFed(result, additionalLocalClaims, localSignInProps);
            ProcessLoginCallbackForSaml2p(result, additionalLocalClaims, localSignInProps);

            // issue authentication cookie for user
            // we must issue the cookie maually, and can't use the SignInManager because
            // it doesn't expose an API to issue additional claims from the login workflow
            var principal = await _signInManager.CreateUserPrincipalAsync(user);

            additionalLocalClaims.AddRange(principal.Claims);
            var name = principal.FindFirst(JwtClaimTypes.Name)?.Value ?? user.Id;
            await HttpContext.SignInAsync(user.Id, name, provider, localSignInProps, additionalLocalClaims.ToArray());

            // delete temporary cookie used during external authentication
            await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);

            // retrieve return URL
            var returnUrl = result.Properties.Items["returnUrl"] ?? "~/";

            // check if external login is in the context of an OIDC request
            var context = await _interaction.GetAuthorizationContextAsync(returnUrl);

            await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.Id, name, true, context?.ClientId));

            if (context != null)
            {
                if (await _clientStore.IsPkceClientAsync(context.ClientId))
                {
                    // if the client is PKCE then we assume it's native, so this change in how to
                    // return the response is for better UX for the end user.
                    return(View("Redirect", new RedirectViewModel {
                        RedirectUrl = returnUrl
                    }));
                }
            }

            return(Redirect(returnUrl));
        }
Exemplo n.º 26
0
        public async Task <IActionResult> Login(LoginInputModel model, string button, string returnUrl = null)
        {
            // check if we are in the context of an authorization request
            var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);

            // the user clicked the "cancel" button
            if (button != "login")
            {
                if (context != null)
                {
                    // if the user cancels, send a result back into IdentityServer as if they
                    // denied the consent (even if this client does not require consent).
                    // this will send back an access denied OIDC error response to the client.
                    await _interaction.GrantConsentAsync(context, ConsentResponse.Denied);

                    // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                    if (await _clientStore.IsPkceClientAsync(context.ClientId))
                    {
                        // if the client is PKCE then we assume it's native, so this change in how to
                        // return the response is for better UX for the end user.
                        return(View("Redirect", new RedirectViewModel {
                            RedirectUrl = model.ReturnUrl
                        }));
                    }

                    return(Redirect(model.ReturnUrl));
                }
                else
                {
                    // since we don't have a valid context, then we just go back to the home page
                    return(Redirect("~/"));
                }
            }

            if (ModelState.IsValid)
            {
                // Here we query the database against the user's inputted information
                var result = await _signInManager.PasswordSignInAsync(model.Username, model.Password, model.RememberLogin, lockoutOnFailure : false);

                if (result.Succeeded)
                {
                    if (context != null)
                    {
                        if (await _clientStore.IsPkceClientAsync(context.ClientId))
                        {
                            // if the client is PKCE then we assume it's native, so this change in how to
                            // return the response is for better UX for the end user.
                            return(View("Redirect", new RedirectViewModel {
                                RedirectUrl = model.ReturnUrl
                            }));
                        }

                        // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                        return(Redirect(model.ReturnUrl));
                    }

                    // request for a local page
                    if (Url.IsLocalUrl(model.ReturnUrl))
                    {
                        return(Redirect(model.ReturnUrl));
                    }
                    else if (string.IsNullOrEmpty(model.ReturnUrl))
                    {
                        return(Redirect("~/"));
                    }
                }
                else
                {
                    // Refresh the page on invalid login.
                    ModelState.AddModelError(string.Empty, "Invalid login attempt.");
                    return(View(await BuildLoginViewModelAsync(model)));
                }
            }

            // something went wrong, show form with error
            var vm = await BuildLoginViewModelAsync(model);

            return(View(vm));
        }
Exemplo n.º 27
0
        public async Task <IActionResult> Callback()
        {
            // read external identity from the temporary cookie
            var result = await HttpContext.AuthenticateAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);

            if (result?.Succeeded != true)
            {
                throw new Exception("External authentication error");
            }

            if (_logger.IsEnabled(LogLevel.Debug))
            {
                var externalClaims = result.Principal.Claims.Select(c => $"{c.Type}: {c.Value}");
                _logger.LogDebug("External claims: {@claims}", externalClaims);
            }

            // lookup our user and external provider info
            var(user, provider, providerUserId, claims) = FindUserFromExternalProvider(result);
            if (user == null)
            {
                // this might be where you might initiate a custom workflow for user registration
                // in this sample we don't show how that would be done, as our sample implementation
                // simply auto-provisions new external user
                user = AutoProvisionUser(provider, providerUserId, claims);
            }

            // this allows us to collect any additional claims or properties
            // for the specific protocols used and store them in the local auth cookie.
            // this is typically used to store data needed for signout from those protocols.
            var additionalLocalClaims = new List <Claim>();
            var localSignInProps      = new AuthenticationProperties();

            ProcessLoginCallbackForOidc(result, additionalLocalClaims, localSignInProps);
            //ProcessLoginCallbackForWsFed(result, additionalLocalClaims, localSignInProps);
            //ProcessLoginCallbackForSaml2p(result, additionalLocalClaims, localSignInProps);

            // issue authentication cookie for user
            var isuser = new IdentityServerUser(user.SubjectId)
            {
                DisplayName      = user.Username,
                IdentityProvider = provider,
                AdditionalClaims = additionalLocalClaims
            };

            await HttpContext.SignInAsync(isuser, localSignInProps);

            // delete temporary cookie used during external authentication
            await HttpContext.SignOutAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);

            // retrieve return URL
            var returnUrl = result.Properties.Items["returnUrl"] ?? "~/";

            // check if external login is in the context of an OIDC request
            var context = await _interaction.GetAuthorizationContextAsync(returnUrl);

            await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.SubjectId, user.Username, true, context?.ClientId));

            if (context != null)
            {
                if (await _clientStore.IsPkceClientAsync(context.ClientId))
                {
                    // if the client is PKCE then we assume it's native, so this change in how to
                    // return the response is for better UX for the end user.
                    return(this.LoadingPage("Redirect", returnUrl));
                }
            }

            return(Redirect(returnUrl));
        }
Exemplo n.º 28
0
        public async Task <IActionResult> Login(LoginInputModel model, string button)
        {
            var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);

            if (button != "login")
            {
                if (context != null)
                {
                    await _interaction.GrantConsentAsync(context, ConsentResponse.Denied);

                    if (await _clientStore.IsPkceClientAsync(context.ClientId))
                    {
                        return(View("Redirect", new RedirectViewModel {
                            RedirectUrl = model.ReturnUrl
                        }));
                    }

                    return(Redirect(model.ReturnUrl));
                }

                return(Redirect("~/"));
            }

            if (ModelState.IsValid)
            {
                var user = await _userManager.FindByNameAsync(model.Username);

                if (user != null && await _userManager.CheckPasswordAsync(user, model.Password))
                {
                    await _events.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id, user.Name));

                    AuthenticationProperties props = null;
                    if (AccountOptions.AllowRememberLogin && model.RememberLogin)
                    {
                        props = new AuthenticationProperties
                        {
                            IsPersistent = true,
                            ExpiresUtc   = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
                        }
                    }
                    ;
                    ;

                    await _userManager.AddClaimAsync(user, new Claim("userName", user.UserName));

                    await _userManager.AddClaimAsync(user, new Claim("name", user.Name));

                    await _userManager.AddClaimAsync(user, new Claim("email", user.Email));

                    await _userManager.AddClaimAsync(user, new Claim("role", Roles.Consumer));

                    await _userManager.AddClaimAsync(user, new Claim("companyName", user.CompanyName));


                    await HttpContext.SignInAsync(user.Id, user.UserName, props);

                    if (context != null)
                    {
                        if (await _clientStore.IsPkceClientAsync(context.ClientId))
                        {
                            return(View("Redirect", new RedirectViewModel {
                                RedirectUrl = model.ReturnUrl
                            }));
                        }

                        return(Redirect(model.ReturnUrl));
                    }

                    if (Url.IsLocalUrl(model.ReturnUrl))
                    {
                        return(Redirect(model.ReturnUrl));
                    }
                    if (string.IsNullOrEmpty(model.ReturnUrl))
                    {
                        return(Redirect("~/"));
                    }
                    throw new Exception("invalid return URL");
                }

                await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials"));

                ModelState.AddModelError(string.Empty, AccountOptions.InvalidCredentialsErrorMessage);
            }

            // something went wrong, show form with error
            var vm = await BuildLoginViewModelAsync(model);

            return(View(vm));
        }
        public async Task <IActionResult> Login(LoginInputModel model, string button)
        {
            // check if we are in the context of an authorization request
            var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);

            // the user clicked the "cancel" button
            if (button != "login")
            {
                if (context != null)
                {
                    // if the user cancels, send a result back into IdentityServer as if they
                    // denied the consent (even if this client does not require consent).
                    // this will send back an access denied OIDC error response to the client.
                    await _interaction.GrantConsentAsync(context, ConsentResponse.Denied);

                    // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                    if (await _clientStore.IsPkceClientAsync(context.ClientId))
                    {
                        // if the client is PKCE then we assume it's native, so this change in how to
                        // return the response is for better UX for the end user.
                        return(View("Redirect", new RedirectViewModel {
                            RedirectUrl = model.ReturnUrl
                        }));
                    }

                    return(Redirect(model.ReturnUrl));
                }
                else
                {
                    // since we don't have a valid context, then we just go back to the home page
                    return(Redirect("~/"));
                }
            }

            if (ModelState.IsValid)
            {
                // validate username/password against in-memory store
                if (_users.ValidateCredentials(model.Username, model.Password))
                {
                    var user = _users.FindByUsername(model.Username);
                    await _events.RaiseAsync(new UserLoginSuccessEvent(user.Username, user.SubjectId, user.Username, clientId : context?.ClientId));

                    // only set explicit expiration here if user chooses "remember me".
                    // otherwise we rely upon expiration configured in cookie middleware.
                    AuthenticationProperties props = null;
                    if (AccountOptions.AllowRememberLogin && model.RememberLogin)
                    {
                        props = new AuthenticationProperties
                        {
                            IsPersistent = true,
                            ExpiresUtc   = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
                        };
                    }
                    ;

                    // issue authentication cookie with subject ID and username
                    await HttpContext.SignInAsync(user.SubjectId, user.Username, props);

                    if (context != null)
                    {
                        if (await _clientStore.IsPkceClientAsync(context.ClientId))
                        {
                            // if the client is PKCE then we assume it's native, so this change in how to
                            // return the response is for better UX for the end user.
                            return(View("Redirect", new RedirectViewModel {
                                RedirectUrl = model.ReturnUrl
                            }));
                        }

                        // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                        return(Redirect(model.ReturnUrl));
                    }

                    // request for a local page
                    if (Url.IsLocalUrl(model.ReturnUrl))
                    {
                        return(Redirect(model.ReturnUrl));
                    }
                    else if (string.IsNullOrEmpty(model.ReturnUrl))
                    {
                        return(Redirect("~/"));
                    }
                    else
                    {
                        // user might have clicked on a malicious link - should be logged
                        throw new Exception("invalid return URL");
                    }
                }

                await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials", clientId : context?.ClientId));

                ModelState.AddModelError(string.Empty, AccountOptions.InvalidCredentialsErrorMessage);
            }

            // something went wrong, show form with error
            var vm = await BuildLoginViewModelAsync(model);

            return(View(vm));
        }
        public async Task <IActionResult> Login(LoginInputModel model, string button)
        {
            // check if we are in the context of an authorization request
            var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);

            // the user clicked the "cancel" button
            if (button != "login")
            {
                if (context != null)
                {
                    // if the user cancels, send a result back into IdentityServer as if they
                    // denied the consent (even if this client does not require consent).
                    // this will send back an access denied OIDC error response to the client.
                    await _interaction.GrantConsentAsync(context, ConsentResponse.Denied);

                    // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                    if (await _clientStore.IsPkceClientAsync(context.ClientId))
                    {
                        // if the client is PKCE then we assume it's native, so this change in how to
                        // return the response is for better UX for the end user.
                        return(View("Redirect", new RedirectViewModel {
                            RedirectUrl = model.ReturnUrl
                        }));
                    }

                    return(Redirect(model.ReturnUrl));
                }
                else
                {
                    // since we don't have a valid context, then we just go back to the home page
                    return(Redirect("~/"));
                }
            }

            if (ModelState.IsValid)
            {
                // validate username/password
                var user = await _userManager.FindByNameAsync(model.Username);

                if (user != null && await _userManager.CheckPasswordAsync(user, model.Password))
                {
                    //await _events.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id, user.Name));

                    // only set explicit expiration here if user chooses "remember me".
                    // otherwise we rely upon expiration configured in cookie middleware.
                    AuthenticationProperties props = null;
                    if (AccountOptions.AllowRememberLogin && model.RememberLogin)
                    {
                        props = new AuthenticationProperties
                        {
                            IsPersistent = true,
                            ExpiresUtc   = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
                        };
                    }
                    ;

                    // issue authentication cookie with subject ID and username
                    await HttpContext.SignInAsync(user.Id, user.UserName, props);

                    if (context != null)
                    {
                        if (await _clientStore.IsPkceClientAsync(context.ClientId))
                        {
                            // if the client is PKCE then we assume it's native, so this change in how to
                            // return the response is for better UX for the end user.
                            return(View("Redirect", new RedirectViewModel {
                                RedirectUrl = model.ReturnUrl
                            }));
                        }

                        // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                        return(Redirect(model.ReturnUrl));
                    }

                    var validUrlsForClient = new string[]
                    {
                        //"https://localhost:44344/api/Profile/login/callback",
                        "https://localhost:44344/signin-my-auth-server",
                        "https://localhost:44344/signin-my-auth-server/"
                    };

                    // Append query-params to redirect-url
                    var redirectUrl = QueryHelpers.AddQueryString(model.ReturnUrl, new Dictionary <string, string>
                    {
                        { "state", model.State },
                        { "code", Guid.NewGuid().ToString() }
                    });
                    //var uriBuilder = new UriBuilder(model.ReturnUrl);
                    //var query = System.Web.HttpUtility.ParseQueryString(uriBuilder.Query);
                    ////query["state"] = ;
                    //uriBuilder.Query = query.ToString();
                    //var redirectUrl = uriBuilder.ToString();

                    // request for a local page
                    if (Url.IsLocalUrl(model.ReturnUrl))
                    {
                        return(Redirect(redirectUrl));
                    }
                    else if (string.IsNullOrEmpty(model.ReturnUrl))
                    {
                        return(Redirect("~/"));
                    }
                    else if (validUrlsForClient.Contains(model.ReturnUrl))
                    {
                        return(Redirect(redirectUrl));
                    }
                    else
                    {
                        // user might have clicked on a malicious link - should be logged
                        throw new Exception("invalid return URL");
                    }
                }

                //await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials"));
                ModelState.AddModelError(string.Empty, AccountOptions.InvalidCredentialsErrorMessage);
            }

            // something went wrong, show form with error
            var vm = await BuildLoginViewModelAsync(model);

            return(View(vm));
        }