Skip to content

Commit

Permalink
fix: update password with access token
Browse files Browse the repository at this point in the history
  • Loading branch information
liuyu committed Sep 13, 2024
1 parent a7037af commit 5a5ac4e
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 98 deletions.
4 changes: 3 additions & 1 deletion internal/authentication/file_user_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
"github.com/authelia/authelia/v4/internal/logging"
)

var _ UserProvider = &FileUserProvider{}

// FileUserProvider is a provider reading details from a file.
type FileUserProvider struct {
config *schema.FileAuthenticationBackend
Expand Down Expand Up @@ -96,7 +98,7 @@ func (p *FileUserProvider) GetDetails(username string) (details *UserDetails, er
}

// UpdatePassword update the password of the given user.
func (p *FileUserProvider) UpdatePassword(username string, newPassword string) (err error) {
func (p *FileUserProvider) UpdatePassword(username, _ string, newPassword string) (err error) {
var details DatabaseUserDetails

if details, err = p.database.GetUserDetails(username); err != nil {
Expand Down
6 changes: 3 additions & 3 deletions internal/authentication/file_user_provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ func TestShouldUpdatePassword(t *testing.T) {

assert.NoError(t, provider.StartupCheck())

err := provider.UpdatePassword("harry", "newpassword")
err := provider.UpdatePassword("harry", "", "newpassword")
assert.NoError(t, err)

// Reset the provider to force a read from disk.
Expand All @@ -181,7 +181,7 @@ func TestShouldUpdatePasswordHashingAlgorithmToArgon2id(t *testing.T) {
assert.NoError(t, provider.StartupCheck())

assert.True(t, strings.HasPrefix(provider.database.Users["harry"].Digest.Encode(), "$6$"))
err := provider.UpdatePassword("harry", "newpassword")
err := provider.UpdatePassword("harry", "", "newpassword")
assert.NoError(t, err)

// Reset the provider to force a read from disk.
Expand All @@ -208,7 +208,7 @@ func TestShouldUpdatePasswordHashingAlgorithmToSHA512(t *testing.T) {
assert.NoError(t, provider.StartupCheck())

assert.True(t, strings.HasPrefix(provider.database.Users["john"].Digest.Encode(), "$argon2id$"))
err := provider.UpdatePassword("john", "newpassword")
err := provider.UpdatePassword("john", "", "newpassword")
assert.NoError(t, err)

// Reset the provider to force a read from disk.
Expand Down
88 changes: 15 additions & 73 deletions internal/authentication/kubesphere_user_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (

"github.com/emicklei/go-restful/v3"
"github.com/go-resty/resty/v2"
"github.com/jellydator/ttlcache/v3"

"github.com/authelia/authelia/v4/internal/utils"
)
Expand All @@ -32,23 +31,15 @@ const (
TokenCacheCapacity = 1000
)

type UserCache struct {
token string
pwd string
}
var _ UserProvider = &KubesphereUserProvider{}

type KubesphereUserProvider struct {
client *resty.Client
cache *ttlcache.Cache[string, UserCache]
}

func NewKubesphereUserProvider() *KubesphereUserProvider {
return &KubesphereUserProvider{
client: resty.New().SetTimeout(2 * time.Second),
cache: ttlcache.New(
ttlcache.WithTTL[string, UserCache](TokenCacheTTL),
ttlcache.WithCapacity[string, UserCache](TokenCacheCapacity), // max online client 1000.
),
}
}

Expand Down Expand Up @@ -92,80 +83,37 @@ func (p *KubesphereUserProvider) CheckUserPassword(username string, password str
RefreshToken: tokens.RefreshToken,
}

p.cache.Set(username, UserCache{tokens.AccessToken, password}, TokenCacheTTL)

return true, res, nil
}

func (p *KubesphereUserProvider) GetDetails(username string) (details *UserDetails, err error) {
token := p.cache.Get(username)
if token == nil {
info, err := utils.GetUserInfoFromBFL(p.client, username)
if err != nil {
return nil, err
}

details := &UserDetails{
Username: username,
DisplayName: username,
Groups: []string{info.OwnerRole},
Emails: []string{username + "@myterminus.com"}, // FIXME:
}

return details, nil
} else {
userUrl := fmt.Sprintf("http://%s.user-space-%s/bfl/iam/v1alpha1/users/%s", utils.BFL_NAME, username, username)

resp, err := p.client.R().
SetHeader(restful.HEADER_Accept, restful.MIME_JSON).
SetHeader(string(utils.TerminusAuthTokenHeader), token.Value().token).
SetResult(&utils.Response{Data: &utils.UserDetail{}}).
Get(userUrl)

if err != nil {
return nil, err
}

if resp.StatusCode() != http.StatusOK {
return nil, errors.New(string(resp.Body()))
}

responseData := resp.Result().(*utils.Response)

if responseData.Code != 0 {
return nil, errors.New(responseData.Message)
}

d := responseData.Data.(*utils.UserDetail)

details := &UserDetails{
Username: username,
DisplayName: username,
// Emails: []string{d.Email},
Emails: []string{username + "@myterminus.com"}, // FIXME:
Groups: d.Roles,
}
info, err := utils.GetUserInfoFromBFL(p.client, username)
if err != nil {
return nil, err
}

return details, nil
details = &UserDetails{
Username: username,
DisplayName: username,
Groups: []string{info.OwnerRole},
Emails: []string{username + "@myterminus.com"}, // FIXME:
}

return details, nil
}

// UpdatePassword update the password of the given user.
func (p *KubesphereUserProvider) UpdatePassword(username string, newPassword string) (err error) {
cache := p.cache.Get(username)
if cache == nil {
return ErrUserNotFound
}
func (p *KubesphereUserProvider) UpdatePassword(username, token string, newPassword string) (err error) {

userUrl := fmt.Sprintf("http://%s.user-space-%s/bfl/iam/v1alpha1/users/%s/password", utils.BFL_NAME, username, username)
reset := utils.PasswordReset{
CurrentPassword: cache.Value().pwd,
CurrentPassword: "",
Password: newPassword,
}

resp, err := p.client.R().
SetHeader(restful.HEADER_Accept, restful.MIME_JSON).
SetHeader(string(utils.TerminusAuthTokenHeader), cache.Value().token).
SetHeader(string(utils.TerminusAuthTokenHeader), token).
SetResult(&utils.Response{}).
SetBody(reset).
Put(userUrl)
Expand Down Expand Up @@ -226,12 +174,6 @@ func (p *KubesphereUserProvider) Refresh(username, token string) (res *ValidResu
RefreshToken: tokens.RefreshToken,
}

cache := p.cache.Get(username)
if cache != nil {
password := cache.Value().pwd
p.cache.Set(username, UserCache{tokens.AccessToken, password}, TokenCacheTTL)
}

return res, nil
}

Expand Down
4 changes: 3 additions & 1 deletion internal/authentication/ldap_user_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import (
"github.com/authelia/authelia/v4/internal/utils"
)

var _ UserProvider = &LDAPUserProvider{}

// LDAPUserProvider is a UserProvider that connects to LDAP servers like ActiveDirectory, OpenLDAP, OpenDJ, FreeIPA, etc.
type LDAPUserProvider struct {
config schema.LDAPAuthenticationBackend
Expand Down Expand Up @@ -177,7 +179,7 @@ func (p *LDAPUserProvider) GetDetails(username string) (details *UserDetails, er
}

// UpdatePassword update the password of the given user.
func (p *LDAPUserProvider) UpdatePassword(username, password string) (err error) {
func (p *LDAPUserProvider) UpdatePassword(username, _, password string) (err error) {
var (
client LDAPClient
profile *ldapUserProfile
Expand Down
34 changes: 17 additions & 17 deletions internal/authentication/ldap_user_provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1387,7 +1387,7 @@ func TestShouldNotUpdateUserPasswordConnect(t *testing.T) {
err := provider.StartupCheck()
require.NoError(t, err)

err = provider.UpdatePassword("john", "password")
err = provider.UpdatePassword("john", "", "password")
assert.EqualError(t, err, "unable to update password. Cause: dial failed with error: tcp timeout")
}

Expand Down Expand Up @@ -1464,7 +1464,7 @@ func TestShouldNotUpdateUserPasswordGetDetails(t *testing.T) {
err := provider.StartupCheck()
require.NoError(t, err)

err = provider.UpdatePassword("john", "password")
err = provider.UpdatePassword("john", "", "password")
assert.EqualError(t, err, "unable to update password. Cause: cannot find user DN of user 'john'. Cause: LDAP Result Code 2 \"Protocol Error\": permission error")
}

Expand Down Expand Up @@ -1571,7 +1571,7 @@ func TestShouldUpdateUserPassword(t *testing.T) {
err := provider.StartupCheck()
require.NoError(t, err)

err = provider.UpdatePassword("john", "password")
err = provider.UpdatePassword("john", "", "password")
require.NoError(t, err)
}

Expand Down Expand Up @@ -1680,7 +1680,7 @@ func TestShouldUpdateUserPasswordMSAD(t *testing.T) {
err := provider.StartupCheck()
require.NoError(t, err)

err = provider.UpdatePassword("john", "password")
err = provider.UpdatePassword("john", "", "password")
require.NoError(t, err)
}

Expand Down Expand Up @@ -1809,7 +1809,7 @@ func TestShouldUpdateUserPasswordMSADWithReferrals(t *testing.T) {
err := provider.StartupCheck()
require.NoError(t, err)

err = provider.UpdatePassword("john", "password")
err = provider.UpdatePassword("john", "", "password")
require.NoError(t, err)
}

Expand Down Expand Up @@ -1927,7 +1927,7 @@ func TestShouldUpdateUserPasswordMSADWithReferralsWithReferralConnectErr(t *test
err := provider.StartupCheck()
require.NoError(t, err)

err = provider.UpdatePassword("john", "password")
err = provider.UpdatePassword("john", "", "password")
assert.EqualError(t, err, "unable to update password. Cause: error occurred connecting to referred LDAP server 'ldap://192.168.0.1': dial failed with error: tcp timeout. Original Error: LDAP Result Code 10 \"Referral\": error occurred")
}

Expand Down Expand Up @@ -2060,7 +2060,7 @@ func TestShouldUpdateUserPasswordMSADWithReferralsWithReferralModifyErr(t *testi
err := provider.StartupCheck()
require.NoError(t, err)

err = provider.UpdatePassword("john", "password")
err = provider.UpdatePassword("john", "", "password")
assert.EqualError(t, err, "unable to update password. Cause: error occurred performing modify on referred LDAP server 'ldap://192.168.0.1': LDAP Result Code 51 \"Busy\": error occurred. Original Error: LDAP Result Code 10 \"Referral\": error occurred")
}

Expand Down Expand Up @@ -2174,7 +2174,7 @@ func TestShouldUpdateUserPasswordMSADWithoutReferrals(t *testing.T) {
err := provider.StartupCheck()
require.NoError(t, err)

err = provider.UpdatePassword("john", "password")
err = provider.UpdatePassword("john", "", "password")
assert.EqualError(t, err, "unable to update password. Cause: LDAP Result Code 10 \"Referral\": error occurred")
}

Expand Down Expand Up @@ -2280,7 +2280,7 @@ func TestShouldUpdateUserPasswordPasswdModifyExtension(t *testing.T) {
err := provider.StartupCheck()
require.NoError(t, err)

err = provider.UpdatePassword("john", "password")
err = provider.UpdatePassword("john", "", "password")
require.NoError(t, err)
}

Expand Down Expand Up @@ -2408,7 +2408,7 @@ func TestShouldUpdateUserPasswordPasswdModifyExtensionWithReferrals(t *testing.T
err := provider.StartupCheck()
require.NoError(t, err)

err = provider.UpdatePassword("john", "password")
err = provider.UpdatePassword("john", "", "password")
require.NoError(t, err)
}

Expand Down Expand Up @@ -2521,7 +2521,7 @@ func TestShouldUpdateUserPasswordPasswdModifyExtensionWithoutReferrals(t *testin
err := provider.StartupCheck()
require.NoError(t, err)

err = provider.UpdatePassword("john", "password")
err = provider.UpdatePassword("john", "", "password")
assert.EqualError(t, err, "unable to update password. Cause: LDAP Result Code 10 \"Referral\": error occurred")
}

Expand Down Expand Up @@ -2638,7 +2638,7 @@ func TestShouldUpdateUserPasswordPasswdModifyExtensionWithReferralsReferralConne
err := provider.StartupCheck()
require.NoError(t, err)

err = provider.UpdatePassword("john", "password")
err = provider.UpdatePassword("john", "", "password")
assert.EqualError(t, err, "unable to update password. Cause: error occurred connecting to referred LDAP server 'ldap://192.168.0.1': dial failed with error: tcp timeout. Original Error: LDAP Result Code 10 \"Referral\": error occurred")
}

Expand Down Expand Up @@ -2770,7 +2770,7 @@ func TestShouldUpdateUserPasswordPasswdModifyExtensionWithReferralsReferralPassw
err := provider.StartupCheck()
require.NoError(t, err)

err = provider.UpdatePassword("john", "password")
err = provider.UpdatePassword("john", "", "password")
assert.EqualError(t, err, "unable to update password. Cause: error occurred performing password modify on referred LDAP server 'ldap://192.168.0.1': LDAP Result Code 51 \"Busy\": too busy. Original Error: LDAP Result Code 10 \"Referral\": error occurred")
}

Expand Down Expand Up @@ -2881,7 +2881,7 @@ func TestShouldUpdateUserPasswordActiveDirectoryWithServerPolicyHints(t *testing
err := provider.StartupCheck()
require.NoError(t, err)

err = provider.UpdatePassword("john", "password")
err = provider.UpdatePassword("john", "", "password")
assert.NoError(t, err)
}

Expand Down Expand Up @@ -2992,7 +2992,7 @@ func TestShouldUpdateUserPasswordActiveDirectoryWithServerPolicyHintsDeprecated(
err := provider.StartupCheck()
require.NoError(t, err)

err = provider.UpdatePassword("john", "password")
err = provider.UpdatePassword("john", "", "password")
require.NoError(t, err)
}

Expand Down Expand Up @@ -3103,7 +3103,7 @@ func TestShouldUpdateUserPasswordActiveDirectory(t *testing.T) {
err := provider.StartupCheck()
require.NoError(t, err)

err = provider.UpdatePassword("john", "password")
err = provider.UpdatePassword("john", "", "password")
require.NoError(t, err)
}

Expand Down Expand Up @@ -3211,7 +3211,7 @@ func TestShouldUpdateUserPasswordBasic(t *testing.T) {
err := provider.StartupCheck()
require.NoError(t, err)

err = provider.UpdatePassword("john", "password")
err = provider.UpdatePassword("john", "", "password")
require.NoError(t, err)
}

Expand Down
2 changes: 1 addition & 1 deletion internal/authentication/user_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ type UserProvider interface {

CheckUserPassword(username string, password string) (valid bool, result *ValidResult, err error)
GetDetails(username string) (details *UserDetails, err error)
UpdatePassword(username string, newPassword string) (err error)
UpdatePassword(username, accessToken string, newPassword string) (err error)
Refresh(username, token string) (*ValidResult, error)
}
2 changes: 1 addition & 1 deletion internal/handlers/handler_reset_password_step2.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func ResetPasswordPOST(ctx *middlewares.AutheliaCtx) {
return
}

if err = ctx.Providers.UserProvider.UpdatePassword(username, requestBody.Password); err != nil {
if err = ctx.Providers.UserProvider.UpdatePassword(username, userSession.AccessToken, requestBody.Password); err != nil {
switch {
case utils.IsStringInSliceContains(err.Error(), ldapPasswordComplexityCodes),
utils.IsStringInSliceContains(err.Error(), ldapPasswordComplexityErrors):
Expand Down
5 changes: 4 additions & 1 deletion internal/mocks/user_provider.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 5a5ac4e

Please sign in to comment.