Commit ae4ca335 authored by ale's avatar ale

Allow us to opportunistically enable encryption for users

If the user has no encryption keys, we'll initialize them on password
changes. This feature is controlled by a configuration parameter.
parent 78d377a0
Pipeline #1522 passed with stages
in 1 minute and 30 seconds
......@@ -43,7 +43,11 @@ func (r *ChangeUserPasswordRequest) Validate(rctx *RequestContext) error {
// Serve the request.
func (r *ChangeUserPasswordRequest) Serve(rctx *RequestContext) (interface{}, error) {
err := rctx.User.setPrimaryPassword(rctx.Context, rctx.TX, r.CurPassword, r.Password)
err := rctx.User.setPrimaryPassword(rctx.Context, rctx.TX, r.CurPassword, r.Password, rctx.enableOpportunisticEncryption)
if err != nil {
return nil, err
}
rctx.audit.Log(rctx, ResourceID{}, "password changed (user)")
rctx.logUserAction(&rctx.User.User, umdb.LogTypePasswordChange, "password changed (user)")
return nil, err
......@@ -126,7 +130,7 @@ func (r *AccountRecoveryRequest) Serve(rctx *RequestContext) (interface{}, error
return &resp, nil
}
if err := rctx.User.setPrimaryPassword(rctx.Context, rctx.TX, r.RecoveryPassword, r.Password); err != nil {
if err := rctx.User.setPrimaryPassword(rctx.Context, rctx.TX, r.RecoveryPassword, r.Password, rctx.enableOpportunisticEncryption); err != nil {
return nil, err
}
if err := rctx.User.disable2FA(rctx.Context, rctx.TX); err != nil {
......
......@@ -30,6 +30,8 @@ type Config struct {
} `yaml:"sso"`
UserMetaDB *clientutil.BackendConfig `yaml:"user_meta_server"`
EnableOpportunisticEncryption bool `yaml:"enable_opportunistic_encryption"`
}
func (c *Config) domainBackend() domainBackend {
......
......@@ -102,7 +102,7 @@ func (c *testClient) request(uri string, req, out interface{}) error {
return json.Unmarshal(data, out)
}
func startService(t testing.TB) (func(), as.Backend, *testClient) {
func startServiceWithConfig(t testing.TB, svcConfig as.Config) (func(), as.Backend, *testClient) {
stop := ldaptest.StartServer(t, &ldaptest.Config{
Dir: "../ldaptest",
Port: testLDAPPort,
......@@ -121,7 +121,6 @@ func startService(t testing.TB) (func(), as.Backend, *testClient) {
ssoStop, signer, ssoPubKeyFile := withSSO(t)
var svcConfig as.Config
svcConfig.SSO.PublicKeyFile = ssoPubKeyFile
svcConfig.SSO.Domain = testSSODomain
svcConfig.SSO.Service = testSSOService
......@@ -161,6 +160,10 @@ func startService(t testing.TB) (func(), as.Backend, *testClient) {
}, be, c
}
func startService(t testing.TB) (func(), as.Backend, *testClient) {
return startServiceWithConfig(t, as.Config{})
}
// Verify that authentication on GetUser works as expected:
// - users can fetch their own data but not other users'
// - admins can read everything.
......@@ -226,16 +229,23 @@ func TestIntegration_ChangeUserPassword_AuthFail(t *testing.T) {
// Verify various attempts at changing the password (user has no encryption keys).
func TestIntegration_ChangeUserPassword(t *testing.T) {
runChangeUserPasswordTest(t, "uno@investici.org")
runChangeUserPasswordTest(t, "uno@investici.org", as.Config{})
}
// Verify various attempts at changing the password (user has no encryption keys).
func TestIntegration_ChangeUserPassword_WithOpportunisticEncryption(t *testing.T) {
runChangeUserPasswordTest(t, "uno@investici.org", as.Config{
EnableOpportunisticEncryption: true,
})
}
// Verify various attempts at changing the password (user with encryption keys).
func TestIntegration_ChangeUserPassword_WithEncryptionKeys(t *testing.T) {
runChangeUserPasswordTest(t, "due@investici.org")
runChangeUserPasswordTest(t, "due@investici.org", as.Config{})
}
func runChangeUserPasswordTest(t *testing.T, username string) {
stop, _, c := startService(t)
func runChangeUserPasswordTest(t *testing.T, username string, cfg as.Config) {
stop, _, c := startServiceWithConfig(t, cfg)
defer stop()
testdata := []struct {
......
......@@ -80,6 +80,8 @@ type AccountService struct {
resourceValidator *resourceValidator
userValidator UserValidatorFunc
resourceTemplates *templateContext
enableOpportunisticEncryption bool
}
// NewAccountService builds a new AccountService with the specified configuration.
......@@ -97,6 +99,7 @@ func newAccountServiceWithSSO(backend Backend, config *Config, ssoValidator sso.
authService: newAuthService(config, ssoValidator),
audit: &syslogAuditLogger{},
backend: backend,
enableOpportunisticEncryption: config.EnableOpportunisticEncryption,
}
if config.UserMetaDB != nil {
......
......@@ -184,7 +184,7 @@ func (u *RawUser) check2FAState(ctx context.Context, tx TX) error {
// Set the primary password for the user. When encryption keys are present,
// requires a valid unlockPassword.
func (u *RawUser) setPrimaryPassword(ctx context.Context, tx TX, unlockPassword, password string) error {
func (u *RawUser) setPrimaryPassword(ctx context.Context, tx TX, unlockPassword, password string, enableOpportunisticEncryption bool) error {
if u.HasEncryptionKeys {
l, err := u.Keys.add(UserEncryptionKeyMainID, unlockPassword, password)
if err != nil {
......@@ -194,6 +194,10 @@ func (u *RawUser) setPrimaryPassword(ctx context.Context, tx TX, unlockPassword,
if err := tx.SetUserEncryptionKeys(ctx, &u.User, u.Keys); err != nil {
return err
}
} else if enableOpportunisticEncryption {
if err := u.initEncryption(ctx, tx, password); err != nil {
return err
}
}
enc := pwhash.Encrypt(password)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment