More work on auth system
This commit is contained in:
parent
2afb14c4b3
commit
7d385e48de
4 changed files with 37 additions and 5 deletions
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
)
|
)
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue