-
Notifications
You must be signed in to change notification settings - Fork 964
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: integration with Hydra #2549
feat: integration with Hydra #2549
Conversation
Hi @grantzvolsky I'd like to give this a shot, against better advice from @vinckr. Which field is the |
Hi @paulbalomiri, I would recommend waiting until this is reviewed and merged. There are a couple of things that still need to be addressed in this PR, like consent remember, making sure that all e2e tests pass, and other things. To answer your question: when your app redirects the user agent to Hydra, Hydra generates a |
Can I help you somehow to speed things up? I wanna play around with Hydra and Kratos in my pet project. And it looks like it's doesn't make sense to implement any glue code for Hydra-Kratos integration as soon as native integration is almost there. |
Hi, @grantzvolsky is currently busy with other priorities and will return to this topic once those are resolved! I know that this topic is urgent for many, but we can't clone him unfortunately ;) |
@grantzvolsky @aeneasr |
8fc0546
to
2fb5c3c
Compare
Codecov Report
@@ Coverage Diff @@
## master #2549 +/- ##
==========================================
- Coverage 75.84% 75.79% -0.06%
==========================================
Files 302 304 +2
Lines 17796 17976 +180
==========================================
+ Hits 13498 13625 +127
- Misses 3264 3300 +36
- Partials 1034 1051 +17
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. |
9e3c934
to
ef8859b
Compare
a735d5b
to
4267949
Compare
persistence/sql/migratest/fixtures/registration_flow/ef18b06e-4700-4021-9949-ef783cd86be8.json
Outdated
Show resolved
Hide resolved
persistence/sql/migratest/fixtures/login_flow/349c945a-60f8-436a-a301-7a42c92604f9.json
Outdated
Show resolved
Hide resolved
persistence/sql/migrations/sql/20220607000001000000_hydra_login_challenge.sqlite3.up.sql
Outdated
Show resolved
Hide resolved
selfservice/flow/login/handler.go
Outdated
cr, err := hydraclient.AcceptHydraLoginRequest( | ||
hydra_admin_url.String(), | ||
hlc, | ||
sess.IdentityID.String(), | ||
h.d.Config().SessionPersistentCookie(r.Context()), | ||
int64(h.d.Config().SessionLifespan(r.Context())/time.Second), | ||
sess.AMR, | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless Ory Hydra tells us that it is ok to skip the login request:
lr, err := hydraclient.GetHydraLoginRequest(hydra_admin_url, hlc)
if err != nil {
// ...
}
if lr.Skip {
// ...
} else {
// ...
}
we should not auto-accept the login. Because it is possible that Ory Hydra is demanding us to show the login screen.
See this code here: https://github.com/ory/hydra-login-consent-node/blob/1496070c9bc5ddcefa327a7311d288c0ede60dcc/src/routes/login.ts#L26-L43
An important question here too is that the reference implementation uses the subject ( https://github.com/ory/hydra-login-consent-node/blob/1496070c9bc5ddcefa327a7311d288c0ede60dcc/src/routes/login.ts#L41 ) which is coming from Ory Hydra, not the own session store.
I think that Ory Hydra has a protection in place which would prevent us from Ory Hydra expecting one subject, and Ory Kratos sending another. But we should double-check that!
Long story short:
- You need to fetch the login request
- If skip is true, you can auto-accept it with the following requirements:
- No session exists yet -> the
subject
value from Ory Hydra's login request response is used. See example - A session exists and
kratos.identity.id == hydra.subject
-> the identity id from the Ory Kratos session is used - A session exists and
kratos.identity.id != hydra.subject
:- Either send
kratos.identity.id
to Ory Hydra, which most likely will end up in an error or; - Invalidate the session and continue to the login form
- Either send
- No session exists yet -> the
- If skip is false you need to:
- If a session exists, log the user out, and perform a fresh log in
- If a session does not exist, continue to the login form
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your insightful review!
Regarding the login logic, this is how I implemented it in the update that I just submitted:
- If skip is true, you can auto-accept it with the following requirements:
i. No session exists yet -> the subject value from Ory Hydra's login request response is used. See example
I don't think this is ever the case, because we handle the Hydra challenge either if AlreadyLoggedIn (session exists) or in the post-login hook (session exists; it has just been created).
2.i and 2.ii
I believe the implementation satisfies both scenarios by always using kratos.identity.id. I just need to add a test for the error when there's a mismatch (will do over the weekend).
- If skip is false you need to:
i. If a session exists, log the user out, and perform a fresh log in
I implemented this by adding a refresh=true
to the login request initialization. This should have the added benefit that it won't "sign the user out of github when they don't complete a circleci login".
Regarding registration, no changes were necessary because the user always enters a password during registration, and the login challenge is handled in the post-registration hook.
Please let me know what you think :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please check the one long comment on login/handler.go
The same applies to the registration flow! Here too we need to respect the "skip" parameter
selfservice/flow/login/handler.go
Outdated
@@ -461,6 +514,26 @@ | |||
return | |||
} | |||
|
|||
if ar.HydraLoginChallenge != uuid.Nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add tests for this new functionality in Go code.
selfservice/flow/login/handler.go
Outdated
if errors.Is(err, ErrAlreadyLoggedIn) { | ||
if r.URL.Query().Has("login_challenge") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add tests for this new functionality in Go code.
@@ -354,6 +357,26 @@ | |||
return | |||
} | |||
|
|||
if ar.HydraLoginChallenge != uuid.Nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add tests for this new functionality in Go code.
@@ -202,6 +205,25 @@ | |||
return nil | |||
} | |||
|
|||
if a.HydraLoginChallenge != uuid.Nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add tests for this new functionality in Go code.
473a6a6
to
0cce52f
Compare
import * as uuid from 'uuid' | ||
import * as oauth2 from '../../../helpers/oauth2' | ||
|
||
context('OpenID Provider', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good set up in the tests :)
0cce52f
to
82bb054
Compare
5245cc2
to
7ce1a88
Compare
@grantzvolsky I don't want to step on your toes here, but would you find it helpful if I fixed some of the breaking tests or are there more breaking changes to come such that it doesn't make sense to do that yet? |
@jpollard-cs Do you mean the e2e tests? They should pass as soon as ory/kratos-selfservice-ui-node#198 is merged. Regarding the tests that Aeneas requested to be added, the only tests that are missing at the moment are those for the registration handler and registration hook, and I expect to add those tomorrow. |
amazing! let me know if there's any other way I can help |
@@ -414,6 +414,7 @@ func TestCompleteLogin(t *testing.T) { | |||
|
|||
t.Run("case=succeeds with passwordless login", func(t *testing.T) { | |||
run := func(t *testing.T, spa bool) { | |||
conf.MustSet(ctx, config.ViperKeySessionWhoAmIAAL, "aal1") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@aeneasr Please take a look at why this test passes in master without this configured.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've left a few comments on things I noticed while going through the code.
I'll now take a look at the integration e2e!
@@ -354,6 +366,16 @@ func (h *Handler) fetchFlow(w http.ResponseWriter, r *http.Request, ps httproute | |||
return | |||
} | |||
|
|||
if ar.HydraLoginChallenge.Valid { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add tests for this in handler_test.go
If you don't want to boot hydra, you could also use a gomock
implementation of the hydra client
@@ -0,0 +1,356 @@ | |||
package password_test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe move this file to the hydra directory?
test/e2e/cypress/integration/profiles/oidc-provider/login.spec.ts
Outdated
Show resolved
Hide resolved
test/e2e/cypress/integration/profiles/oidc-provider/login.spec.ts
Outdated
Show resolved
Hide resolved
test/e2e/cypress/integration/profiles/oidc-provider/login.spec.ts
Outdated
Show resolved
Hide resolved
test/e2e/cypress/integration/profiles/oidc-provider/mfa.spec.ts
Outdated
Show resolved
Hide resolved
38f4e8f
to
ec3befb
Compare
This commit removes the --e2e cypress option because it is broken in the current release. There is an unreleased fix[1], so we may re-add it later, but it isn't necessary because --e2e is the default. [1]: cypress-io/cypress#22829
When using Kratos with Hydra as an OIDC IDP, the Kratos options * session.cookie.persistent and * session.lifespan now also apply to third party login.
195815e
to
78ddde8
Compare
7d7fb95
to
3252529
Compare
This is made obsolete by #2804? |
yes |
@grantzvolsky you are my hero, thank you =) |
This PR adds the configuration option
selfservice.hydra_admin_url
. Setting this value to a Hydra admin endpoint URL turns Kratos into an OIDC identity provider. Resolves #273Related issue(s)
#273
Checklist
vulnerability. If this pull request addresses a security. vulnerability, I confirm that I got green light (please contact
[email protected]) from the maintainers to push the changes.
Further Comments