forked from authentricity/authentricity
170 lines
4.8 KiB
Go
170 lines
4.8 KiB
Go
package models
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/GehirnInc/crypt"
|
|
_ "github.com/GehirnInc/crypt/sha256_crypt"
|
|
_ "github.com/GehirnInc/crypt/sha512_crypt"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type Disposition string
|
|
|
|
const (
|
|
DispositionIntrinsic Disposition = "intrinsic"
|
|
DispositionSystem Disposition = "system"
|
|
DispositionDynamic Disposition = "dynamic"
|
|
DispositionRegular Disposition = "regular"
|
|
DispositionContainer Disposition = "container"
|
|
DispositionReserved Disposition = "reserved"
|
|
)
|
|
|
|
type ResourceLimit struct {
|
|
Cur uint64 `mapstructure:"cur"`
|
|
Max uint64 `mapstructure:"max"`
|
|
}
|
|
|
|
type UserRecord struct {
|
|
UUID uuid.UUID `mapstructure:"uuid"`
|
|
UserName string `mapstructure:"userName"`
|
|
Realm string `mapstructure:"realm,omitempty"`
|
|
RealName string `mapstructure:"realName,omitempty"`
|
|
EmailAddress string `mapstructure:"emailAddress,omitempty"`
|
|
IconName string `mapstructure:"iconName,omitempty"`
|
|
Location string `mapstructure:"location,omitempty"`
|
|
Disposition Disposition `mapstructure:"disposition,omitempty"`
|
|
Shell string `mapstructure:"shell,omitempty"`
|
|
Ummask *int32 `mapstructure:"umask,omitempty"`
|
|
Environment []string `mapstructure:"environment,omitempty"`
|
|
TimeZone string `mapstructure:"timeZone,omitempty"`
|
|
PreferredLanguage string `mapstructure:"preferredLanguage,omitempty"`
|
|
NiceLevel int32 `mapstructure:"niceLevel,omitempty"`
|
|
ResourceLimits map[string]ResourceLimit `mapstructure:"resourceLimits,omitempty"`
|
|
Locked bool `mapstructure:"locked,omitempty"`
|
|
NotBeforeUSec *int64 `mapstructure:"notBeforeUSec,omitempty"`
|
|
NotAfterUSec *int64 `mapstructure:"notAfterUSec,omitempty"`
|
|
HomeDirectory string `mapstructure:"homeDirectory,omitempty"`
|
|
UID uint32 `mapstructure:"uid,omitempty"`
|
|
GID uint32 `mapstructure:"gid,omitempty"`
|
|
Service string `mapstructure:"service,omitempty"`
|
|
Privileged *UserPrivileged `mapstructure:"privileged,omitempty"`
|
|
Other map[string]interface{} `mapstructure:"-,remain"`
|
|
}
|
|
|
|
func (ur *UserRecord) ID() uuid.UUID {
|
|
return ur.UUID
|
|
}
|
|
|
|
func (ur *UserRecord) SetID(id uuid.UUID) {
|
|
ur.UUID = id
|
|
}
|
|
|
|
func (ur *UserRecord) Type() EntityType {
|
|
return TypeUser
|
|
}
|
|
|
|
func (ur *UserRecord) Name() string {
|
|
return ur.UserName
|
|
}
|
|
|
|
func (ur *UserRecord) Email() string {
|
|
return ur.EmailAddress
|
|
}
|
|
|
|
func (ur *UserRecord) StripPrivileged() {
|
|
ur.Privileged = nil
|
|
}
|
|
|
|
func (ur *UserRecord) MarshalJSON() ([]byte, error) {
|
|
m := make(map[string]interface{})
|
|
for k, v := range ur.Other {
|
|
m[k] = v
|
|
}
|
|
if err := decode(ur, &m); err != nil {
|
|
return nil, err
|
|
}
|
|
m["@type"] = string(TypeUser)
|
|
return json.Marshal(m)
|
|
}
|
|
|
|
func (ur *UserRecord) UnmarshalJSON(data []byte) error {
|
|
m := make(map[string]interface{})
|
|
if err := json.Unmarshal(data, m); err != nil {
|
|
return err
|
|
}
|
|
delete(m, "@type")
|
|
return decode(m, ur)
|
|
}
|
|
|
|
func (ur *UserRecord) SynthesizeGroup() *GroupRecord {
|
|
return &GroupRecord{
|
|
UUID: ur.UUID,
|
|
GroupName: ur.UserName,
|
|
Realm: ur.Realm,
|
|
Description: ur.RealName,
|
|
Disposition: ur.Disposition,
|
|
GID: ur.GID,
|
|
Service: ur.Service,
|
|
}
|
|
}
|
|
|
|
func (ur *UserRecord) IsUserAllowedToLogin() bool {
|
|
if ur.Locked {
|
|
return false
|
|
}
|
|
|
|
nowMicros := time.Now().UnixMicro()
|
|
if ur.NotBeforeUSec != nil && *ur.NotBeforeUSec > nowMicros {
|
|
return false
|
|
}
|
|
|
|
if ur.NotAfterUSec != nil && *ur.NotAfterUSec < nowMicros {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (ur *UserRecord) EnsurePrivileged() *UserPrivileged {
|
|
if ur.Privileged == nil {
|
|
ur.Privileged = new(UserPrivileged)
|
|
}
|
|
return ur.Privileged
|
|
}
|
|
|
|
type UserPrivileged struct {
|
|
HashedPassword []string `mapstructure:"hashedPassword,omitempty"`
|
|
SSHAuthorizedKeys []string `mapstructure:"sshAuthorizedKeys,omitempty"`
|
|
PublicKeyCredentials []PublicKeyCredential `mapstructure:"publicKeyCredentials,omitempty"`
|
|
|
|
Other map[string]interface{} `mapstructure:"-,remain"`
|
|
}
|
|
|
|
func (priv *UserPrivileged) CheckPassword(pw string) bool {
|
|
if priv == nil {
|
|
return false
|
|
}
|
|
|
|
k := []byte(pw)
|
|
|
|
for _, possibleHash := range priv.HashedPassword {
|
|
if !crypt.IsHashSupported(possibleHash) {
|
|
continue
|
|
}
|
|
|
|
cr := crypt.NewFromHash(possibleHash)
|
|
err := cr.Verify(possibleHash, k)
|
|
if err == nil {
|
|
return true
|
|
} else if errors.Is(err, crypt.ErrKeyMismatch) {
|
|
return false
|
|
} else {
|
|
continue
|
|
}
|
|
}
|
|
return false
|
|
}
|