Skip to content

Commit

Permalink
fix: don't assume the login challenge to be a UUID
Browse files Browse the repository at this point in the history
For compatibility with ory/hydra#3515, which
now encodes the whole flow in the login challenge, we cannot further
assume that the challenge is a UUID.
  • Loading branch information
hperl committed Jun 14, 2023
1 parent 697be03 commit 84d14ed
Show file tree
Hide file tree
Showing 43 changed files with 104 additions and 117 deletions.
14 changes: 6 additions & 8 deletions hydra/fake.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import (
"context"
"errors"

"github.com/gofrs/uuid"

hydraclientgo "github.com/ory/hydra-client-go/v2"
"github.com/ory/kratos/session"
)
Expand All @@ -27,24 +25,24 @@ func NewFakeHydra() *FakeHydra {
return &FakeHydra{}
}

func (h *FakeHydra) AcceptLoginRequest(ctx context.Context, hlc uuid.UUID, sub string, amr session.AuthenticationMethods) (string, error) {
switch hlc.String() {
func (h *FakeHydra) AcceptLoginRequest(_ context.Context, loginChallenge string, _ string, _ session.AuthenticationMethods) (string, error) {
switch loginChallenge {
case FAKE_ACCEPT_REQUEST_FAIL:
return "", errors.New("failed to accept login request")
default:
panic("unknown fake login_challenge " + hlc.String())
panic("unknown fake login_challenge " + loginChallenge)
}
}

func (h *FakeHydra) GetLoginRequest(ctx context.Context, hlc uuid.NullUUID) (*hydraclientgo.OAuth2LoginRequest, error) {
switch hlc.UUID.String() {
func (h *FakeHydra) GetLoginRequest(_ context.Context, loginChallenge string) (*hydraclientgo.OAuth2LoginRequest, error) {
switch loginChallenge {
case FAKE_ACCEPT_REQUEST_FAIL:
return &hydraclientgo.OAuth2LoginRequest{}, nil
case FAKE_SUCCESS:
return &hydraclientgo.OAuth2LoginRequest{
RequestUrl: "https://www.ory.sh",
}, nil
default:
panic("unknown fake login_challenge " + hlc.UUID.String())
panic("unknown fake login_challenge " + loginChallenge)
}
}
34 changes: 14 additions & 20 deletions hydra/hydra.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@ package hydra

import (
"context"
"fmt"
"net/http"
"time"

"github.com/ory/x/httpx"
"github.com/ory/x/sqlxx"

"github.com/gofrs/uuid"
"github.com/pkg/errors"

"github.com/ory/herodot"
Expand All @@ -26,12 +25,12 @@ type (
config.Provider
x.HTTPClientProvider
}
HydraProvider interface {
Provider interface {
Hydra() Hydra
}
Hydra interface {
AcceptLoginRequest(ctx context.Context, hlc uuid.UUID, sub string, amr session.AuthenticationMethods) (string, error)
GetLoginRequest(ctx context.Context, hlc uuid.NullUUID) (*hydraclientgo.OAuth2LoginRequest, error)
AcceptLoginRequest(ctx context.Context, loginChallenge string, subject string, amr session.AuthenticationMethods) (string, error)
GetLoginRequest(ctx context.Context, loginChallenge string) (*hydraclientgo.OAuth2LoginRequest, error)
}
DefaultHydra struct {
d hydraDependencies
Expand All @@ -44,19 +43,14 @@ func NewDefaultHydra(d hydraDependencies) *DefaultHydra {
}
}

func GetLoginChallengeID(conf *config.Config, r *http.Request) (uuid.NullUUID, error) {
func GetLoginChallengeID(conf *config.Config, r *http.Request) (sqlxx.NullString, error) {
if !r.URL.Query().Has("login_challenge") {
return uuid.NullUUID{}, nil
return "", nil
} else if conf.OAuth2ProviderURL(r.Context()) == nil {
return uuid.NullUUID{}, errors.WithStack(herodot.ErrInternalServerError.WithReason("refusing to parse login_challenge query parameter because " + config.ViperKeyOAuth2ProviderURL + " is invalid or unset"))
return "", errors.WithStack(herodot.ErrInternalServerError.WithReason("refusing to parse login_challenge query parameter because " + config.ViperKeyOAuth2ProviderURL + " is invalid or unset"))
}

hlc, err := uuid.FromString(r.URL.Query().Get("login_challenge"))
if err != nil || hlc.IsNil() {
return uuid.NullUUID{}, errors.WithStack(herodot.ErrBadRequest.WithReason("the login_challenge parameter is present but invalid or zero UUID"))
} else {
return uuid.NullUUID{UUID: hlc, Valid: true}, nil
}
return sqlxx.NullString(r.URL.Query().Get("login_challenge")), nil
}

func (h *DefaultHydra) getAdminURL(ctx context.Context) (string, error) {
Expand Down Expand Up @@ -85,11 +79,11 @@ func (h *DefaultHydra) getAdminAPIClient(ctx context.Context) (hydraclientgo.OAu
return hydraclientgo.NewAPIClient(configuration).OAuth2Api, nil
}

func (h *DefaultHydra) AcceptLoginRequest(ctx context.Context, hlc uuid.UUID, sub string, amr session.AuthenticationMethods) (string, error) {
func (h *DefaultHydra) AcceptLoginRequest(ctx context.Context, loginChallenge string, subject string, amr session.AuthenticationMethods) (string, error) {
remember := h.d.Config().SessionPersistentCookie(ctx)
rememberFor := int64(h.d.Config().SessionLifespan(ctx) / time.Second)

alr := hydraclientgo.NewAcceptOAuth2LoginRequest(sub)
alr := hydraclientgo.NewAcceptOAuth2LoginRequest(subject)
alr.Remember = &remember
alr.RememberFor = &rememberFor
alr.Amr = []string{}
Expand All @@ -102,7 +96,7 @@ func (h *DefaultHydra) AcceptLoginRequest(ctx context.Context, hlc uuid.UUID, su
return "", err
}

resp, r, err := aa.AcceptOAuth2LoginRequest(ctx).LoginChallenge(fmt.Sprintf("%x", hlc)).AcceptOAuth2LoginRequest(*alr).Execute()
resp, r, err := aa.AcceptOAuth2LoginRequest(ctx).LoginChallenge(loginChallenge).AcceptOAuth2LoginRequest(*alr).Execute()
if err != nil {
innerErr := herodot.ErrInternalServerError.WithWrap(err).WithReasonf("Unable to accept OAuth 2.0 Login Challenge.")
if r != nil {
Expand All @@ -126,8 +120,8 @@ func (h *DefaultHydra) AcceptLoginRequest(ctx context.Context, hlc uuid.UUID, su
return resp.RedirectTo, nil
}

func (h *DefaultHydra) GetLoginRequest(ctx context.Context, hlc uuid.NullUUID) (*hydraclientgo.OAuth2LoginRequest, error) {
if !hlc.Valid {
func (h *DefaultHydra) GetLoginRequest(ctx context.Context, loginChallenge string) (*hydraclientgo.OAuth2LoginRequest, error) {
if loginChallenge == "" {
return nil, errors.WithStack(herodot.ErrBadRequest.WithReason("invalid login_challenge"))
}

Expand All @@ -136,7 +130,7 @@ func (h *DefaultHydra) GetLoginRequest(ctx context.Context, hlc uuid.NullUUID) (
return nil, err
}

hlr, r, err := aa.GetOAuth2LoginRequest(ctx).LoginChallenge(fmt.Sprintf("%x", hlc.UUID)).Execute()
hlr, r, err := aa.GetOAuth2LoginRequest(ctx).LoginChallenge(loginChallenge).Execute()
if err != nil {
innerErr := herodot.ErrInternalServerError.WithWrap(err).WithReasonf("Unable to get OAuth 2.0 Login Challenge.")
if r != nil {
Expand Down
55 changes: 27 additions & 28 deletions hydra/hydra_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,25 @@ package hydra_test
import (
"net/http"
"os"
"reflect"
"testing"

"github.com/gofrs/uuid"
"github.com/stretchr/testify/assert"

"github.com/ory/kratos/driver/config"
"github.com/ory/kratos/hydra"
"github.com/ory/x/configx"
"github.com/ory/x/logrusx"
"github.com/ory/x/sqlxx"
"github.com/ory/x/urlx"
)

func requestFromChallenge(s string) *http.Request {
return &http.Request{URL: urlx.ParseOrPanic("https://hydra?login_challenge=" + s)}
}

func TestGetLoginChallengeID(t *testing.T) {
validChallenge := "https://hydra?login_challenge=b346a452-e8fb-4828-8ef8-a4dbc98dc23a"
invalidChallenge := "https://hydra?login_challenge=invalid"
uuidChallenge := "b346a452-e8fb-4828-8ef8-a4dbc98dc23a"
blobChallenge := "1337deadbeefcafe"
defaultConfig := config.MustNew(t, logrusx.New("", ""), os.Stderr, configx.SkipValidation())
configWithHydra := config.MustNew(
t,
Expand All @@ -37,67 +41,62 @@ func TestGetLoginChallengeID(t *testing.T) {
r *http.Request
}
tests := []struct {
name string
args args
want uuid.NullUUID
wantErr bool
name string
args args
want string
assertErr assert.ErrorAssertionFunc
}{
{
name: "no login challenge; hydra is not configured",
args: args{
conf: defaultConfig,
r: &http.Request{URL: urlx.ParseOrPanic("https://hydra")},
},
want: uuid.NullUUID{Valid: false},
wantErr: false,
want: "",
assertErr: assert.NoError,
},
{
name: "no login challenge; hydra is configured",
args: args{
conf: configWithHydra,
r: &http.Request{URL: urlx.ParseOrPanic("https://hydra")},
},
want: uuid.NullUUID{Valid: false},
wantErr: false,
want: "",
assertErr: assert.NoError,
},
{
name: "login_challenge is present; Hydra is not configured",
args: args{
conf: defaultConfig,
r: &http.Request{URL: urlx.ParseOrPanic(validChallenge)},
r: requestFromChallenge(uuidChallenge),
},
want: uuid.NullUUID{Valid: false},
wantErr: true,
want: "",
assertErr: assert.Error,
},
{
name: "login_challenge is present; hydra is configured",
args: args{
conf: configWithHydra,
r: &http.Request{URL: urlx.ParseOrPanic(validChallenge)},
r: requestFromChallenge(uuidChallenge),
},
want: uuid.NullUUID{Valid: true, UUID: uuid.FromStringOrNil("b346a452-e8fb-4828-8ef8-a4dbc98dc23a")},
wantErr: false,
want: uuidChallenge,
assertErr: assert.NoError,
},
{
name: "login_challenge is invalid; hydra is configured",
args: args{
conf: configWithHydra,
r: &http.Request{URL: urlx.ParseOrPanic(invalidChallenge)},
r: requestFromChallenge(blobChallenge),
},
want: uuid.NullUUID{Valid: false},
wantErr: true,
want: blobChallenge,
assertErr: assert.NoError,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := hydra.GetLoginChallengeID(tt.args.conf, tt.args.r)
if (err != nil) != tt.wantErr {
t.Errorf("GetLoginChallengeID() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetLoginChallengeID() = %v, want %v", got, tt.want)
}
tt.assertErr(t, err)
assert.Equal(t, sqlxx.NullString(tt.want), got)
})
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"id": "0bc96cc9-dda4-4700-9e42-35731f2af91e",
"oauth2_login_challenge": null,
"type": "api",
"expires_at": "2013-10-07T08:23:19Z",
"issued_at": "2013-10-07T08:23:19Z",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"id": "1fb23c75-b809-42cc-8984-6ca2d0a1192f",
"oauth2_login_challenge": null,
"type": "api",
"expires_at": "2013-10-07T08:23:19Z",
"issued_at": "2013-10-07T08:23:19Z",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"id": "202c1981-1e25-47f0-8764-75ad506c2bec",
"oauth2_login_challenge": null,
"type": "browser",
"expires_at": "2013-10-07T08:23:19Z",
"issued_at": "2013-10-07T08:23:19Z",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"id": "349c945a-60f8-436a-a301-7a42c92604f9",
"oauth2_login_challenge": "3caddfd5-9903-4bce-83ff-cae36f42dff7",
"type": "browser",
"expires_at": "2013-10-07T08:23:19Z",
"issued_at": "2013-10-07T08:23:19Z",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"id": "38caf592-b042-4551-b92f-8d5223c2a4e2",
"oauth2_login_challenge": null,
"type": "api",
"expires_at": "2013-10-07T08:23:19Z",
"issued_at": "2013-10-07T08:23:19Z",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"id": "3a9ea34f-0f12-469b-9417-3ae5795a7baa",
"oauth2_login_challenge": null,
"type": "browser",
"expires_at": "2013-10-07T08:23:19Z",
"issued_at": "2013-10-07T08:23:19Z",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"id": "43c99182-bb67-47e1-b564-bb23bd8d4393",
"oauth2_login_challenge": null,
"type": "browser",
"expires_at": "2013-10-07T08:23:19Z",
"issued_at": "2013-10-07T08:23:19Z",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"id": "47edd3a8-0998-4779-9469-f4b8ee4430df",
"oauth2_login_challenge": null,
"type": "api",
"expires_at": "2013-10-07T08:23:19Z",
"issued_at": "2013-10-07T08:23:19Z",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"id": "56d94e8b-8a5d-4b7f-8a6e-3259d2b2903e",
"oauth2_login_challenge": null,
"type": "browser",
"expires_at": "2013-10-07T08:23:19Z",
"issued_at": "2013-10-07T08:23:19Z",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"id": "6d387820-f2f4-4f9f-9980-a90d89e7811f",
"oauth2_login_challenge": null,
"type": "browser",
"expires_at": "2013-10-07T08:23:19Z",
"issued_at": "2013-10-07T08:23:19Z",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"id": "916ded11-aa64-4a27-b06e-96e221a509d7",
"oauth2_login_challenge": null,
"type": "browser",
"expires_at": "2013-10-07T08:23:19Z",
"issued_at": "2013-10-07T08:23:19Z",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"id": "99974ce6-388c-4669-a95a-7757ee724020",
"oauth2_login_challenge": null,
"type": "browser",
"expires_at": "2013-10-07T08:23:19Z",
"issued_at": "2013-10-07T08:23:19Z",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"id": "b1fac7fb-d016-4a06-a7fe-e4eab2a0429f",
"oauth2_login_challenge": null,
"type": "api",
"expires_at": "2013-10-07T08:23:19Z",
"issued_at": "2013-10-07T08:23:19Z",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"id": "d6aa1f23-88c9-4b9b-a850-392f48c7f9e8",
"oauth2_login_challenge": null,
"type": "api",
"expires_at": "2013-10-07T08:23:19Z",
"issued_at": "2013-10-07T08:23:19Z",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"id": "05a7f09d-4ef3-41fb-958a-6ad74584b36a",
"oauth2_login_challenge": null,
"type": "browser",
"expires_at": "2013-10-07T08:23:19Z",
"issued_at": "2013-10-07T08:23:19Z",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"id": "22d58184-b97d-44a5-bbaf-0aa8b4000d81",
"oauth2_login_challenge": null,
"type": "browser",
"expires_at": "2013-10-07T08:23:19Z",
"issued_at": "2013-10-07T08:23:19Z",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"id": "2bf132e0-5d40-4df9-9a11-9106e5333735",
"oauth2_login_challenge": null,
"type": "browser",
"expires_at": "2013-10-07T08:23:19Z",
"issued_at": "2013-10-07T08:23:19Z",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"id": "696e7022-c466-44f6-89c6-8cf93c06a62a",
"oauth2_login_challenge": null,
"type": "api",
"expires_at": "2013-10-07T08:23:19Z",
"issued_at": "2013-10-07T08:23:19Z",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"id": "87fa3f43-5155-42b4-a1ad-174c2595fdaf",
"oauth2_login_challenge": null,
"type": "browser",
"expires_at": "2013-10-07T08:23:19Z",
"issued_at": "2013-10-07T08:23:19Z",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"id": "8ef215a9-e8d5-43b3-9aa3-cb4333562e36",
"oauth2_login_challenge": null,
"type": "api",
"expires_at": "2013-10-07T08:23:19Z",
"issued_at": "2013-10-07T08:23:19Z",
Expand Down

0 comments on commit 84d14ed

Please sign in to comment.