-
-
Notifications
You must be signed in to change notification settings - Fork 963
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: login & registration via code #3378
Conversation
33b1c05
to
62ce450
Compare
41cfae9
to
ffb2035
Compare
5c5d4c3
to
0666a33
Compare
42a1173
to
bd2bbeb
Compare
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.
Very nice! I still need to review the login tests, the registration code, and the registration tests, as well as e2e and trying out the flow myself. In summary, this looks great! There are a few things we need to address:
- Should we enable / disable login / regstration for the code method? If yes, then why not also for verification / recovery?
- The introduced state parameters are not "backwards" looking - they only apply to the new flows which I find a bit strange?
- The SQL migrations should be kept in as few files as possible and avoid DEFAULTs on existing large tables
- The state machine we use in login/registration sets values in the callbacks of outer functions. If a callback is not called, these values might be nil, leading to panics
@@ -38,6 +38,19 @@ | |||
"type": "boolean" | |||
} | |||
} | |||
}, | |||
"code": { |
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'm wondering if we should use a different credential name here. oob_otp
(out of band one time password) is probably the "correct" terminology, but noone understands what this means.
What are your thoughts?
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.
otp
?. code
is also okay since the method you need to enable is code
.
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.
Nice ! I looked at everything now - see comments
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | ||
req.Header.Set("Accept", "application/json") |
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.
Take a look at the password tests - we are testing various flows there (browser html, browser ajax, native api) and I think we need to do this here and in registration too. There are also some testhelpers you can use to easily submit these flows!
|
||
// Step 2: Check if the flow traits match the identity traits | ||
for _, n := range container.NewFromJSON("", node.DefaultGroup, p.Traits, "traits").Nodes { | ||
if !strings.EqualFold(f.GetUI().GetNodes().Find(n.ID()).Attributes.GetValue().(string), n.Attributes.GetValue().(string)) { |
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.
Are you sure these are all strings allways?
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 actually don't know tbh. I also don't know what the best way would be to check if the traits are the same between the submitted UI nodes and the DB UI nodes :/
Maybe @zepatrik knows more about UI node checking ;)
app: "express" as "express", | ||
profile: "code", | ||
}, | ||
// { |
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.
We should probably enable this :)
app: "express" as "express", | ||
profile: "code", | ||
}, | ||
// { |
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.
enable
app: "express" as "express", | ||
profile: "code", | ||
}, | ||
// { |
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.
enable
test/e2e/cypress/support/commands.ts
Outdated
} | ||
console.log({ mailItems: response.body.mailItems }) | ||
console.log({ mailItem }) | ||
console.log({ email }) |
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.
Remove logs?
test/e2e/run.sh
Outdated
@@ -136,7 +136,7 @@ prepare() { | |||
nc -zv localhost 4445 && exit 1 | |||
nc -zv localhost 4446 && exit 1 | |||
nc -zv localhost 4455 && exit 1 | |||
nc -zv localhost 4456 && exit 1 | |||
# nc -zv localhost 4456 && exit 1 |
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.
re-enable?
test/e2e/run.sh
Outdated
>"${base}/test/e2e/ui-node.e2e.log" 2>&1 & | ||
) | ||
fi | ||
# if [ -z ${NODE_UI_PATH+x} ]; then |
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.
re-enable?
92c2292
to
951485b
Compare
Codecov Report
@@ Coverage Diff @@
## master #3378 +/- ##
==========================================
+ Coverage 78.14% 78.24% +0.10%
==========================================
Files 327 339 +12
Lines 21742 22495 +753
==========================================
+ Hits 16991 17602 +611
- Misses 3492 3582 +90
- Partials 1259 1311 +52
|
726b76a
to
e117fef
Compare
Some things to consider before merging:
See this example: One alternative would be to return the if (data.continue_with) {
...
}
code:
enabled: true # enables verification, recovery
passwordless_enabled: true # additionally enables passwordless flows
# aal2_enabled: true Which I'm in favor of.
|
f13a51f
to
70b2914
Compare
Make sure to actually do a pre-release, if you just use a random id it is uploaded as the latest package. (I had that happen a while back.) |
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.
This looks very good! I just had some minor questions and one security concern regarding the code that checks the code.
@@ -19,6 +19,8 @@ type ( | |||
CourierTemplatesVerificationValid() *config.CourierEmailTemplate | |||
CourierTemplatesRecoveryInvalid() *config.CourierEmailTemplate | |||
CourierTemplatesRecoveryValid() *config.CourierEmailTemplate | |||
CourierTemplatesLoginValid() *config.CourierEmailTemplate |
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.
Where is this interface being used or implemented?
@@ -739,6 +748,7 @@ func (p *Config) SelfServiceStrategy(ctx context.Context, strategy string) *Self | |||
// we need to forcibly set these values here: | |||
if !pp.Exists(enabledKey) { |
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.
missing fallthrough?
persistence/sql/persister_login.go
Outdated
secrets: | ||
for _, secret := range p.r.Config().SecretsSession(ctx) { | ||
suppliedCode := []byte(p.hmacValueWithSecret(ctx, codeVal, secret)) | ||
for i := range loginCodes { |
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.
This for
loop looks a bit concerning. If an attacker can create multiple login codes in quick succession, the probability that one of the codes matches a random guess rises.
From a security perspective we should only ever check against one login code, IMHO the latest.
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.
hmm, i added this since you could have multiple identifiers listed under the code credentials type.
The user submits one of those identifiers, an email is sent out to all of their identifiers linked to the code credential. Each email contains a unique code. The second submit the user can submit any of the codes sent out.
See this identity schema https://github.com/ory/kratos/blob/f1a0fae19e32014a9151f320ed2ad6a903f129ea/test/e2e/profiles/code/identity.complex.traits.schema.json
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 think you're both right. In the default case, where an identity has only one or two "login emails", I think that Alano is correct. As far as I can tell, multiple codes (related to one flow id) would only ever be sent out if the identity schema has more than one code credentials identifier.
However, if an identity schema allows an array of identifiers (so 1..n emails used for login), this could theoretically be abused.
I guess this can be fixed by sending EVERY address the same code. At the moment we send every address a different code, which makes brute forcing more likely because we reduce the search space.
Does that make sense?
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.
hmm true, i didn't think of that 🤔
Yeah i agree, sending each the same code will prevent this.
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 had to revert this logic, every address needs a unique code, otherwise we don't know which address got the code - and thus can't verify the correct email.
} | ||
|
||
secrets: | ||
for _, secret := range p.r.Config().SecretsSession(ctx) { |
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.
Same concern about checking multiple codes applies here.
return registrationCode, nil | ||
} | ||
|
||
func (p *Persister) UseRegistrationCode(ctx context.Context, flowID uuid.UUID, rawCode string, addresses ...string) (*code.RegistrationCode, error) { |
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.
This function is very similar to UseLoginCode
. Can we extract this out into a generic function?
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 did this already on review branch
style: format refactor: code cleanup and flow refinement feat: store code credential address type fix: login resend button and field errors fix: invalid code handling and error messages test(e2e): registration with code test: login and registration code fix: login and registration tests style: format test: registration with code error cases test: login with code error messages test: login with code test: login and registration code test: login errors fix: unit tests and verification flow fix: ui rendering on code group instead of default fix: sdk generation fix: sdk generation and tests chore: improve registration with code test chore: code review chore: code review chore: cleanup based on review comments
d8a5c2f
to
42ac455
Compare
Implements Login and Registration via the code strategy.
Related issue(s)
This feature adds passwordless email code login. When a user signs up, or signs in, a code is sent to their email address which they can use to complete the authentication process.
This feature is currently only working for browser facing APIs.
Closes #2029
Closes https://github.com/ory-corp/cloud/issues/3573
Checklist
introduces a new feature.
contributing code guidelines.
vulnerability. If this pull request addresses a security vulnerability, I
confirm that I got the approval (please contact
security@ory.sh) from the maintainers to push
the changes.
works.
Further Comments