Skip to content

Commit 68da400

Browse files
committed
Add ability to import user password credentials and removed dependency to driver/config from hash
1 parent bb1e866 commit 68da400

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+705
-141
lines changed

cmd/hashers/argon2/root.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"reflect"
77
"strings"
88

9+
"github.com/ory/kratos/hash"
10+
911
"github.com/spf13/cobra"
1012
"github.com/spf13/pflag"
1113

@@ -76,7 +78,7 @@ func configProvider(cmd *cobra.Command, flagConf *argon2Config) (*argon2Config,
7678
_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "Unable to initialize the config provider: %s\n", err)
7779
return nil, cmdx.FailSilently(cmd)
7880
}
79-
conf.localConfig = *conf.config.HasherArgon2()
81+
conf.localConfig = (config.Argon2)(*conf.config.HasherArgon2())
8082

8183
if cmd.Flags().Changed(FlagIterations) {
8284
conf.localConfig.Iterations = flagConf.localConfig.Iterations
@@ -162,6 +164,10 @@ func (c *argon2Config) Config(_ context.Context) *config.Config {
162164
return c.config
163165
}
164166

167+
func (c *argon2Config) HashConfig(ctx context.Context) hash.HashConfigProvider {
168+
return c.Config(ctx)
169+
}
170+
165171
func (c *argon2Config) HasherArgon2() (*config.Argon2, error) {
166172
if c.localConfig.Memory == 0 {
167173
c.localConfig.Memory = config.Argon2DefaultMemory

driver/config/config.go

+14-17
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import (
1515
"testing"
1616
"time"
1717

18+
"github.com/ory/kratos/hash"
19+
1820
"golang.org/x/net/publicsuffix"
1921

2022
"github.com/duo-labs/webauthn/protocol"
@@ -172,19 +174,9 @@ const (
172174
const DefaultSessionCookieName = "ory_kratos_session"
173175

174176
type (
175-
Argon2 struct {
176-
Memory bytesize.ByteSize `json:"memory"`
177-
Iterations uint32 `json:"iterations"`
178-
Parallelism uint8 `json:"parallelism"`
179-
SaltLength uint32 `json:"salt_length"`
180-
KeyLength uint32 `json:"key_length"`
181-
ExpectedDuration time.Duration `json:"expected_duration"`
182-
ExpectedDeviation time.Duration `json:"expected_deviation"`
183-
DedicatedMemory bytesize.ByteSize `json:"dedicated_memory"`
184-
}
185-
Bcrypt struct {
186-
Cost uint32 `json:"cost"`
187-
}
177+
Argon2 hash.Argon2Config
178+
Bcrypt hash.BcryptConfig
179+
188180
SelfServiceHook struct {
189181
Name string `json:"hook"`
190182
Config json.RawMessage `json:"config"`
@@ -215,6 +207,7 @@ type (
215207

216208
Provider interface {
217209
Config(ctx context.Context) *Config
210+
hash.ConfigProvider
218211
}
219212
)
220213

@@ -394,10 +387,10 @@ func (p *Config) SessionName() string {
394387
return stringsx.Coalesce(p.p.String(ViperKeySessionName), DefaultSessionCookieName)
395388
}
396389

397-
func (p *Config) HasherArgon2() *Argon2 {
390+
func (p *Config) HasherArgon2() *hash.Argon2Config {
398391
// warn about usage of default values and point to the docs
399392
// warning will require https://github.com/ory/viper/issues/19
400-
return &Argon2{
393+
return &hash.Argon2Config{
401394
Memory: p.p.ByteSizeF(ViperKeyHasherArgon2ConfigMemory, Argon2DefaultMemory),
402395
Iterations: uint32(p.p.IntF(ViperKeyHasherArgon2ConfigIterations, int(Argon2DefaultIterations))),
403396
Parallelism: uint8(p.p.IntF(ViperKeyHasherArgon2ConfigParallelism, int(Argon2DefaultParallelism))),
@@ -409,15 +402,15 @@ func (p *Config) HasherArgon2() *Argon2 {
409402
}
410403
}
411404

412-
func (p *Config) HasherBcrypt() *Bcrypt {
405+
func (p *Config) HasherBcrypt() *hash.BcryptConfig {
413406
// warn about usage of default values and point to the docs
414407
// warning will require https://github.com/ory/viper/issues/19
415408
cost := uint32(p.p.IntF(ViperKeyHasherBcryptCost, int(BcryptDefaultCost)))
416409
if !p.IsInsecureDevMode() && cost < BcryptDefaultCost {
417410
cost = BcryptDefaultCost
418411
}
419412

420-
return &Bcrypt{Cost: cost}
413+
return &hash.BcryptConfig{Cost: cost}
421414
}
422415

423416
func (p *Config) listenOn(key string) string {
@@ -1040,6 +1033,10 @@ func (p *Config) HasherPasswordHashingAlgorithm() string {
10401033
}
10411034
}
10421035

1036+
func (p *Config) Hasher(provider hash.ConfigProvider) hash.Hasher {
1037+
return hash.NewHasher(p.HasherPasswordHashingAlgorithm(), provider)
1038+
}
1039+
10431040
func (p *Config) CipherAlgorithm() string {
10441041
configValue := p.p.StringF(ViperKeyCipherAlgorithm, DefaultCipherAlgorithm)
10451042
switch configValue {

driver/registry.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ type Registry interface {
7979
errorx.HandlerProvider
8080
errorx.PersistenceProvider
8181

82-
hash.HashProvider
82+
hash.Generator
8383

8484
identity.HandlerProvider
8585
identity.ValidationProvider

driver/registry_default.go

+6-8
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,10 @@ import (
77
"sync"
88
"time"
99

10+
"github.com/gobuffalo/pop/v6"
1011
"github.com/hashicorp/go-retryablehttp"
11-
1212
"github.com/ory/x/httpx"
1313

14-
"github.com/gobuffalo/pop/v6"
15-
1614
"github.com/ory/nosurf"
1715

1816
"github.com/ory/kratos/selfservice/strategy/webauthn"
@@ -271,6 +269,10 @@ func (m *RegistryDefault) SMTPConfig(ctx context.Context) courier.SMTPConfig {
271269
return m.Config(ctx)
272270
}
273271

272+
func (m *RegistryDefault) HashConfig(ctx context.Context) hash.HashConfigProvider {
273+
return m.Config(ctx)
274+
}
275+
274276
func (m *RegistryDefault) selfServiceStrategies() []interface{} {
275277
if len(m.selfserviceStrategies) == 0 {
276278
m.selfserviceStrategies = []interface{}{
@@ -404,11 +406,7 @@ func (m *RegistryDefault) Cipher() cipher.Cipher {
404406

405407
func (m *RegistryDefault) Hasher() hash.Hasher {
406408
if m.passwordHasher == nil {
407-
if m.c.HasherPasswordHashingAlgorithm() == "bcrypt" {
408-
m.passwordHasher = hash.NewHasherBcrypt(m)
409-
} else {
410-
m.passwordHasher = hash.NewHasherArgon2(m)
411-
}
409+
m.passwordHasher = m.c.Hasher(m)
412410
}
413411
return m.passwordHasher
414412
}

hash/hash_comparator.go

+2-4
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ import (
1212
"golang.org/x/crypto/argon2"
1313
"golang.org/x/crypto/bcrypt"
1414
"golang.org/x/crypto/pbkdf2"
15-
16-
"github.com/ory/kratos/driver/config"
1715
)
1816

1917
var ErrUnknownHashAlgorithm = errors.New("unknown hash algorithm")
@@ -102,7 +100,7 @@ func IsPbkdf2Hash(hash []byte) bool {
102100
return isPbkdf2Hash.Match(hash)
103101
}
104102

105-
func decodeArgon2idHash(encodedHash string) (p *config.Argon2, salt, hash []byte, err error) {
103+
func decodeArgon2idHash(encodedHash string) (p *Argon2Config, salt, hash []byte, err error) {
106104
parts := strings.Split(encodedHash, "$")
107105
if len(parts) != 6 {
108106
return nil, nil, nil, ErrInvalidHash
@@ -117,7 +115,7 @@ func decodeArgon2idHash(encodedHash string) (p *config.Argon2, salt, hash []byte
117115
return nil, nil, nil, ErrIncompatibleVersion
118116
}
119117

120-
p = new(config.Argon2)
118+
p = new(Argon2Config)
121119
_, err = fmt.Sscanf(parts[3], "m=%d,t=%d,p=%d", &p.Memory, &p.Iterations, &p.Parallelism)
122120
if err != nil {
123121
return nil, nil, nil, err

hash/hasher.go

+42-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
package hash
22

3-
import "context"
3+
import (
4+
"context"
5+
"time"
6+
7+
"github.com/inhies/go-bytesize"
8+
)
49

510
// Hasher provides methods for generating and comparing password hashes.
611
type Hasher interface {
@@ -11,6 +16,41 @@ type Hasher interface {
1116
Understands(hash []byte) bool
1217
}
1318

14-
type HashProvider interface {
19+
// Generator is the interface that objects that can construct hashers must implement
20+
type Generator interface {
1521
Hasher() Hasher
1622
}
23+
24+
// HashConfigProvider is the interface that objects that can generate configuration for the implemented hashers must
25+
// implement
26+
type HashConfigProvider interface {
27+
HasherBcrypt() *BcryptConfig
28+
HasherArgon2() *Argon2Config
29+
}
30+
31+
type BcryptConfig struct {
32+
Cost uint32 `json:"cost"`
33+
}
34+
35+
type Argon2Config struct {
36+
Memory bytesize.ByteSize `json:"memory"`
37+
Iterations uint32 `json:"iterations"`
38+
Parallelism uint8 `json:"parallelism"`
39+
SaltLength uint32 `json:"salt_length"`
40+
KeyLength uint32 `json:"key_length"`
41+
ExpectedDuration time.Duration `json:"expected_duration"`
42+
ExpectedDeviation time.Duration `json:"expected_deviation"`
43+
DedicatedMemory bytesize.ByteSize `json:"dedicated_memory"`
44+
}
45+
46+
type ConfigProvider interface {
47+
HashConfig(ctx context.Context) HashConfigProvider
48+
}
49+
50+
func NewHasher(algorithm string, provider ConfigProvider) Hasher {
51+
if algorithm == "bcrypt" {
52+
return NewHasherBcrypt(provider)
53+
} else {
54+
return NewHasherArgon2(provider)
55+
}
56+
}

hash/hasher_argon2.go

+2-4
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import (
1111

1212
"github.com/pkg/errors"
1313
"golang.org/x/crypto/argon2"
14-
15-
"github.com/ory/kratos/driver/config"
1614
)
1715

1816
var (
@@ -26,7 +24,7 @@ type Argon2 struct {
2624
}
2725

2826
type Argon2Configuration interface {
29-
config.Provider
27+
ConfigProvider
3028
}
3129

3230
func NewHasherArgon2(c Argon2Configuration) *Argon2 {
@@ -38,7 +36,7 @@ func toKB(mem bytesize.ByteSize) uint32 {
3836
}
3937

4038
func (h *Argon2) Generate(ctx context.Context, password []byte) ([]byte, error) {
41-
p := h.c.Config(ctx).HasherArgon2()
39+
p := h.c.HashConfig(ctx).HasherArgon2()
4240

4341
salt := make([]byte, p.SaltLength)
4442
if _, err := rand.Read(salt); err != nil {

hash/hasher_bcrypt.go

+4-6
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,17 @@ package hash
33
import (
44
"context"
55

6-
"github.com/ory/kratos/schema"
7-
86
"golang.org/x/crypto/bcrypt"
97

10-
"github.com/ory/kratos/driver/config"
8+
"github.com/ory/kratos/schema/errors"
119
)
1210

1311
type Bcrypt struct {
1412
c BcryptConfiguration
1513
}
1614

1715
type BcryptConfiguration interface {
18-
config.Provider
16+
ConfigProvider
1917
}
2018

2119
func NewHasherBcrypt(c BcryptConfiguration) *Bcrypt {
@@ -27,7 +25,7 @@ func (h *Bcrypt) Generate(ctx context.Context, password []byte) ([]byte, error)
2725
return nil, err
2826
}
2927

30-
hash, err := bcrypt.GenerateFromPassword(password, int(h.c.Config(ctx).HasherBcrypt().Cost))
28+
hash, err := bcrypt.GenerateFromPassword(password, int(h.c.HashConfig(ctx).HasherBcrypt().Cost))
3129
if err != nil {
3230
return nil, err
3331
}
@@ -40,7 +38,7 @@ func validateBcryptPasswordLength(password []byte) error {
4038
// so if password is longer than 72 bytes, function returns an error
4139
// See https://en.wikipedia.org/wiki/Bcrypt#User_input
4240
if len(password) > 72 {
43-
return schema.NewPasswordPolicyViolationError(
41+
return errors.NewPasswordPolicyViolationError(
4442
"#/password",
4543
"passwords are limited to a maximum length of 72 characters",
4644
)

0 commit comments

Comments
 (0)