Exemplo n.º 1
0
        /// <summary>
        /// Detect if a route matches any of whitelisted prefixes
        /// </summary>
        /// <param name="context">Http request context</param>
        /// <param name="authorizationService">Authorization service for each request</param>
        /// <returns>Response be set to 404 if the route is not whitelisted</returns>
        public async Task Invoke(HttpContext context, IAuthorizationService authorizationService = null)
        {
            DateTime requestTime = DateTime.UtcNow;

            // Step 1: if disguise host exists, replace the request header HOST to DISGUISED-HOST
            //         if disguist host does not exist, check and replace ~1 with regex
            if (context.Request.Headers.TryGetValue(DisguisedHostHeader, out StringValues value))
            {
                context.Request.Headers[HostHeader] = value;
            }
            else
            {
                context.Request.Host = new HostString(SanitizeScmUrl(
                                                          context.Request.Headers[HostHeader].FirstOrDefault()));
            }

            if (context.Request.Headers.TryGetValue(ForwardedProtocolHeader, out value))
            {
                context.Request.Scheme = value;
            }

            // Step 2: check if it is homepage route or favicon route, always return 200
            if (IsHomePageRoute(context.Request.Path) || IsFavIconRoute(context.Request.Path))
            {
                context.Response.StatusCode = 200;
                KuduEventGenerator.Log().ApiEvent(
                    ServerConfiguration.GetApplicationName(),
                    "LinuxConsumptionEndpoint",
                    context.Request.GetEncodedPathAndQuery(),
                    context.Request.Method,
                    System.Environment.GetEnvironmentVariable("x-ms-request-id") ?? string.Empty,
                    context.Response.StatusCode,
                    (DateTime.UtcNow - requestTime).Milliseconds,
                    context.Request.GetUserAgent());
                return;
            }

            // Step 3: check if the request endpoint is enabled in Linux Consumption
            if (!IsRouteWhitelisted(context.Request.Path))
            {
                context.Response.StatusCode = 404;
                KuduEventGenerator.Log().ApiEvent(
                    ServerConfiguration.GetApplicationName(),
                    "BlacklistedLinuxConsumptionEndpoint",
                    context.Request.GetEncodedPathAndQuery(),
                    context.Request.Method,
                    System.Environment.GetEnvironmentVariable("x-ms-request-id") ?? string.Empty,
                    context.Response.StatusCode,
                    (DateTime.UtcNow - requestTime).Milliseconds,
                    context.Request.GetUserAgent());
                return;
            }

            // Step 4: check if the request matches authorization policy
            AuthenticateResult authenticationResult = await context.AuthenticateAsync(ArmAuthenticationDefaults.AuthenticationScheme);

            if (!authenticationResult.Succeeded)
            {
                context.Response.StatusCode = 401;
                KuduEventGenerator.Log().ApiEvent(
                    ServerConfiguration.GetApplicationName(),
                    "UnauthenticatedLinuxConsumptionEndpoint",
                    context.Request.GetEncodedPathAndQuery(),
                    context.Request.Method,
                    System.Environment.GetEnvironmentVariable("x-ms-request-id") ?? string.Empty,
                    context.Response.StatusCode,
                    (DateTime.UtcNow - requestTime).Milliseconds,
                    context.Request.GetUserAgent());
                return;
            }

            if (authorizationService != null)
            {
                AuthorizationResult endpointAuthorization = await authorizationService.AuthorizeAsync(authenticationResult.Principal, AuthorizationPolicy);

                if (!endpointAuthorization.Succeeded)
                {
                    context.Response.StatusCode = 401;
                    KuduEventGenerator.Log().ApiEvent(
                        ServerConfiguration.GetApplicationName(),
                        "UnauthorizedLinuxConsumptionEndpoint",
                        context.Request.GetEncodedPathAndQuery(),
                        context.Request.Method,
                        System.Environment.GetEnvironmentVariable("x-ms-request-id") ?? string.Empty,
                        context.Response.StatusCode,
                        (DateTime.UtcNow - requestTime).Milliseconds,
                        context.Request.GetUserAgent());
                    return;
                }
            }

            await _next.Invoke(context);
        }
        public async Task <IActionResult> Authorize([ModelBinder(typeof(OpenIddictMvcBinder))] OpenIdConnectRequest request)
        {
            // Retrieve the claims stored in the authentication cookie.
            // If they can't be extracted, redirect the user to the login page.
            var result = await HttpContext.AuthenticateAsync();

            if (result == null || !result.Succeeded || request.HasPrompt(OpenIddictConstants.Prompts.Login))
            {
                return(RedirectToLoginPage(request));
            }

            // If a max_age parameter was provided, ensure that the cookie is not too old.
            // If it's too old, automatically redirect the user agent to the login page.
            if (request.MaxAge != null && result.Properties.IssuedUtc != null &&
                DateTimeOffset.UtcNow - result.Properties.IssuedUtc > TimeSpan.FromSeconds(request.MaxAge.Value))
            {
                return(RedirectToLoginPage(request));
            }

            var application = await _applicationManager.FindByClientIdAsync(request.ClientId);

            if (application == null)
            {
                return(View("Error", new ErrorViewModel
                {
                    Error = OpenIddictConstants.Errors.InvalidClient,
                    ErrorDescription = T["The specified 'client_id' parameter is invalid."]
                }));
            }

            var authorizations = await _authorizationManager.FindAsync(
                subject : result.Principal.GetUserIdentifier(),
                client : await _applicationManager.GetIdAsync(application),
                status : OpenIddictConstants.Statuses.Valid,
                type : OpenIddictConstants.AuthorizationTypes.Permanent,
                scopes : ImmutableArray.CreateRange(request.GetScopes()));

            switch (await _applicationManager.GetConsentTypeAsync(application))
            {
            case OpenIddictConstants.ConsentTypes.External when authorizations.IsEmpty:
                return(RedirectToClient(new OpenIdConnectResponse
                {
                    Error = OpenIddictConstants.Errors.ConsentRequired,
                    ErrorDescription = T["The logged in user is not allowed to access this client application."]
                }));

            case OpenIddictConstants.ConsentTypes.Implicit:
            case OpenIddictConstants.ConsentTypes.External when authorizations.Any():
            case OpenIddictConstants.ConsentTypes.Explicit when authorizations.Any() &&
                !request.HasPrompt(OpenIddictConstants.Prompts.Consent):
                var authorization = authorizations.LastOrDefault();

                var ticket = await CreateUserTicketAsync(result.Principal, application, authorization, request);

                return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme));

            case OpenIddictConstants.ConsentTypes.Explicit when request.HasPrompt(OpenIddictConstants.Prompts.None):
                return(RedirectToClient(new OpenIdConnectResponse
                {
                    Error = OpenIddictConstants.Errors.ConsentRequired,
                    ErrorDescription = T["Interactive user consent is required."]
                }));

            default:
                return(View(new AuthorizeViewModel
                {
                    ApplicationName = await _applicationManager.GetDisplayNameAsync(application),
                    RequestId = request.RequestId,
                    Scope = request.Scope
                }));
            }
        }
Exemplo n.º 3
0
        //[HttpPost]
        //public IActionResult Authorize()
        //{
        //    string scheme = "OAuth";
        //    ////如果已经认证通过,
        //    if (User.Identity.IsAuthenticated)
        //    {
        //        return Redirect("UserInfo");
        //    }
        //    //触发授权,DefaultChallengeScheme配置的是OAuth
        //    return Challenge(scheme);
        //    //return await ProcessWindowsLoginAsync("/Account/Authorize");

        //    //return View();
        //}

        /// <summary>
        ///
        /// </summary>
        /// <param name="returnUrl"></param>
        /// <returns></returns>
        private async Task <IActionResult> ProcessWindowsLoginAsync(string returnUrl)
        {
            //string scheme = "OAuth";
            string scheme = "oidc";

            scheme = OpenIdConnectDefaults.DisplayName;
            // see if windows auth has already been requested and succeeded
            //WindowsPrincipal
            var userResult = await HttpContext.AuthenticateAsync(scheme);

            // DefaultAuthenticateScheme causes User to be set
            // var user = context.User;

            // This is what [Authorize] calls
            var user   = userResult.Principal;
            var props1 = userResult.Properties;

            //已经授权,登录并跳转
            if (User.Identity.IsAuthenticated)
            {
                var ck    = userResult.Properties.GetTokens();
                var token = userResult.Properties.GetTokenValue("access_token");

                return(View("UserInfo"));
            }


            //if (userResult?.Principal is ClaimsPrincipal wp)
            //{
            //    // we will issue the external cookie and then redirect the
            //    // user back to the external callback, in essence, treating windows
            //    // auth the same as any other external authentication mechanism
            //    var props = new AuthenticationProperties()
            //    {
            //        RedirectUri = Url.Action("Callback"),
            //        Items =
            //        {
            //            { "returnUrl", returnUrl },
            //            { "scheme", scheme },
            //        }
            //    };

            //    var id = new ClaimsIdentity(scheme);

            //    var result11 = HttpContext.AuthenticateAsync("idsrv").Result;

            //    id.AddClaim(new Claim(JwtClaimTypes.Subject, wp.Identity.Name));
            //    id.AddClaim(new Claim(JwtClaimTypes.Name, wp.Identity.Name));

            //    await HttpContext.SignInAsync("idsrv",
            //        new ClaimsPrincipal(id),
            //        props);
            //    //HttpContext.SignInAsync(wp.Identity.Name, wp.Identity.Name, props);
            //    return Redirect(props.RedirectUri);
            //}
            else
            {
                //触发授权,DefaultChallengeScheme配置的是OAuth
                return(Challenge(scheme));
                //await HttpContext.ChallengeAsync("OAuth");
            }
        }
        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);
            }

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

            if (user == null)
            {
                user = await CustomUserProvisionProcess(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();

            ProcessLoginCallback(result, additionalLocalClaims, localSignInProps);

            var user_username  = user.Username;
            var user_subjectId = user.SubjectId;

            // 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(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?.Client.ClientId));

            if (context != null)
            {
                if (context.IsNativeClient())
                {
                    // The client is 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.º 5
0
        public async Task <IActionResult> DefaultCallback()
        {
            // read external identity from the temporary cookie
            AuthenticateResult result =
                await HttpContext.AuthenticateAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme)
                .ConfigureAwait(false);

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

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

            // lookup our user and external provider info
            (IdentityUser user, string provider, string providerUserId, IEnumerable <Claim> claims) =
                await FindUserFromExternalProvider(null);

            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 identityUserService.AutoProvisionUser(provider, providerUserId, claims.ToList());
            }

            // 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.
            List <Claim>             additionalLocalClaims = new List <Claim>();
            AuthenticationProperties localSignInProps      = new AuthenticationProperties();

            ProcessLoginCallbackForOidc(null, additionalLocalClaims, localSignInProps);

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

            await HttpContext.SignInAsync(isuser, localSignInProps)
            .ConfigureAwait(false);

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

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

            // check if external login is in the context of an OIDC request
            AuthorizationRequest context = await interaction.GetAuthorizationContextAsync(returnUrl)
                                           .ConfigureAwait(false);

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

            if (context != null)
            {
                if (await clientStore.IsPkceClientAsync(context.ClientId)
                    .ConfigureAwait(false))
                {
                    // 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.º 6
0
        public async Task Invoke(HttpContext context)
        {
            context.Features.Set <IAuthenticationFeature>(new AuthenticationFeature
            {
                OriginalPath     = context.Request.Path,
                OriginalPathBase = context.Request.PathBase
            });

            // Give any IAuthenticationRequestHandler schemes a chance to handle the request
            var handlers = context.RequestServices.GetRequiredService <IAuthenticationHandlerProvider>();

            foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync())
            {
                // Determine if scheme is appropriate for the current context FIRST
                if (scheme is IDynamicAuthenticationScheme dynamicScheme)
                {
                    switch (dynamicScheme.SsoType)
                    {
                    case SsoType.OpenIdConnect:
                    default:
                        if (dynamicScheme.Options is OpenIdConnectOptions oidcOptions &&
                            !await oidcOptions.CouldHandleAsync(scheme.Name, context))
                        {
                            // It's OIDC and Dynamic, but not a good fit
                            continue;
                        }
                        break;

                    case SsoType.Saml2:
                        if (dynamicScheme.Options is Saml2Options samlOptions &&
                            !await samlOptions.CouldHandleAsync(scheme.Name, context))
                        {
                            // It's SAML and Dynamic, but not a good fit
                            continue;
                        }
                        break;
                    }
                }

                // This far it's not dynamic OR it is but "could" be handled
                if (await handlers.GetHandlerAsync(context, scheme.Name) is IAuthenticationRequestHandler handler &&
                    await handler.HandleRequestAsync())
                {
                    return;
                }
            }

            // Fallback to the default scheme from the provider
            var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync();

            if (defaultAuthenticate != null)
            {
                var result = await context.AuthenticateAsync(defaultAuthenticate.Name);

                if (result?.Principal != null)
                {
                    context.User = result.Principal;
                }
            }

            await _next(context);
        }
Exemplo n.º 7
0
        public async Task <IActionResult> Exchange()
        {
            var request = HttpContext.GetOpenIddictServerRequest() ??
                          throw new InvalidOperationException("The OpenID Connect request cannot be retrieved.");

            if (request.IsPasswordGrantType())
            {
                var user = await _userManager.FindByNameAsync(request.Username);

                if (user == null)
                {
                    return(Forbid(
                               authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
                               properties: new AuthenticationProperties(new Dictionary <string, string>
                    {
                        [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.InvalidGrant,
                        [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The username/password couple is invalid."
                    })));
                }

                // Validate the username/password parameters and ensure the account is not locked out.
                var result = await _signInManager.CheckPasswordSignInAsync(user, request.Password, lockoutOnFailure : true);

                if (!result.Succeeded)
                {
                    return(Forbid(
                               authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
                               properties: new AuthenticationProperties(new Dictionary <string, string>
                    {
                        [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.InvalidGrant,
                        [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The username/password couple is invalid."
                    })));
                }

                var principal = await _signInManager.CreateUserPrincipalAsync(user);

                // Note: in this sample, the granted scopes match the requested scope
                // but you may want to allow the user to uncheck specific scopes.
                // For that, simply restrict the list of scopes before calling SetScopes.
                principal.SetScopes(request.GetScopes());
                principal.SetResources(await _scopeManager.ListResourcesAsync(principal.GetScopes()).ToListAsync());

                foreach (var claim in principal.Claims)
                {
                    claim.SetDestinations(GetDestinations(claim, principal));
                }

                // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens.
                return(SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme));
            }

            else if (request.IsAuthorizationCodeGrantType() || request.IsDeviceCodeGrantType() || request.IsRefreshTokenGrantType())
            {
                // Retrieve the claims principal stored in the authorization code/device code/refresh token.
                var principal = (await HttpContext.AuthenticateAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)).Principal;

                // Retrieve the user profile corresponding to the authorization code/refresh token.
                // Note: if you want to automatically invalidate the authorization code/refresh token
                // when the user password/roles change, use the following line instead:
                // var user = _signInManager.ValidateSecurityStampAsync(info.Principal);
                var user = await _userManager.GetUserAsync(principal);

                if (user == null)
                {
                    return(Forbid(
                               authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
                               properties: new AuthenticationProperties(new Dictionary <string, string>
                    {
                        [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.InvalidGrant,
                        [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The token is no longer valid."
                    })));
                }

                // Ensure the user is still allowed to sign in.
                if (!await _signInManager.CanSignInAsync(user))
                {
                    return(Forbid(
                               authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
                               properties: new AuthenticationProperties(new Dictionary <string, string>
                    {
                        [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.InvalidGrant,
                        [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is no longer allowed to sign in."
                    })));
                }

                foreach (var claim in principal.Claims)
                {
                    claim.SetDestinations(GetDestinations(claim, principal));
                }

                // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens.
                return(SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme));
            }

            throw new InvalidOperationException("The specified grant type is not supported.");
        }
Exemplo n.º 8
0
        public async Task <IActionResult> Index()
        {
            var model = new DiagnosticsViewModel(await HttpContext.AuthenticateAsync());

            return(View(model));
        }
        public async Task <IActionResult> Exchange(OpenIdConnectRequest request)
        {
            Debug.Assert(request.IsTokenRequest(),
                         "The OpenIddict binder for ASP.NET Core MVC is not registered. " +
                         "Make sure services.AddOpenIddict().AddMvcBinders() is correctly called.");

            if (request.IsPasswordGrantType())
            {
                var user = await _userManager.FindByEmailAsync(request.Username);

                if (user == null)
                {
                    _logger.LogDebug("User {0} not found", request.Username);
                    return(BadRequest("Invalid username or password."));
                }

                // Validate the username/password parameters and ensure the account is not locked out.
                var result = await _signInManager.CheckPasswordSignInAsync(user, request.Password, lockoutOnFailure : true);

                if (!result.Succeeded)
                {
                    _logger.LogDebug("Sign-in Failed: {0}", result);
                    return(BadRequest("Invalid username or password"));
                }

                // Create a new authentication ticket.
                var ticket = await CreateTicketAsync(request, user);

                return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme));
            }
            else if (request.IsRefreshTokenGrantType())
            {
                var info = await HttpContext.AuthenticateAsync(OpenIddictServerDefaults.AuthenticationScheme);

                var user = await _userManager.GetUserAsync(info.Principal);

                if (user == null)
                {
                    return(BadRequest(new OpenIdConnectResponse
                    {
                        Error = OpenIdConnectConstants.Errors.InvalidGrant,
                        ErrorDescription = "The refresh token is no longer valid."
                    }));
                }

                if (!await _signInManager.CanSignInAsync(user))
                {
                    return(BadRequest(new OpenIdConnectResponse
                    {
                        Error = OpenIdConnectConstants.Errors.InvalidGrant,
                        ErrorDescription = "The user is no longer allowed to sign in."
                    }));
                }

                var ticket = await CreateTicketAsync(request, user, info.Properties);

                return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme));
            }

            return(BadRequest(new OpenIdConnectResponse
            {
                Error = OpenIdConnectConstants.Errors.UnsupportedGrantType,
                ErrorDescription = "The specified grant type is not supported."
            }));
        }
        public async Task <IActionResult> ExternalLoginCallback()
        {
            // read external identity from the temporary cookie
            var result = await HttpContext.AuthenticateAsync(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 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);

                if (user == null)
                {
                    return(RedirectToAction("LoginError", "Home", new { Error = string.Join(" ", _notifications.GetNotifications().Select(a => $"{a.Key}: {a.Value}")) }));
                }
            }

            // 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
            // I don't have pride of this.
            var s = new UserIdentity()
            {
                Id                   = user.Id,
                Name                 = user.Name,
                SecurityStamp        = user.SecurityStamp,
                AccessFailedCount    = user.AccessFailedCount,
                Bio                  = user.Bio,
                Company              = user.Company,
                Email                = user.Email,
                EmailConfirmed       = user.EmailConfirmed,
                JobTitle             = user.JobTitle,
                LockoutEnabled       = user.LockoutEnabled,
                LockoutEnd           = user.LockoutEnd,
                PhoneNumber          = user.PhoneNumber,
                PhoneNumberConfirmed = user.PhoneNumberConfirmed,
                Picture              = user.Picture,
                TwoFactorEnabled     = user.TwoFactorEnabled,
                Url                  = user.Url,
                UserName             = user.UserName,
            };
            var principal = await _signInManager.CreateUserPrincipalAsync(s);

            additionalLocalClaims.AddRange(principal.Claims);
            var name = principal.FindFirst(JwtClaimTypes.Name)?.Value ?? user.Id.ToString();

            await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.Id.ToString(), name));

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

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

            // validate return URL and redirect back to authorization endpoint or a local page
            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.º 11
0
        public async Task <IActionResult> ExternalLoginCallback()
        {
            // read external identity from the temporary cookie
            var result = await HttpContext.AuthenticateAsync(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 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>();

            additionalLocalClaims.AddRange(claims);

            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 _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.Id, name));

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

            await HttpContext.SignInAsync(isuser, localSignInProps);

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

            // validate return URL and redirect back to authorization endpoint or a local page
            var returnUrl = result.Properties.Items["returnUrl"];

            if (_interaction.IsValidReturnUrl(returnUrl) || Url.IsLocalUrl(returnUrl))
            {
                return(Redirect(returnUrl));
            }

            return(Redirect("~/"));
        }
Exemplo n.º 12
0
        public async Task <IActionResult> Authorize(OpenIdConnectRequest request)
        {
            var info = await _signInManager.GetExternalLoginInfoAsync();

            var auth = await HttpContext.AuthenticateAsync(IdentityConstants.ExternalScheme);

            var principal = auth.Principal;

            // var providerKey = auth.Principal.Claims.FirstOrDefault();
            if (info == null)
            {
                return(Render(ExternalLoginStatus.Invalid));
            }

            // Sign in the user with this external login provider if the user already has a login.
            var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent : false);

            if (result.Succeeded)
            {
                // Retrieve the profile of the logged in user.
                var user = await _userManager.FindByLoginAsync(info.LoginProvider, info.ProviderKey);

                // var user = await _userManager.GetUserAsync(principal);
                if (user == null)
                {
                    return(Render(ExternalLoginStatus.Error));
                }

                _logger.LogInformation(5, "User logged in with {Name} provider.", info.LoginProvider);
                var ticket = await CreateTicketAsync(request, user);

                // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens.
                return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme));

                // return Render(ExternalLoginStatus.Ok); // Everything Ok, login user
            }
            else
            {
                // External account doesn't have a local account so ask to create one
                return(Render(ExternalLoginStatus.CreateAccount));
            }


            // if (result.RequiresTwoFactor)
            // {
            //     return Render(ExternalLoginStatus.TwoFactor);
            // }
            // if (result.IsLockedOut)
            // {
            //     return Render(ExternalLoginStatus.Lockout);
            // }
            // else
            // {
            //     // If the user does not have an account, then ask the user to create an account.
            //     // ViewData["ReturnUrl"] = returnUrl;
            //     // ViewData["LoginProvider"] = info.LoginProvider;
            //     // var email = info.Principal.FindFirstValue(ClaimTypes.Email);
            //     // return RedirectToAction("Index", "Home", new ExternalLoginCreateAccountViewModel { Email = email });
            //     return Render(ExternalLoginStatus.CreateAccount);
            // }

            // if (!User.Identity.IsAuthenticated)
            // {
            //     // If the client application request promptless authentication,
            //     // return an error indicating that the user is not logged in.
            //     if (request.HasPrompt(OpenIdConnectConstants.Prompts.None))
            //     {
            //         var properties = new AuthenticationProperties(new Dictionary<string, string>
            //         {
            //             [OpenIdConnectConstants.Properties.Error] = OpenIdConnectConstants.Errors.LoginRequired,
            //             [OpenIdConnectConstants.Properties.ErrorDescription] = "The user is not logged in."
            //         });

            //         // Ask OpenIddict to return a login_required error to the client application.
            //         return Forbid(properties, OpenIdConnectServerDefaults.AuthenticationScheme);
            //     }

            //     return Challenge();
            // }
        }
Exemplo n.º 13
0
        public async Task <IActionResult> ExternalLoginCallback()
        {
            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);
            var provider = result.Properties.Items["scheme"];
            var userId   = userIdClaim.Value;

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

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

                await _userManager.AddLoginAsync(user, new UserLoginInfo(provider, userId, provider));
            }

            var additionalClaims = new List <Claim>();

            var sid = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.SessionId);

            if (sid != null)
            {
                additionalClaims.Add(new Claim(JwtClaimTypes.SessionId, sid.Value));
            }

            AuthenticationProperties props = null;
            var id_token = result.Properties.GetTokenValue("id_token");

            if (id_token != null)
            {
                props = new AuthenticationProperties();
                props.StoreTokens(new[] { new AuthenticationToken {
                                              Name = "id_token", Value = id_token
                                          } });
            }

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

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

            await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);

            var returnUrl = result.Properties.Items["returnUrl"];

            if (_interaction.IsValidReturnUrl(returnUrl) || Url.IsLocalUrl(returnUrl))
            {
                return(Redirect(returnUrl));
            }

            return(Redirect("~/"));
        }
        public async Task Invoke(HttpContext context)
        {
            var startDt = DateTime.Now;
            var sw      = new Stopwatch();

            sw.Start();
            using (var reqBody = new MemoryStream())
            {
                var originalReqBody = context.Request.Body;
                if (_options.Value.LogRequestBody(context.Request))
                {
                    await originalReqBody.CopyToAsync(reqBody);

                    reqBody.Seek(0, SeekOrigin.Begin);
                    context.Request.Body = reqBody;
                }

                using (var resBody = new MemoryStream())
                {
                    var originalResBody = context.Response.Body;
                    context.Response.Body = resBody;

                    await _next(context);

                    // logging
                    string reqString;
                    if (_options.Value.LogRequestBody(context.Request))
                    {
                        reqBody.Seek(0, SeekOrigin.Begin);

                        using (var reqSteamReader = new StreamReader(reqBody))
                        {
                            reqString = await reqSteamReader.ReadToEndAsync();

                            context.Request.Body = originalReqBody;
                        }
                    }
                    else
                    {
                        reqString = $"{context.Request.ContentLength} bytes are ignored";
                    }

                    string resString;
                    resBody.Seek(0, SeekOrigin.Begin);
                    using (var resStreamReader = new StreamReader(resBody))
                    {
                        if (_options.Value.LogResponseBody(context.Response))
                        {
                            resString = await resStreamReader.ReadToEndAsync();
                        }
                        else
                        {
                            resString = $"{resBody.Length} bytes are ignored";
                        }

                        resBody.Seek(0, SeekOrigin.Begin);
                        await resBody.CopyToAsync(originalResBody);

                        context.Response.Body = originalResBody;
                    }

                    var authentication = await context.AuthenticateAsync();

                    // may be null
                    var principal       = authentication.Principal;
                    var isAuthenticated = principal?.Identity.IsAuthenticated == true;
                    sw.Stop();
                    var lines = new List <string>
                    {
                        BuildDelimiter("request"),
                        $"received at: {startDt:yyyy-MM-dd HH:mm:ss.fff}",
                        $"elapsed: {sw.ElapsedMilliseconds}ms",
                        $"url: {context.Request.GetDisplayUrl()}",
                        $"remote address: {context.Connection.RemoteIpAddress}:{context.Connection.RemotePort}",
                        $"method: {context.Request.Method}",
                        $"headers: {(!context.Request.Headers.Any() ? null : $"{Environment.NewLine}{string.Join(Environment.NewLine, context.Request.Headers.Select(t => $"\t{t.Key}: {t.Value}"))}")}",
                        $"body: {reqString}",
                        BuildDelimiter("session"),
                        $"authenticated: {isAuthenticated}",
                        $"name: {principal?.Identity.Name}",
                        $"claims: {(principal != null ? $"{{{string.Join(", ", principal.Claims.Select(t => $"{t.Type}: {t.Value}"))}}}" : null)}",
                        BuildDelimiter("response"),
                        $"status: {context.Response.StatusCode}",
                        $"headers: {(!context.Response.Headers.Any() ? null : $"{Environment.NewLine}{string.Join(Environment.NewLine, context.Response.Headers.Select(t => $"\t{t.Key}: {t.Value}"))}")}",
                        $"body: {resString}"
                    };
                    _logger.LogInformation(_eventId, $"{string.Join(Environment.NewLine, lines)}");
                }
            }
Exemplo n.º 15
0
    public async Task <IActionResult> OnGet()
    {
        // read external identity from the temporary cookie
        var result = await HttpContext.AuthenticateAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);

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

        var externalUser = result.Principal;

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

        // lookup our user and external provider info
        // 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");

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

        // find external user
        var user = await _userManager.FindByLoginAsync(provider, providerUserId);

        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, externalUser.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();

        CaptureExternalLoginContext(result, additionalLocalClaims, localSignInProps);

        // issue authentication cookie for user
        await _signInManager.SignInWithClaimsAsync(user, localSignInProps, additionalLocalClaims);

        // 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, user.UserName, true, context?.Client.ClientId));

        if (context != null)
        {
            if (context.IsNativeClient())
            {
                // The client is native, so this change in how to
                // return the response is for better UX for the end user.
                return(this.LoadingPage(returnUrl));
            }
        }

        return(Redirect(returnUrl));
    }
        public async Task <IActionResult> Callback()
        {
            // OK - This runs through the authentication method in Startup.cs
            var result = await HttpContext.AuthenticateAsync(IdentityConstants.ExternalScheme);

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

            // Uncomment to see a log of the Claims
            //ClaimsPrincipal principalResult = result.Principal as ClaimsPrincipal;
            //if (null != principalResult)
            //{
            //    foreach (Claim claim in principalResult.Claims)
            //    {
            //        Console.WriteLine("CLAIM TYPE: " + claim.Type + "; CLAIM VALUE: " + claim.Value);
            //    }
            //}

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

            // OK - Auto-register "New" External-Provider Authenticated "User"
            if (user == null)
            {
                // User registration for external log in
                user = await AutoRegisterExternalUser(provider, providerUserId, claims);
            }
            else
            // Check if picture or username has changed
            {
                user = await UpdateExternalUser(user, claims);
            }

            // OK - Used to store data needed for signout from those protocols.
            var additionalLocalClaims = new List <Claim>();

            // OK - Add state to cookie I create
            var localSignInProps = new AuthenticationProperties();

            var principal = await _signInManager.CreateUserPrincipalAsync(user);

            additionalLocalClaims.AddRange(principal.Claims);
            var name = principal.FindFirst(JwtClaimTypes.Name)?.Value ?? user.Id;

            await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.Id, name));

            // OK - This is our Cookie
            await HttpContext.SignInAsync(user.Id, name, provider, localSignInProps, additionalLocalClaims.ToArray());

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

            // OK - validate return URL and redirect back to authorization endpoint or a local page
            var returnUrl = result.Properties.Items["returnUrl"];

            if (_interaction.IsValidReturnUrl(returnUrl) || Url.IsLocalUrl(returnUrl))
            {
                return(Redirect(returnUrl));
            }

            return(Redirect("~/"));
        }
Exemplo n.º 17
0
        public async Task <IActionResult> Exchange(OpenIdConnectRequest request)
        {
            if (request.IsPasswordGrantType())
            {
                var user = await _userManager.FindByEmailAsync(request.Username) ?? await _userManager.FindByNameAsync(request.Username);

                if (user == null)
                {
                    return(BadRequest(new OpenIdConnectResponse
                    {
                        Error = OpenIdConnectConstants.Errors.InvalidGrant,
                        ErrorDescription = "Please check that your email and password is correct"
                    }));
                }

                // Ensure the user is enabled.
                if (!user.IsEnabled)
                {
                    return(BadRequest(new OpenIdConnectResponse
                    {
                        Error = OpenIdConnectConstants.Errors.InvalidGrant,
                        ErrorDescription = "The specified user account is disabled"
                    }));
                }


                // Validate the username/password parameters and ensure the account is not locked out.
                var result = await _signInManager.CheckPasswordSignInAsync(user, request.Password, true);

                // Ensure the user is not already locked out.
                if (result.IsLockedOut)
                {
                    return(BadRequest(new OpenIdConnectResponse
                    {
                        Error = OpenIdConnectConstants.Errors.InvalidGrant,
                        ErrorDescription = "The specified user account has been suspended"
                    }));
                }

                // Reject the token request if two-factor authentication has been enabled by the user.
                if (result.RequiresTwoFactor)
                {
                    return(BadRequest(new OpenIdConnectResponse
                    {
                        Error = OpenIdConnectConstants.Errors.InvalidGrant,
                        ErrorDescription = "Invalid login procedure"
                    }));
                }

                // Ensure the user is allowed to sign in.
                if (result.IsNotAllowed)
                {
                    return(BadRequest(new OpenIdConnectResponse
                    {
                        Error = OpenIdConnectConstants.Errors.InvalidGrant,
                        ErrorDescription = "The specified user is not allowed to sign in"
                    }));
                }

                if (!result.Succeeded)
                {
                    return(BadRequest(new OpenIdConnectResponse
                    {
                        Error = OpenIdConnectConstants.Errors.InvalidGrant,
                        ErrorDescription = "Please check that your email and password is correct"
                    }));
                }



                // Create a new authentication ticket.
                var ticket = await CreateTicketAsync(request, user);

                return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme));
            }
            else if (request.IsRefreshTokenGrantType())
            {
                // Retrieve the claims principal stored in the refresh token.
                var info = await HttpContext.AuthenticateAsync(OpenIdConnectServerDefaults.AuthenticationScheme);

                // Retrieve the user profile corresponding to the refresh token.
                // Note: if you want to automatically invalidate the refresh token
                // when the user password/roles change, use the following line instead:
                // var user = _signInManager.ValidateSecurityStampAsync(info.Principal);
                var user = await _userManager.GetUserAsync(info.Principal);

                if (user == null)
                {
                    return(BadRequest(new OpenIdConnectResponse
                    {
                        Error = OpenIdConnectConstants.Errors.InvalidGrant,
                        ErrorDescription = "The refresh token is no longer valid"
                    }));
                }

                // Ensure the user is still allowed to sign in.
                if (!await _signInManager.CanSignInAsync(user))
                {
                    return(BadRequest(new OpenIdConnectResponse
                    {
                        Error = OpenIdConnectConstants.Errors.InvalidGrant,
                        ErrorDescription = "The user is no longer allowed to sign in"
                    }));
                }

                // Create a new authentication ticket, but reuse the properties stored
                // in the refresh token, including the scopes originally granted.
                var ticket = await CreateTicketAsync(request, user);

                return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme));
            }
            return(BadRequest(new OpenIdConnectResponse
            {
                Error = OpenIdConnectConstants.Errors.UnsupportedGrantType,
                ErrorDescription = "The specified grant type is not supported"
            }));
        }
Exemplo n.º 18
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) = 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 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.SubjectId, user.Username));


            // 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);

            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.º 19
0
        public async Task <IActionResult> ExternalLoginCallback()
        {
            // 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");
            }

            // retrieve claims of the external user
            var externalUser = result.Principal;
            var claims       = externalUser.Claims.ToList();

            // 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 = 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");
            }

            // remove the user id claim from the claims collection and move to the userId property
            // also set the name of the external authentication provider
            claims.Remove(userIdClaim);
            var provider = result.Properties.Items["scheme"];
            var userId   = userIdClaim.Value;

            // this is where custom logic would most likely be needed to match your users from the
            // external provider's authentication result, and provision the user as you see fit.
            //
            // check if the external user is already provisioned
            var user = await _userManager.FindByLoginAsync(provider, userId);

            if (user == null)
            {
                // this sample simply auto-provisions new external user
                // another common approach is to start a registrations workflow first
                // a common way to build a registration page is to use the claims from the
                // external provider to pre-populate a registration screen, and then store those
                // as claims (or custom properties) in the ASP.NET Identity database.
                user = new JarvisUser
                {
                    UserName = Guid.NewGuid().ToString(),
                };
                var identityResult = await _userManager.CreateAsync(user);

                if (!identityResult.Succeeded)
                {
                    throw new Exception(identityResult.Errors.First().Description);
                }

                identityResult = await _userManager.AddLoginAsync(user, new UserLoginInfo(provider, userId, provider));

                if (!identityResult.Succeeded)
                {
                    throw new Exception(identityResult.Errors.First().Description);
                }
            }

            var additionalClaims = new List <Claim>();

            // if the external system sent a session id claim, copy it over
            // so we can use it for single sign-out
            var sid = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.SessionId);

            if (sid != null)
            {
                additionalClaims.Add(new Claim(JwtClaimTypes.SessionId, sid.Value));
            }

            // if the external provider issued an id_token, we'll keep it for signout
            AuthenticationProperties props = null;
            var id_token = result.Properties.GetTokenValue("id_token");

            if (id_token != null)
            {
                props = new AuthenticationProperties();
                props.StoreTokens(new[] { new AuthenticationToken {
                                              Name = "id_token", Value = id_token
                                          } });
            }

            var name = externalUser.FindFirst(JwtClaimTypes.Name)?.Value;

            if (name == null)
            {
                name = externalUser.FindFirst(ClaimTypes.Name)?.Value;
            }
            if (name == null)
            {
                name = user.Id.ToString();
            }

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

            await HttpContext.SignInAsync(user.Id.ToString(), name, provider, props, additionalClaims.ToArray());

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

            // validate return URL and redirect back to authorization endpoint or a local page
            var returnUrl = result.Properties.Items["returnUrl"];

            if (_interaction.IsValidReturnUrl(returnUrl) || Url.IsLocalUrl(returnUrl))
            {
                return(Redirect(returnUrl));
            }

            return(Redirect("~/"));
        }
Exemplo n.º 20
0
        public async Task <IActionResult> ExternalLoginCallback()
        {
            var result = await HttpContext.AuthenticateAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);

            if (result?.Succeeded != true)
            {
                throw new Exception("外部授权错误");
            }

            // 获取外部登录的Claims信息
            var externalUser = result.Principal;
            var claims       = externalUser.Claims.ToList();

            //尝试确定外部用户的唯一ID(由提供者发出)
            //最常见的索赔,索赔类型分,nameidentifier
            //取决于外部提供者,可能使用其他一些索赔类型
            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("未知用户");
            }

            //从集合中移除用户ID索赔索赔和移动用户标识属性还设置外部身份验证提供程序的名称。
            claims.Remove(userIdClaim);
            var provider = result.Properties.Items["scheme"];
            var userId   = userIdClaim.Value;

            // 这是最有可能需要自定义逻辑来匹配您的用户的外部提供者的身份验证结果,并为用户提供您所认为合适的结果。
            //  检查外部用户已经设置
            var user = "";// _users.FindByExternalProvider(provider, userId);

            if (user == null)
            {
                //此示例只是自动提供新的外部用户,另一种常见的方法是首先启动注册工作流
                //user = _users.AutoProvisionUser(provider, userId, claims);
            }

            var additionalClaims = new List <Claim>();

            // 如果外部系统发送了会话ID请求,请复制它。所以我们可以用它进行单点登录
            var sid = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.SessionId);

            if (sid != null)
            {
                additionalClaims.Add(new Claim(JwtClaimTypes.SessionId, sid.Value));
            }

            //如果外部供应商发出id_token,我们会把它signout
            AuthenticationProperties props = null;
            var id_token = result.Properties.GetTokenValue("id_token");

            if (id_token != null)
            {
                props = new AuthenticationProperties();
                props.StoreTokens(new[] { new AuthenticationToken {
                                              Name = "id_token", Value = id_token
                                          } });
            }

            // 为用户颁发身份验证cookie
            //   await _events.RaiseAsync(new UserLoginSuccessEvent(provider, userId, user.SubjectId, user.Username));
            // await HttpContext.SignInAsync(user.SubjectId, user.Username, provider, props, additionalClaims.ToArray());

            // 删除外部验证期间使用的临时cookie
            await HttpContext.SignOutAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);

            // 验证返回URL并重定向回授权端点或本地页面
            var returnUrl = result.Properties.Items["returnUrl"];

            if (_identityServerInteractionService.IsValidReturnUrl(returnUrl) || Url.IsLocalUrl(returnUrl))
            {
                return(Redirect(returnUrl));
            }

            return(Redirect("~/"));
        }
Exemplo n.º 21
0
        public async Task <IActionResult> Authorize()
        {
            var request = HttpContext.GetOpenIddictServerRequest() ??
                          throw new InvalidOperationException("The OpenID Connect request cannot be retrieved.");

            // Retrieve the user principal stored in the authentication cookie.
            // If it can't be extracted, redirect the user to the login page.
            var result = await HttpContext.AuthenticateAsync(IdentityConstants.ApplicationScheme);

            if (result == null || !result.Succeeded)
            {
                // If the client application requested promptless authentication,
                // return an error indicating that the user is not logged in.
                if (request.HasPrompt(Prompts.None))
                {
                    return(Forbid(
                               authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
                               properties: new AuthenticationProperties(new Dictionary <string, string>
                    {
                        [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.LoginRequired,
                        [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is not logged in."
                    })));
                }

                return(Challenge(
                           authenticationSchemes: IdentityConstants.ApplicationScheme,
                           properties: new AuthenticationProperties
                {
                    RedirectUri = Request.PathBase + Request.Path + QueryString.Create(
                        Request.HasFormContentType ? Request.Form.ToList() : Request.Query.ToList())
                }));
            }

            // If prompt=login was specified by the client application,
            // immediately return the user agent to the login page.
            if (request.HasPrompt(Prompts.Login))
            {
                // To avoid endless login -> authorization redirects, the prompt=login flag
                // is removed from the authorization request payload before redirecting the user.
                var prompt = string.Join(" ", request.GetPrompts().Remove(Prompts.Login));

                var parameters = Request.HasFormContentType ?
                                 Request.Form.Where(parameter => parameter.Key != Parameters.Prompt).ToList() :
                                 Request.Query.Where(parameter => parameter.Key != Parameters.Prompt).ToList();

                parameters.Add(KeyValuePair.Create(Parameters.Prompt, new StringValues(prompt)));

                return(Challenge(
                           authenticationSchemes: IdentityConstants.ApplicationScheme,
                           properties: new AuthenticationProperties
                {
                    RedirectUri = Request.PathBase + Request.Path + QueryString.Create(parameters)
                }));
            }

            // If a max_age parameter was provided, ensure that the cookie is not too old.
            // If it's too old, automatically redirect the user agent to the login page.
            if (request.MaxAge != null && result.Properties?.IssuedUtc != null &&
                DateTimeOffset.UtcNow - result.Properties.IssuedUtc > TimeSpan.FromSeconds(request.MaxAge.Value))
            {
                if (request.HasPrompt(Prompts.None))
                {
                    return(Forbid(
                               authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
                               properties: new AuthenticationProperties(new Dictionary <string, string>
                    {
                        [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.LoginRequired,
                        [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is not logged in."
                    })));
                }

                return(Challenge(
                           authenticationSchemes: IdentityConstants.ApplicationScheme,
                           properties: new AuthenticationProperties
                {
                    RedirectUri = Request.PathBase + Request.Path + QueryString.Create(
                        Request.HasFormContentType ? Request.Form.ToList() : Request.Query.ToList())
                }));
            }

            // Retrieve the profile of the logged in user.
            var user = await _userManager.GetUserAsync(result.Principal) ??
                       throw new InvalidOperationException("The user details cannot be retrieved.");

            // Retrieve the application details from the database.
            var application = await _applicationManager.FindByClientIdAsync(request.ClientId) ??
                              throw new InvalidOperationException("Details concerning the calling client application cannot be found.");

            // Retrieve the permanent authorizations associated with the user and the calling client application.
            var authorizations = await _authorizationManager.FindAsync(
                subject : await _userManager.GetUserIdAsync(user),
                client : await _applicationManager.GetIdAsync(application),
                status : Statuses.Valid,
                type : AuthorizationTypes.Permanent,
                scopes : request.GetScopes()).ToListAsync();

            switch (await _applicationManager.GetConsentTypeAsync(application))
            {
            // If the consent is external (e.g when authorizations are granted by a sysadmin),
            // immediately return an error if no authorization can be found in the database.
            case ConsentTypes.External when !authorizations.Any():
                return(Forbid(
                           authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
                           properties: new AuthenticationProperties(new Dictionary <string, string>
                {
                    [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.ConsentRequired,
                    [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
                        "The logged in user is not allowed to access this client application."
                })));

            // If the consent is implicit or if an authorization was found,
            // return an authorization response without displaying the consent form.
            case ConsentTypes.Implicit:
            case ConsentTypes.External when authorizations.Any():
            case ConsentTypes.Explicit when authorizations.Any() && !request.HasPrompt(Prompts.Consent):
                var principal = await _signInManager.CreateUserPrincipalAsync(user);

                // Note: in this sample, the granted scopes match the requested scope
                // but you may want to allow the user to uncheck specific scopes.
                // For that, simply restrict the list of scopes before calling SetScopes.
                principal.SetScopes(request.GetScopes());
                principal.SetResources(await _scopeManager.ListResourcesAsync(principal.GetScopes()).ToListAsync());

                // Automatically create a permanent authorization to avoid requiring explicit consent
                // for future authorization or token requests containing the same scopes.
                var authorization = authorizations.LastOrDefault();
                if (authorization == null)
                {
                    authorization = await _authorizationManager.CreateAsync(
                        principal : principal,
                        subject : await _userManager.GetUserIdAsync(user),
                        client : await _applicationManager.GetIdAsync(application),
                        type : AuthorizationTypes.Permanent,
                        scopes : principal.GetScopes());
                }

                principal.SetInternalAuthorizationId(await _authorizationManager.GetIdAsync(authorization));

                foreach (var claim in principal.Claims)
                {
                    claim.SetDestinations(GetDestinations(claim, principal));
                }

                return(SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme));

            // At this point, no authorization was found in the database and an error must be returned
            // if the client application specified prompt=none in the authorization request.
            case ConsentTypes.Explicit   when request.HasPrompt(Prompts.None):
            case ConsentTypes.Systematic when request.HasPrompt(Prompts.None):
                return(Forbid(
                           authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
                           properties: new AuthenticationProperties(new Dictionary <string, string>
                {
                    [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.ConsentRequired,
                    [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
                        "Interactive user consent is required."
                })));

            // In every other case, render the consent form.
            default:
                return(View(new AuthorizeViewModel
                {
                    ApplicationName = await _applicationManager.GetDisplayNameAsync(application),
                    Scope = request.Scope
                }));
            }
        }
Exemplo n.º 22
0
    public async Task Invoke(HttpContext context)
    {
        if (!context.WebSockets.IsWebSocketRequest)
        {
            context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
            return;
        }

        var auth = await context.AuthenticateAsync();

        if (!auth.Succeeded)
        {
            context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
            return;
        }

        var subscription = default(StreamSubscriptionHandle <WebSocketMessage>);
        var userId       = new Guid(auth.Ticket.Principal.Claims.Single(e => e.Type == ClaimTypes.NameIdentifier).Value);

        try
        {
            var webSocket = await context.WebSockets.AcceptWebSocketAsync();

            _logger.LogInformation("[Websocket] opened connection for UserId: {userId}", userId);

            subscription = await
                           _clusterClient
                           .GetStreamProvider(Constants.InMemoryStream)
                           .GetStream <WebSocketMessage>(userId, Constants.WebSocketNamespace)
                           .SubscribeAsync(async(evt, st) =>
            {
                var bytes     = Encoding.UTF8.GetBytes(System.Text.Json.JsonSerializer.Serialize(evt));
                var msgBuffer = new ArraySegment <byte>(bytes, 0, bytes.Length);
                await webSocket.SendAsync(msgBuffer, WebSocketMessageType.Text, true, CancellationToken.None);
            });

            var buffer = new byte[1024 * 4];

            while (webSocket.CloseStatus.HasValue == false)
            {
                await webSocket.ReceiveAsync(new ArraySegment <byte>(buffer), CancellationToken.None);
            }

            await webSocket.CloseAsync(
                webSocket.CloseStatus.Value,
                webSocket.CloseStatusDescription, CancellationToken.None);

            _logger.LogInformation("[Websocket] closed connection for TraceId: {traceId}", userId);
        }
        catch (Exception e)
        {
            _logger.LogError("[Websocket] disconnect error -> {exception}", e);
        }
        finally
        {
            if (subscription != null)
            {
                await subscription.UnsubscribeAsync();
            }
        }
    }
Exemplo n.º 23
0
        public async Task RefreshUserClaimsAsync(HttpContext httpContext)
        {
            if (!httpContext.User.Identity.IsAuthenticated)
            {
                return;
            }

            var authenticateResult = await httpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);

            if (authenticateResult == null || !authenticateResult.Succeeded)
            {
                throw new AuthenticationException("Can not re-authenticate user");
            }

            var properties = authenticateResult.Properties;

            var authenticationService = (AuthenticationService)httpContext.RequestServices.GetRequiredService <IAuthenticationService>();
            var openIdConnectHandler  = (OpenIdConnectHandler)await authenticationService.Handlers.GetHandlerAsync(
                httpContext,
                OpenIdConnectDefaults.AuthenticationScheme
                );

            var configurationAsync = await openIdConnectHandler.Options.ConfigurationManager.GetConfigurationAsync(CancellationToken.None);

            var userInfoEndpoint = configurationAsync.UserInfoEndpoint;

            var accessToken = properties.Items[".Token.access_token"];

            if (!string.IsNullOrEmpty(accessToken))
            {
                var responseMessage = await openIdConnectHandler.Options.Backchannel.SendAsync(
                    new HttpRequestMessage(HttpMethod.Get, userInfoEndpoint)
                {
                    Headers =
                    {
                        Authorization = new AuthenticationHeaderValue("Bearer", accessToken)
                    }
                }
                    );

                responseMessage.EnsureSuccessStatusCode();

                var userInfoResponse = await responseMessage.Content.ReadAsStringAsync();

                var contentType = responseMessage.Content.Headers.ContentType;
                var jUser       = ParseResponse(userInfoResponse, contentType);

                var primaryIdentity = authenticateResult.Principal.Identity;
                var identity        = authenticateResult.Principal.Identities.FirstOrDefault(x =>
                                                                                             x.Name == primaryIdentity.Name && x.AuthenticationType == primaryIdentity.AuthenticationType);

                if (identity == null)
                {
                    throw new AuthenticationException("Can not refresh primary identity");
                }

                foreach (var claim in identity.Claims.ToList())
                {
                    switch (claim.Type)
                    {
                    case "sid":
                    case ClaimTypes.NameIdentifier:
                    case "http://schemas.microsoft.com/identity/claims/identityprovider":
                    case "http://schemas.microsoft.com/claims/authnmethodsreferences":
                        continue;
                    }

                    identity.RemoveClaim(claim);
                }

                foreach (var claimAction in openIdConnectHandler.Options.ClaimActions)
                {
                    claimAction.Run(jUser, identity, openIdConnectHandler.Scheme.Name);
                }
            }

            await httpContext.SignInAsync(
                CookieAuthenticationDefaults.AuthenticationScheme,
                authenticateResult.Principal,
                authenticateResult.Properties
                );
        }
Exemplo n.º 24
0
 public async Task OnGetAsync()
 {
     Input = new DiagnosticsViewModel(await HttpContext.AuthenticateAsync());
 }
        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");
            }

            var externalClaims = result.Principal.Claims.Select(c => $"{c.Type}: {c.Value}");

            // 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 UserProvisioner.ProvisionUserAsync(provider, providerUserId, claims.ToList(), CancellationToken.None);
            }

            // 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 sign-out from those protocols
            var additionalLocalClaims = new List <Claim>();

            var localSignInProps = new AuthenticationProperties();

            ProcessLoginCallback(result, additionalLocalClaims, localSignInProps);

            // issue authentication cookie for user
            var identityServerUser = new IdentityServerUser(user.Id)
            {
                DisplayName      = user.UserName,
                IdentityProvider = provider,
                AdditionalClaims = additionalLocalClaims
            };

            await SignInManager.SignInAsync(user, localSignInProps.IsPersistent);

            // 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, user.UserName, true, context?.Client.ClientId));

            if (context != null)
            {
                if (context.IsNativeClient())
                {
                    // The client is 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));
        }
        public async Task <IActionResult> ExternalLoginCallback()
        {
            IdentityUser        user;
            string              provider, providerUserId;
            IEnumerable <Claim> claims;
            // read external identity from the temporary cookie
            var result = await HttpContext.AuthenticateAsync(IdentityConstants.ExternalScheme);

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

            // lookup our user and external provider info

            if (result.Properties.Items["scheme"] == "Windows")
            {
                (user, provider, providerUserId, claims) = await FindUserFromWindows(result);
            }
            else
            {
                (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);
            this.User.Claims.Append(new Claim("SessionId", Guid.NewGuid().ToString()));

            //foreach(var claim in claims)
            //{
            //    additionalLocalClaims.AddRange(claims);
            //}

            additionalLocalClaims.AddRange(this.User.Claims);
            var name = this.User.Claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Name)?.Value ?? user.Id;
            await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.Id, name));

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

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

            // validate return URL and redirect back to authorization endpoint or a local page
            var returnUrl = result.Properties.Items["returnUrl"];

            if (_interaction.IsValidReturnUrl(returnUrl) || Url.IsLocalUrl(returnUrl))
            {
                return(Redirect(returnUrl));
            }

            return(Redirect("~/"));
        }
        private async Task <string> RenewTokensAsync()
        {
            var client = new HttpClient();
            var disco  = await client.GetDiscoveryDocumentAsync("http://localhost:7200");

            if (disco.IsError)
            {
                throw new Exception(disco.Error);
            }

            var refreshToken = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.RefreshToken);

            var tokenResponse = await client.RequestRefreshTokenAsync(new RefreshTokenRequest
            {
                Address      = disco.TokenEndpoint,
                ClientId     = "sword mvc",
                ClientSecret = "sword",
                Scope        = "swordApi openid profile email phone address",
                GrantType    = OpenIdConnectGrantTypes.RefreshToken,
                RefreshToken = refreshToken
            });

            if (tokenResponse.IsError)
            {
                throw new Exception(tokenResponse.Error);
            }
            var expiresAt = DateTime.UtcNow + TimeSpan.FromSeconds(tokenResponse.ExpiresIn);
            var tokens    = new[]
            {
                new AuthenticationToken
                {
                    Name  = OpenIdConnectParameterNames.IdToken,
                    Value = tokenResponse.IdentityToken
                },
                new AuthenticationToken
                {
                    Name  = OpenIdConnectParameterNames.AccessToken,
                    Value = tokenResponse.AccessToken
                },
                new AuthenticationToken
                {
                    Name  = OpenIdConnectParameterNames.RefreshToken,
                    Value = tokenResponse.RefreshToken
                },
                new AuthenticationToken
                {
                    Name  = "expires_at",
                    Value = expiresAt.ToString("o", CultureInfo.InvariantCulture)
                }
            };

            // 获取身份认证的结果,包含当前的pricipal和properties
            var currentAuthenticateResult = await HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);

            // 把新的tokens存起来
            currentAuthenticateResult.Properties.StoreTokens(tokens);
            // 登录
            await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, currentAuthenticateResult.Principal, currentAuthenticateResult.Properties);

            return(tokenResponse.AccessToken);
        }
        public async Task <IActionResult> Exchange(OpenIdConnectRequest request)
        {
            Debug.Assert(request.IsTokenRequest(),
                         "The OpenIddict binder for ASP.NET Core MVC is not registered. " +
                         "Make sure services.AddOpenIddict().AddMvcBinders() is correctly called.");

            if (request.IsPasswordGrantType())
            {
                var user = await _userManager.FindByNameAsync(request.Username);

                if (user == null)
                {
                    return(BadRequest(new OpenIdConnectResponse
                    {
                        Error = OpenIdConnectConstants.Errors.InvalidGrant,
                        ErrorDescription = "The username/password couple is invalid."
                    }));
                }

                // Validate the username/password parameters and ensure the account is not locked out.
                var result = await _signInManager.CheckPasswordSignInAsync(user, request.Password, lockoutOnFailure : true);

                if (!result.Succeeded)
                {
                    return(BadRequest(new OpenIdConnectResponse
                    {
                        Error = OpenIdConnectConstants.Errors.InvalidGrant,
                        ErrorDescription = "The username/password couple is invalid."
                    }));
                }

                // Create a new authentication ticket.
                var ticket = await CreateTicketAsync(request, user);

                return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme));
            }

            else if (request.IsAuthorizationCodeGrantType() || request.IsRefreshTokenGrantType())
            {
                // Retrieve the claims principal stored in the authorization code/refresh token.
                var info = await HttpContext.AuthenticateAsync(OpenIdConnectServerDefaults.AuthenticationScheme);

                // Retrieve the user profile corresponding to the authorization code/refresh token.
                // Note: if you want to automatically invalidate the authorization code/refresh token
                // when the user password/roles change, use the following line instead:
                // var user = _signInManager.ValidateSecurityStampAsync(info.Principal);
                var user = await _userManager.GetUserAsync(info.Principal);

                if (user == null)
                {
                    return(BadRequest(new OpenIdConnectResponse
                    {
                        Error = OpenIdConnectConstants.Errors.InvalidGrant,
                        ErrorDescription = "The token is no longer valid."
                    }));
                }

                // Ensure the user is still allowed to sign in.
                if (!await _signInManager.CanSignInAsync(user))
                {
                    return(BadRequest(new OpenIdConnectResponse
                    {
                        Error = OpenIdConnectConstants.Errors.InvalidGrant,
                        ErrorDescription = "The user is no longer allowed to sign in."
                    }));
                }

                // Create a new authentication ticket, but reuse the properties stored in the
                // authorization code/refresh token, including the scopes originally granted.
                var ticket = await CreateTicketAsync(request, user, info.Properties);

                return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme));
            }
            else if (request.IsClientCredentialsGrantType())
            {
                // Note: the client credentials are automatically validated by OpenIddict:
                // if client_id or client_secret are invalid, this action won't be invoked.
                var application = await _applicationManager.FindByClientIdAsync(request.ClientId, HttpContext.RequestAborted);

                if (application == null)
                {
                    return(BadRequest(new OpenIdConnectResponse
                    {
                        Error = OpenIdConnectConstants.Errors.InvalidClient,
                        ErrorDescription = "The client application was not found in the database."
                    }));
                }

                // Create a new authentication ticket.
                var ticket = CreateTicket(request, application);

                return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme));
            }

            return(BadRequest(new OpenIdConnectResponse
            {
                Error = OpenIdConnectConstants.Errors.UnsupportedGrantType,
                ErrorDescription = "The specified grant type is not supported."
            }));
        }
Exemplo n.º 29
0
        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);
            }

            // 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 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();

            ProcessLoginCallback(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;

            var isuser = new IdentityServerUser(user.Id)
            {
                DisplayName      = name,
                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, user.Id, name, true, context?.Client.ClientId));

            if (context != null)
            {
                if (context.IsNativeClient())
                {
                    // The client is 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.º 30
0
        public async Task <IActionResult> Callback()
        {
            var acc = User.Identity.IsAuthenticated;
            // read external identity from the temporary cookie
            //var result = await HttpContext.AuthenticateAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);
            var result = await HttpContext.AuthenticateAsync("OpenIdConnect");

            var result1 = await HttpContext.AuthenticateAsync();

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

            //授权成功,把用户信息添加到数据库

            /*
             * result.Properties 中包含了很多信息,根据想要拿取即可
             * 比如:access_token,refresh_token
             */
            var returnUrl = result.Properties.Items["returnUrl"] ?? "~/"; //这是
            //result.Properties.Items["scheme"];
            //result.Properties.Items[".Token.access_token"];
            //result.Properties.Items[".Token.refresh_token"];
            var scheme = string.Empty;

            if (result.Properties.Items.ContainsKey("scheme"))
            {
                scheme = result.Properties.Items["scheme"].ToString();
                //或者
                //scheme = result.Properties.Items[".AuthScheme"];
            }

            var ide = result.Principal.Identities.ToList();

            var id_token     = result.Properties.GetTokenValue("id_token");
            var access_token = result.Properties.GetTokenValue("access_token");

            //刷新token必须存在服务端,不能暴露给客户端
            var refresh_token = result.Properties.GetTokenValue("refresh_token");

            var a1  = result.Properties.GetTokenValue("refresh_token");
            var a2  = result.Properties.GetTokenValue("expires_at");
            var abc = result.Properties.GetTokens();



            var parts     = access_token.Split('.');
            var header    = parts[0];
            var payload   = parts[1];
            var json      = Encoding.UTF8.GetString(Base64Url.Decode(payload));
            var claims    = JObject.Parse(json);
            var auth_time = Utils.ConvertSecondsToDateTime(long.Parse(claims.GetValue("auth_time").ToString())); //颁发时间
            var exp       = Utils.ConvertSecondsToDateTime(long.Parse(claims.GetValue("exp").ToString()));       //过期时间

            //反序列化
            var user = JsonConvert.DeserializeObject <User>(json);

            /*
             * 这里要明确一点,就是第三方哪个字段是唯一的,
             * 比如QQ登陆。那么QQ号就是唯一的。就必须获取QQ号码作为该平台的账号
             * 现在假定ids4服务器email是唯一的(暂且不讨论可以更换)
             */
            var userModel = _infoDbContext.users.FirstOrDefault(_ => _.Email == user.Email);

            if (userModel == null) //新增
            {
                var userEntity = _infoDbContext.Add(new User
                {
                    Email                = claims.GetValue("email").ToString(),
                    UserName             = claims.GetValue("name").ToString(),
                    BindId               = int.Parse(claims.GetValue("sub").ToString()),
                    Address              = user.Address,
                    EmailConfirmed       = user.EmailConfirmed,
                    PhoneNumber          = user.PhoneNumber,
                    PhoneNumberConfirmed = user.PhoneNumberConfirmed,
                    Source               = scheme
                }).Entity;
                var row = await _infoDbContext.SaveChangesAsync();

                if (row > 0)
                {
                    if (!string.IsNullOrWhiteSpace(access_token))
                    {
                        _infoDbContext.Add(new PersistedGrant
                        {
                            UserId     = userEntity.Id,
                            CreateTime = auth_time,
                            Expiration = exp,
                            Token      = access_token,
                            Type       = GrantsType.access_token.ToString()
                        });
                    }
                    if (!string.IsNullOrWhiteSpace(refresh_token))
                    {
                        _infoDbContext.Add(new PersistedGrant
                        {
                            UserId     = userEntity.Id,
                            CreateTime = auth_time,
                            Expiration = exp,
                            Token      = refresh_token,
                            Type       = GrantsType.refresh_token.ToString()
                        });
                        await _infoDbContext.SaveChangesAsync();
                    }
                }
            }
            else
            {
                var grant = _infoDbContext.persistedGrants.Where(_ => _.UserId == userModel.Id);
                if (grant != null)
                {
                    var ref_token = grant.First(_ => _.Type == GrantsType.refresh_token.ToString());
                    var acc_token = grant.First(_ => _.Type == GrantsType.access_token.ToString());

                    if (ref_token != null)
                    {
                        ref_token.CreateTime = auth_time;
                        ref_token.Expiration = exp;
                        ref_token.Token      = refresh_token;
                    }
                    if (acc_token != null)
                    {
                        acc_token.CreateTime = auth_time;
                        acc_token.Expiration = exp;
                        acc_token.Token      = access_token;
                    }
                }

                //更新user 防止用户更新过资料
                userModel.Email    = claims.GetValue("email").ToString();
                userModel.UserName = claims.GetValue("name").ToString();
                userModel.Source   = scheme;
                await _infoDbContext.SaveChangesAsync();
            }

            //return RedirectToAction("UserInfo", "Account");
            return(RedirectToAction("Index", "About"));
        }