diff --git a/auth-new/auth.go b/auth-new/auth.go index 1dcce0a..c05c377 100644 --- a/auth-new/auth.go +++ b/auth-new/auth.go @@ -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) } diff --git a/auth-new/errors.go b/auth-new/errors.go index 7922390..0b6289c 100644 --- a/auth-new/errors.go +++ b/auth-new/errors.go @@ -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") ) diff --git a/auth-new/login.go b/auth-new/login.go index 740e583..304f261 100644 --- a/auth-new/login.go +++ b/auth-new/login.go @@ -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 +} diff --git a/auth-new/passkey.go b/auth-new/passkey.go index 30a34ad..2505aa3 100644 --- a/auth-new/passkey.go +++ b/auth-new/passkey.go @@ -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