More work on auth system

This commit is contained in:
Melody Becker 2025-03-31 08:07:16 +02:00
parent 2afb14c4b3
commit 7d385e48de
No known key found for this signature in database
4 changed files with 37 additions and 5 deletions

View file

@ -17,5 +17,7 @@ type Authenticator struct {
} }
func calcAccessExpirationTimestamp() time.Time { func calcAccessExpirationTimestamp() time.Time {
// For now, the default expiration is one month after creation
// though "never" might also be a good option
return time.Now().Add(time.Hour * 24 * 30) return time.Now().Add(time.Hour * 24 * 30)
} }

View file

@ -9,4 +9,6 @@ var (
ErrUnsupportedAuthMethod = errors.New("authentication method not supported for this user") ErrUnsupportedAuthMethod = errors.New("authentication method not supported for this user")
ErrInvalidCombination = errors.New("invalid account and token combination") ErrInvalidCombination = errors.New("invalid account and token combination")
ErrProcessTimeout = errors.New("authentication process timed out") ErrProcessTimeout = errors.New("authentication process timed out")
// A user may not login, for whatever reason
ErrCantLogin = errors.New("user can't login")
) )

View file

@ -5,10 +5,12 @@ import (
"git.mstar.dev/mstar/goutils/other" "git.mstar.dev/mstar/goutils/other"
"git.mstar.dev/mstar/goutils/sliceutils" "git.mstar.dev/mstar/goutils/sliceutils"
"github.com/google/uuid"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/gorm/clause" "gorm.io/gorm/clause"
"git.mstar.dev/mstar/linstrom/storage-new"
"git.mstar.dev/mstar/linstrom/storage-new/dbgen" "git.mstar.dev/mstar/linstrom/storage-new/dbgen"
"git.mstar.dev/mstar/linstrom/storage-new/models" "git.mstar.dev/mstar/linstrom/storage-new/models"
) )
@ -79,8 +81,10 @@ func (a *Authenticator) StartPasswordLogin(
username string, username string,
password string, password string,
) (nextState LoginNextState, token string, err error) { ) (nextState LoginNextState, token string, err error) {
var acc *models.User if ok, err := a.canUsernameLogin(username); !ok {
acc, err = dbgen.User.Where(dbgen.User.Username.Eq(username)).First() return LoginNextFailure, "", other.Error("auth", "user may not login", err)
}
acc, err := dbgen.User.Where(dbgen.User.Username.Eq(username)).First()
switch err { switch err {
case nil: case nil:
break break
@ -143,10 +147,10 @@ func (a *Authenticator) StartPasswordLogin(
loginToken := models.LoginProcessToken{ loginToken := models.LoginProcessToken{
User: *acc, User: *acc,
UserId: acc.ID, UserId: acc.ID,
ExpiresAt: time.Now().Add(time.Minute * 5), ExpiresAt: calcAccessExpirationTimestamp(),
Token: uuid.NewString(),
} }
err = dbgen.LoginProcessToken.Clauses(clause.OnConflict{DoNothing: true}). err = dbgen.LoginProcessToken.Clauses(clause.OnConflict{UpdateAll: true}).
Omit(dbgen.LoginProcessToken.Token).
Create(&loginToken) Create(&loginToken)
if err != nil { if err != nil {
@ -159,3 +163,24 @@ func (a *Authenticator) StartPasswordLogin(
return nextStates, loginToken.Token, nil return nextStates, loginToken.Token, nil
} }
func (a *Authenticator) canUsernameLogin(username string) (bool, error) {
acc, err := dbgen.User.Where(dbgen.User.Username.Eq(username)).First()
if err != nil {
return false, err
}
if !acc.FinishedRegistration {
return false, ErrCantLogin
}
// TODO: Check roles too
finalRole := storage.CollapseRolesIntoOne(
sliceutils.Map(acc.Roles, func(t models.UserToRole) models.Role {
return t.Role
})...)
if finalRole.CanLogin != nil && !*finalRole.CanLogin {
return false, ErrCantLogin
}
return true, nil
}

View file

@ -15,6 +15,9 @@ import (
) )
func (a *Authenticator) StartPasskeyLogin(username string) (*protocol.CredentialAssertion, error) { func (a *Authenticator) StartPasskeyLogin(username string) (*protocol.CredentialAssertion, error) {
if ok, err := a.canUsernameLogin(username); !ok {
return nil, other.Error("auth", "user may not login", err)
}
acc, err := dbgen.User.Where(dbgen.User.Username.Eq(username)).First() acc, err := dbgen.User.Where(dbgen.User.Username.Eq(username)).First()
if err != nil { if err != nil {
return nil, err return nil, err