Beispiel #1
0
        public async Task <IActionResult> Exchange(string device_code, OpenIdConnectRequest request, CancellationToken cancellationToken)
        {
            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.IsDeviceCodeGrantType())
            {
                if (request.ClientId == null)
                {
                    return(BadRequest(new OpenIdConnectResponse
                    {
                        Error = OpenIdConnectConstants.Errors.InvalidClient,
                        ErrorDescription = "Missing required parameter client_id."
                    }));
                }

                // exchange device code for tokens
                var application = await _applicationManager.FindByClientIdAsync(request.ClientId, HttpContext.RequestAborted);

                if (application == null)
                {
                    return(BadRequest(new ErrorViewModel
                    {
                        Error = OpenIdConnectConstants.Errors.InvalidClient,
                        ErrorDescription = "Details concerning the calling client application cannot be found in the database"
                    }));
                }

                var code = await _deviceCodeManager.FindByDeviceCodeAsync(device_code);

                if (code == null)
                {
                    return(BadRequest(new ErrorViewModel
                    {
                        Error = OpenIdConnectConstants.Errors.AccessDenied,
                        ErrorDescription = "Access denied" // todo: use canonical descriptions message for these errors
                    }));
                }

                if (code.AuthorizedOn == default(DateTimeOffset))
                {
                    if (code.LastPolledAt == default(DateTimeOffset))
                    {
                        code.LastPolledAt = DateTimeOffset.Now;

                        await _deviceCodeManager.UpdateLastPolledAt(code);
                    }
                    else
                    {
                        var interval = DateTimeOffset.Now - code.LastPolledAt;

                        if (interval.TotalMilliseconds < _deviceCodeOptions.Interval * 950)
                        {
                            return(BadRequest(new ErrorViewModel
                            {
                                Error = DeviceCodeFlowConstants.Errors.SlowDown,
                                ErrorDescription = "Slow down"
                            }));
                        }
                        else
                        {
                            code.LastPolledAt = DateTimeOffset.Now;

                            await _deviceCodeManager.UpdateLastPolledAt(code);
                        }
                    }

                    return(BadRequest(new ErrorViewModel
                    {
                        Error = DeviceCodeFlowConstants.Errors.DeviceCodeAuthorizationPending,
                        ErrorDescription = "Device code authorization pending"
                    }));
                }

                var user = await _userManager.FindByIdAsync(code.Subject);

                if (user == null)
                {
                    return(BadRequest(new ErrorViewModel
                    {
                        Error = OpenIdConnectConstants.Errors.ServerError,
                        ErrorDescription = "An internal error has occurred"
                    }));
                }

                await _deviceCodeManager.Consume(code);

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

                var ticket = await CreateTicketAsync(new OpenIdConnectRequest
                {
                    Scope        = string.Join(" ", code.Scopes),
                    ClientId     = request.ClientId,
                    ClientSecret = request.ClientSecret,
                    GrantType    = request.GrantType
                }, user);

                return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme));
            }
            else if (request.IsPasswordGrantType())
            {
                // not implemented
            }
            else if (request.IsAuthorizationCodeGrantType())
            {
                // Retrieve the claims principal stored in the authorization code.
                var info = await HttpContext.Authentication.GetAuthenticateInfoAsync(
                    OpenIdConnectServerDefaults.AuthenticationScheme);

                // Retrieve the user profile corresponding to the authorization code.
                var user = await _userManager.GetUserAsync(info.Principal);

                if (user == null)
                {
                    return(BadRequest(new OpenIdConnectResponse
                    {
                        Error = OpenIdConnectConstants.Errors.InvalidGrant,
                        ErrorDescription = "The authorization code 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, including the scopes originally granted.
                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."
            }));
        }