diff options
| author | Clement Michaud <clement.michaud34@gmail.com> | 2019-11-17 11:47:07 +0100 |
|---|---|---|
| committer | Clément Michaud <clement.michaud34@gmail.com> | 2019-11-17 16:30:33 +0100 |
| commit | 3b2d733367c88621e4178301f2bcb4bc03613eee (patch) | |
| tree | 41ac41fc5b6cece04db85a08bfa7c32a022f7354 /internal/authentication/file_user_provider.go | |
| parent | a06b69dd458e756f1a3d6867eb5b9f54560e2ee1 (diff) | |
Move source code into internal directory to follow standard project layout.
https://github.com/golang-standards/project-layout
Diffstat (limited to 'internal/authentication/file_user_provider.go')
| -rw-r--r-- | internal/authentication/file_user_provider.go | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/internal/authentication/file_user_provider.go b/internal/authentication/file_user_provider.go new file mode 100644 index 000000000..9882eee71 --- /dev/null +++ b/internal/authentication/file_user_provider.go @@ -0,0 +1,113 @@ +package authentication + +import ( + "fmt" + "io/ioutil" + "sync" + + "github.com/asaskevich/govalidator" + + "gopkg.in/yaml.v2" +) + +// FileUserProvider is a provider reading details from a file. +type FileUserProvider struct { + path *string + database *DatabaseModel + lock *sync.Mutex +} + +// UserDetailsModel is the model of user details in the file database. +type UserDetailsModel struct { + HashedPassword string `yaml:"password" valid:"required"` + Email string `yaml:"email"` + Groups []string `yaml:"groups"` +} + +// DatabaseModel is the model of users file database. +type DatabaseModel struct { + Users map[string]UserDetailsModel `yaml:"users" valid:"required"` +} + +// NewFileUserProvider creates a new instance of FileUserProvider. +func NewFileUserProvider(filepath string) *FileUserProvider { + database, err := readDatabase(filepath) + if err != nil { + // Panic since the file does not exist when Authelia is starting. + panic(err) + } + return &FileUserProvider{ + path: &filepath, + database: database, + lock: &sync.Mutex{}, + } +} + +func readDatabase(path string) (*DatabaseModel, error) { + content, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + db := DatabaseModel{} + err = yaml.Unmarshal(content, &db) + if err != nil { + return nil, err + } + + ok, err := govalidator.ValidateStruct(db) + if err != nil { + return nil, err + } + + if !ok { + return nil, fmt.Errorf("The database format is invalid: %s", err.Error()) + } + return &db, nil +} + +// CheckUserPassword checks if provided password matches for the given user. +func (p *FileUserProvider) CheckUserPassword(username string, password string) (bool, error) { + if details, ok := p.database.Users[username]; ok { + hashedPassword := details.HashedPassword[7:] // Remove {CRYPT} + ok, err := CheckPassword(password, hashedPassword) + if err != nil { + return false, err + } + return ok, nil + } + return false, fmt.Errorf("User '%s' does not exist in database", username) +} + +// GetDetails retrieve the groups a user belongs to. +func (p *FileUserProvider) GetDetails(username string) (*UserDetails, error) { + if details, ok := p.database.Users[username]; ok { + return &UserDetails{ + Groups: details.Groups, + Emails: []string{details.Email}, + }, nil + } + return nil, fmt.Errorf("User '%s' does not exist in database", username) +} + +// UpdatePassword update the password of the given user. +func (p *FileUserProvider) UpdatePassword(username string, newPassword string) error { + details, ok := p.database.Users[username] + if !ok { + return fmt.Errorf("User '%s' does not exist in database", username) + } + + hash := HashPassword(newPassword, "") + details.HashedPassword = fmt.Sprintf("{CRYPT}%s", hash) + + p.lock.Lock() + p.database.Users[username] = details + + b, err := yaml.Marshal(p.database) + if err != nil { + p.lock.Unlock() + return err + } + err = ioutil.WriteFile(*p.path, b, 0644) + p.lock.Unlock() + return err +} |
