snapshot of https://github.com/ory/kratos.git (master, 2026-09-15; blobs > 131072B omitted)
Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
This commit is contained in:
172
hydra/hydra.go
Normal file
172
hydra/hydra.go
Normal file
@@ -0,0 +1,172 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package hydra
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/ory/x/httpx"
|
||||
"github.com/ory/x/sqlxx"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/ory/herodot"
|
||||
hydraclientgo "github.com/ory/hydra-client-go/v2"
|
||||
"github.com/ory/kratos/driver/config"
|
||||
"github.com/ory/kratos/session"
|
||||
)
|
||||
|
||||
type (
|
||||
hydraDependencies interface {
|
||||
config.Provider
|
||||
httpx.ClientProvider
|
||||
}
|
||||
Provider interface {
|
||||
Hydra() Hydra
|
||||
}
|
||||
AcceptLoginRequestParams struct {
|
||||
LoginChallenge string
|
||||
IdentityID string
|
||||
SessionID string
|
||||
AuthenticationMethods session.AuthenticationMethods
|
||||
}
|
||||
Hydra interface {
|
||||
AcceptLoginRequest(ctx context.Context, params AcceptLoginRequestParams) (string, error)
|
||||
GetLoginRequest(ctx context.Context, loginChallenge string) (*hydraclientgo.OAuth2LoginRequest, error)
|
||||
}
|
||||
DefaultHydra struct {
|
||||
d hydraDependencies
|
||||
}
|
||||
)
|
||||
|
||||
func NewDefaultHydra(d hydraDependencies) *DefaultHydra {
|
||||
return &DefaultHydra{
|
||||
d: d,
|
||||
}
|
||||
}
|
||||
|
||||
func GetLoginChallengeID(conf *config.Config, r *http.Request) (sqlxx.NullString, error) {
|
||||
if !r.URL.Query().Has("login_challenge") {
|
||||
return "", nil
|
||||
} else if conf.OAuth2ProviderURL(r.Context()) == nil {
|
||||
return "", errors.WithStack(herodot.ErrMisconfiguration().WithReason("refusing to parse login_challenge query parameter because " + config.ViperKeyOAuth2ProviderURL + " is invalid or unset"))
|
||||
}
|
||||
|
||||
loginChallenge := r.URL.Query().Get("login_challenge")
|
||||
if loginChallenge == "" {
|
||||
return "", errors.WithStack(herodot.ErrBadRequest().WithReason("the login_challenge parameter is present but empty"))
|
||||
}
|
||||
|
||||
return sqlxx.NullString(loginChallenge), nil
|
||||
}
|
||||
|
||||
func (h *DefaultHydra) getAdminURL(ctx context.Context) (string, error) {
|
||||
u := h.d.Config().OAuth2ProviderURL(ctx)
|
||||
if u == nil {
|
||||
return "", errors.WithStack(herodot.ErrMisconfiguration().WithReason(config.ViperKeyOAuth2ProviderURL + " is not configured"))
|
||||
}
|
||||
return u.String(), nil
|
||||
}
|
||||
|
||||
func (h *DefaultHydra) getAdminAPIClient(ctx context.Context) (hydraclientgo.OAuth2API, error) {
|
||||
url, err := h.getAdminURL(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
configuration := hydraclientgo.NewConfiguration()
|
||||
configuration.Servers = hydraclientgo.ServerConfigurations{{URL: url}}
|
||||
|
||||
client := h.d.HTTPClient(ctx).StandardClient()
|
||||
if header := h.d.Config().OAuth2ProviderHeader(ctx); header != nil {
|
||||
client.Transport = httpx.WrapTransportWithHeader(client.Transport, header)
|
||||
}
|
||||
|
||||
configuration.HTTPClient = client
|
||||
return hydraclientgo.NewAPIClient(configuration).OAuth2API, nil
|
||||
}
|
||||
|
||||
func (h *DefaultHydra) AcceptLoginRequest(ctx context.Context, params AcceptLoginRequestParams) (string, error) {
|
||||
remember := h.d.Config().SessionPersistentCookie(ctx)
|
||||
rememberFor := int64(h.d.Config().SessionLifespan(ctx) / time.Second)
|
||||
|
||||
alr := hydraclientgo.NewAcceptOAuth2LoginRequest(params.IdentityID)
|
||||
alr.IdentityProviderSessionId = ¶ms.SessionID
|
||||
alr.Remember = &remember
|
||||
alr.RememberFor = &rememberFor
|
||||
alr.Amr = []string{}
|
||||
for _, r := range params.AuthenticationMethods {
|
||||
alr.Amr = append(alr.Amr, string(r.Method))
|
||||
}
|
||||
|
||||
aa, err := h.getAdminAPIClient(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
resp, r, err := aa.AcceptOAuth2LoginRequest(ctx).LoginChallenge(params.LoginChallenge).AcceptOAuth2LoginRequest(*alr).Execute()
|
||||
if err != nil {
|
||||
innerErr := herodot.ErrInternalServerError().WithWrap(err).WithReasonf("Unable to accept OAuth 2.0 Login Challenge.")
|
||||
if r != nil {
|
||||
innerErr = innerErr.
|
||||
WithDetail("status_code", r.StatusCode).
|
||||
WithDebug(err.Error())
|
||||
}
|
||||
|
||||
if openApiErr := new(hydraclientgo.GenericOpenAPIError); errors.As(err, &openApiErr) {
|
||||
switch oauth2Err := openApiErr.Model().(type) {
|
||||
case hydraclientgo.ErrorOAuth2:
|
||||
innerErr = innerErr.WithDetail("oauth2_error_hint", oauth2Err.GetErrorHint())
|
||||
case *hydraclientgo.ErrorOAuth2:
|
||||
innerErr = innerErr.WithDetail("oauth2_error_hint", oauth2Err.GetErrorHint())
|
||||
}
|
||||
}
|
||||
|
||||
return "", errors.WithStack(innerErr)
|
||||
}
|
||||
|
||||
return resp.RedirectTo, nil
|
||||
}
|
||||
|
||||
func (h *DefaultHydra) GetLoginRequest(ctx context.Context, loginChallenge string) (*hydraclientgo.OAuth2LoginRequest, error) {
|
||||
if loginChallenge == "" {
|
||||
return nil, errors.WithStack(herodot.ErrBadRequest().WithReason("invalid login_challenge"))
|
||||
}
|
||||
|
||||
aa, err := h.getAdminAPIClient(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hlr, r, err := aa.GetOAuth2LoginRequest(ctx).LoginChallenge(loginChallenge).Execute()
|
||||
if err != nil {
|
||||
var innerErr *herodot.DefaultError
|
||||
if r == nil || r.StatusCode >= 500 {
|
||||
innerErr = herodot.ErrInternalServerError()
|
||||
} else {
|
||||
innerErr = herodot.ErrBadRequest()
|
||||
}
|
||||
innerErr = innerErr.WithReasonf("Unable to get OAuth 2.0 Login Challenge.")
|
||||
if r != nil {
|
||||
innerErr = innerErr.
|
||||
WithDetail("status_code", r.StatusCode).
|
||||
WithDebug(err.Error())
|
||||
}
|
||||
|
||||
if openApiErr := new(hydraclientgo.GenericOpenAPIError); errors.As(err, &openApiErr) {
|
||||
switch oauth2Err := openApiErr.Model().(type) {
|
||||
case hydraclientgo.ErrorOAuth2:
|
||||
innerErr = innerErr.WithDetail("oauth2_error_hint", oauth2Err.GetErrorHint())
|
||||
case *hydraclientgo.ErrorOAuth2:
|
||||
innerErr = innerErr.WithDetail("oauth2_error_hint", oauth2Err.GetErrorHint())
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.WithStack(innerErr)
|
||||
}
|
||||
|
||||
return hlr, nil
|
||||
}
|
||||
Reference in New Issue
Block a user