Skip to content

Commit 19a6bcc

Browse files
committed
feat(totp): support account name setting from schema
1 parent 0a7c812 commit 19a6bcc

File tree

9 files changed

+78
-6
lines changed

9 files changed

+78
-6
lines changed

driver/config/config.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import (
66
"crypto/tls"
77
"encoding/json"
88
"fmt"
9-
"io"
109
"github.com/duo-labs/webauthn/protocol"
10+
"io"
1111
"net"
1212
"net/http"
1313
"net/url"
@@ -1010,7 +1010,7 @@ func (p *Config) WebAuthnConfig() *webauthn.Config {
10101010
RPOrigin: p.p.String(ViperKeyWebAuthnRPOrigin),
10111011
RPIcon: p.p.String(ViperKeyWebAuthnRPIcon),
10121012
AuthenticatorSelection: protocol.AuthenticatorSelection{
1013-
UserVerification: protocol.VerificationDiscouraged,
1013+
UserVerification: protocol.VerificationDiscouraged,
10141014
},
10151015
}
10161016
}

schema/extension.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ type (
2020
Password struct {
2121
Identifier bool `json:"identifier"`
2222
} `json:"password"`
23+
TOTP struct {
24+
AccountName bool `json:"account_name"`
25+
} `json:"totp"`
2326
} `json:"credentials"`
2427
Verification struct {
2528
Via string `json:"via"`

schema/extension_test.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,17 @@ import (
1313
)
1414

1515
type extensionStub struct {
16-
identifiers []string
16+
identifiers []string
17+
accountNames []string
1718
}
1819

1920
func (r *extensionStub) Run(ctx jsonschema.ValidationContext, config ExtensionConfig, value interface{}) error {
2021
if config.Credentials.Password.Identifier {
2122
r.identifiers = append(r.identifiers, fmt.Sprintf("%s", value))
2223
}
24+
if config.Credentials.TOTP.AccountName {
25+
r.accountNames = append(r.accountNames, fmt.Sprintf("%s", value))
26+
}
2327
return nil
2428
}
2529

@@ -60,6 +64,7 @@ func TestExtensionRunner(t *testing.T) {
6064
}
6165

6266
assert.EqualValues(t, tc.expect, r.identifiers)
67+
assert.EqualValues(t, tc.expect, r.accountNames)
6368
})
6469
}
6570
})

schema/stub/extension/schema.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
"credentials": {
99
"password": {
1010
"identifier": true
11+
},
12+
"totp": {
13+
"account_name": true
1114
}
1215
}
1316
}

schema/stub/extension/schema.nested.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
"credentials": {
1111
"password": {
1212
"identifier": true
13+
},
14+
"totp": {
15+
"account_name": true
1316
}
1417
}
1518
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package totp
2+
3+
import (
4+
"fmt"
5+
"sync"
6+
7+
"github.com/ory/jsonschema/v3"
8+
"github.com/ory/kratos/schema"
9+
)
10+
11+
type SchemaExtension struct {
12+
AccountName string
13+
l sync.Mutex
14+
}
15+
16+
func NewSchemaExtension(fallback string) *SchemaExtension {
17+
return &SchemaExtension{AccountName: fallback}
18+
}
19+
20+
func (r *SchemaExtension) Run(_ jsonschema.ValidationContext, s schema.ExtensionConfig, value interface{}) error {
21+
r.l.Lock()
22+
defer r.l.Unlock()
23+
if s.Credentials.TOTP.AccountName {
24+
r.AccountName = fmt.Sprintf("%s", value)
25+
}
26+
return nil
27+
}
28+
29+
func (r *SchemaExtension) Finish() error {
30+
return nil
31+
}

selfservice/strategy/totp/settings.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,11 @@ func (s *Strategy) PopulateSettingsMethod(r *http.Request, id *identity.Identity
249249
if hasTOTP {
250250
f.UI.Nodes.Upsert(NewUnlinkTOTPNode())
251251
} else {
252+
e := NewSchemaExtension(id.ID.String())
253+
_ = s.d.IdentityValidator().ValidateWithRunner(r.Context(), id, e)
254+
252255
// No TOTP set up yet, add nodes allowing us to add it.
253-
key, err := NewKey(r.Context(), id.ID.String(), s.d)
256+
key, err := NewKey(r.Context(), e.AccountName, s.d)
254257
if err != nil {
255258
return err
256259
}

selfservice/strategy/totp/settings_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func TestCompleteSettings(t *testing.T) {
5959

6060
conf.MustSet(config.ViperKeySelfServiceSettingsPrivilegedAuthenticationAfter, "1m")
6161

62-
conf.MustSet(config.ViperKeyDefaultIdentitySchemaURL, "file://./stub/login.schema.json")
62+
conf.MustSet(config.ViperKeyDefaultIdentitySchemaURL, "file://./stub/settings.schema.json")
6363
conf.MustSet(config.ViperKeySecretsDefault, []string{"not-a-secure-session-key"})
6464

6565
t.Run("case=device unlinking is available when identity has totp", func(t *testing.T) {
@@ -297,13 +297,14 @@ func TestCompleteSettings(t *testing.T) {
297297

298298
t.Run("type=set up TOTP device", func(t *testing.T) {
299299
checkIdentity := func(t *testing.T, id *identity.Identity, key string) {
300-
_, cred, err := reg.PrivilegedIdentityPool().FindByCredentialsIdentifier(context.Background(), identity.CredentialsTypeTOTP, id.ID.String())
300+
i, cred, err := reg.PrivilegedIdentityPool().FindByCredentialsIdentifier(context.Background(), identity.CredentialsTypeTOTP, id.ID.String())
301301
require.NoError(t, err)
302302
var c totp.CredentialsConfig
303303
require.NoError(t, json.Unmarshal(cred.Config, &c))
304304
actual, err := otp.NewKeyFromURL(c.TOTPURL)
305305
require.NoError(t, err)
306306
assert.Equal(t, key, actual.Secret())
307+
assert.Contains(t, c.TOTPURL, gjson.GetBytes(i.Traits, "subject").String())
307308
}
308309

309310
run := func(t *testing.T, isAPI, isSPA bool, id *identity.Identity, hc *http.Client, f *kratos.SelfServiceSettingsFlow) {
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"$id": "https://example.com/person.schema.json",
3+
"$schema": "http://json-schema.org/draft-07/schema#",
4+
"title": "Person",
5+
"type": "object",
6+
"properties": {
7+
"traits": {
8+
"type": "object",
9+
"properties": {
10+
"subject": {
11+
"type": "string",
12+
"ory.sh/kratos": {
13+
"credentials": {
14+
"totp": {
15+
"account_name": true
16+
}
17+
}
18+
}
19+
}
20+
}
21+
}
22+
}
23+
}

0 commit comments

Comments
 (0)