Skip to content
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

Features #164

Merged
merged 5 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 18 additions & 24 deletions server/core/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -956,7 +956,7 @@ func (a *AuthState) verifyPassword(passDBs []*PassDBMap) (*PassDBResult, error)
break
}
} else {
passDBResult, err = authenticateUser(passDBResult, a, passDB)
err = processPassDBResult(passDBResult, a, passDB)
if err != nil || a.UserFound {
break
}
Expand Down Expand Up @@ -1037,16 +1037,16 @@ func checkAllBackends(configErrors map[global.Backend]error, a *AuthState) (err
return err
}

// authenticateUser updates the passDBResult based on the provided passDB
// processPassDBResult updates the passDBResult based on the provided passDB
// and the AuthState object a.
// If passDBResult is nil, it returns an error of type errors.ErrNoPassDBResult.
// It then calls the util.DebugModule function to log debug information.
// Next, it calls the updateAuthentication function to update the fields of a based on the values in passDBResult.
// If the UserFound field of passDBResult is true, it sets the UserFound field of a to true.
// Finally, it returns the updated passDBResult and nil error.
func authenticateUser(passDBResult *PassDBResult, a *AuthState, passDB *PassDBMap) (*PassDBResult, error) {
func processPassDBResult(passDBResult *PassDBResult, a *AuthState, passDB *PassDBMap) error {
if passDBResult == nil {
return passDBResult, errors.ErrNoPassDBResult
return errors.ErrNoPassDBResult
}

util.DebugModule(
Expand All @@ -1057,20 +1057,20 @@ func authenticateUser(passDBResult *PassDBResult, a *AuthState, passDB *PassDBMa
"passdb_result", fmt.Sprintf("%+v", *passDBResult),
)

passDBResult = updateAuthentication(a, passDBResult, passDB)
updateAuthentication(a, passDBResult, passDB)

if passDBResult.UserFound {
a.UserFound = true
}

return passDBResult, nil
return nil
}

// updateAuthentication updates the fields of the AuthState struct with the values from the PassDBResult struct.
// It checks if each field in passDBResult is not nil and if it is not nil, it updates the corresponding field in the AuthState struct.
// It also updates the SourcePassDBBackend and UsedPassDBBackend fields of the AuthState struct with the values from passDBResult.Backend and passDB.backend respectively.
// It returns the updated PassDBResult struct.
func updateAuthentication(a *AuthState, passDBResult *PassDBResult, passDB *PassDBMap) *PassDBResult {
func updateAuthentication(a *AuthState, passDBResult *PassDBResult, passDB *PassDBMap) {
if passDBResult.UserFound {
a.UserFound = true
}

if passDBResult.AccountField != nil {
a.AccountField = passDBResult.AccountField
}
Expand All @@ -1093,8 +1093,6 @@ func updateAuthentication(a *AuthState, passDBResult *PassDBResult, passDB *Pass

a.SourcePassDBBackend = passDBResult.Backend
a.UsedPassDBBackend = passDB.backend

return passDBResult
}

// setStatusCodes sets different status codes for various services.
Expand Down Expand Up @@ -1584,10 +1582,6 @@ func (a *AuthState) postVerificationProcesses(ctx *gin.Context, useCache bool, b
*/

if a.UserFound {
if passDBResult.AccountField != nil {
a.AccountField = passDBResult.AccountField
}

accountName, err = a.updateUserAccountInRedis()
if err != nil {
level.Error(log.Logger).Log(global.LogKeyGUID, a.GUID, global.LogKeyMsg, err.Error())
Expand All @@ -1600,9 +1594,9 @@ func (a *AuthState) postVerificationProcesses(ctx *gin.Context, useCache bool, b
}
}

if useCache {
// Note: User-DB queries never contain a password!
if !a.NoAuth && useCache {
// Make sure the cache backend is in front of the used backend.
// If this is a userdb-request, the authentication state is forced to "true" (see verifyPassword()-moethod)
if passDBResult.Authenticated {
if accountName != "" {
if backendPos[global.BackendCache] < backendPos[a.UsedPassDBBackend] {
Expand Down Expand Up @@ -1646,7 +1640,10 @@ func (a *AuthState) postVerificationProcesses(ctx *gin.Context, useCache bool, b
Attributes: a.Attributes,
}

go backend.SaveUserDataToRedis(a.HTTPClientContext, *a.GUID, redisUserKey, config.LoadableConfig.Server.Redis.PosCacheTTL, ppc)
// Safety net. Never store empty passwords into ppc.
if ppc.Password != "" {
go backend.SaveUserDataToRedis(a.HTTPClientContext, *a.GUID, redisUserKey, config.LoadableConfig.Server.Redis.PosCacheTTL, ppc)
}
}
}
} else {
Expand All @@ -1661,10 +1658,7 @@ func (a *AuthState) postVerificationProcesses(ctx *gin.Context, useCache bool, b
a.saveFailedPasswordCounterInRedis()
}

// Only passdb requests need reloading
if !a.NoAuth {
a.getAllPasswordHistories()
}
a.getAllPasswordHistories()
}

/*
Expand Down
53 changes: 23 additions & 30 deletions server/core/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,49 +38,42 @@ func cachePassDB(auth *AuthState) (passDBResult *PassDBResult, err error) {

passDBResult = &PassDBResult{}

cacheNames := backend.GetCacheNames(auth.Protocol.Get(), global.CacheAll)
accountName, err = auth.updateUserAccountInRedis()
if err != nil {
return
}

for _, cacheName := range cacheNames.GetStringSlice() {
accountName, err = auth.updateUserAccountInRedis()
if err != nil {
return
}
if accountName != "" {
cacheNames := backend.GetCacheNames(auth.Protocol.Get(), global.CacheAll)

if accountName != "" {
for _, cacheName := range cacheNames.GetStringSlice() {
redisPosUserKey := config.LoadableConfig.Server.Redis.Prefix + "ucp:" + cacheName + ":" + accountName

ppc = &backend.PositivePasswordCache{}

if _, err = backend.LoadCacheFromRedis(auth.HTTPClientContext, redisPosUserKey, ppc); err != nil {
isRedisErr := false
if isRedisErr, err = backend.LoadCacheFromRedis(auth.HTTPClientContext, redisPosUserKey, ppc); err != nil {
return
}
}

if ppc != nil {
if auth.NoAuth || ppc.Password == util.GetHash(util.PreparePassword(auth.Password)) {
passDBResult.UserFound = true
passDBResult.AccountField = ppc.AccountField
passDBResult.TOTPSecretField = ppc.TOTPSecretField
passDBResult.UniqueUserIDField = ppc.UniqueUserIDField
passDBResult.DisplayNameField = ppc.DisplayNameField
passDBResult.Authenticated = true
passDBResult.Backend = ppc.Backend
passDBResult.Attributes = ppc.Attributes
// The user was not found for the current cache name
if isRedisErr {
continue
}
}
}

if !passDBResult.Authenticated {
if key := auth.getPasswordHistoryRedisHashKey(true); key != "" {
auth.loadPasswordHistoryFromRedis(key)
}
passDBResult.UserFound = true
passDBResult.AccountField = ppc.AccountField
passDBResult.TOTPSecretField = ppc.TOTPSecretField
passDBResult.UniqueUserIDField = ppc.UniqueUserIDField
passDBResult.DisplayNameField = ppc.DisplayNameField
passDBResult.Backend = ppc.Backend
passDBResult.Attributes = ppc.Attributes

// Prevent password lookups for already known wrong passwords.
if auth.PasswordHistory != nil {
passwordHash := util.GetHash(util.PreparePassword(auth.Password))
if _, foundPassword := (*auth.PasswordHistory)[passwordHash]; foundPassword {
passDBResult.UserFound = true
if auth.NoAuth || ppc.Password == util.GetHash(util.PreparePassword(auth.Password)) {
passDBResult.Authenticated = true
}

break
}
}

Expand Down
Loading