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 {
// 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)
}

View file

@ -9,4 +9,6 @@ var (
ErrUnsupportedAuthMethod = errors.New("authentication method not supported for this user")
ErrInvalidCombination = errors.New("invalid account and token combination")
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/sliceutils"
"github.com/google/uuid"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
"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/models"
)
@ -79,8 +81,10 @@ func (a *Authenticator) StartPasswordLogin(
username string,
password string,
) (nextState LoginNextState, token string, err error) {
var acc *models.User
acc, err = dbgen.User.Where(dbgen.User.Username.Eq(username)).First()
if ok, err := a.canUsernameLogin(username); !ok {
return LoginNextFailure, "", other.Error("auth", "user may not login", err)
}
acc, err := dbgen.User.Where(dbgen.User.Username.Eq(username)).First()
switch err {
case nil:
break
@ -143,10 +147,10 @@ func (a *Authenticator) StartPasswordLogin(
loginToken := models.LoginProcessToken{
User: *acc,
UserId: acc.ID,
ExpiresAt: time.Now().Add(time.Minute * 5),
ExpiresAt: calcAccessExpirationTimestamp(),
Token: uuid.NewString(),
}
err = dbgen.LoginProcessToken.Clauses(clause.OnConflict{DoNothing: true}).
Omit(dbgen.LoginProcessToken.Token).
err = dbgen.LoginProcessToken.Clauses(clause.OnConflict{UpdateAll: true}).
Create(&loginToken)
if err != nil {
@ -159,3 +163,24 @@ func (a *Authenticator) StartPasswordLogin(
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) {
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()
if err != nil {
return nil, err