Tests
This commit is contained in:
parent
460162737a
commit
7d9f687768
3 changed files with 278 additions and 45 deletions
|
@ -22,7 +22,7 @@ type Manager interface {
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
Name string
|
Name string
|
||||||
Pass string // hashed
|
Hash string // password hash (bcrypt)
|
||||||
Role Role
|
Role Role
|
||||||
Grants []Grant
|
Grants []Grant
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,8 @@ func AllowedRole(role Role) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
ErrUnauthenticated = errors.New("unauthenticated")
|
||||||
ErrUnauthorized = errors.New("unauthorized")
|
ErrUnauthorized = errors.New("unauthorized")
|
||||||
|
ErrInvalidArgument = errors.New("invalid argument")
|
||||||
ErrNotFound = errors.New("not found")
|
ErrNotFound = errors.New("not found")
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,24 +2,14 @@ package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
_ "github.com/mattn/go-sqlite3" // SQLite driver
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
"regexp"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
const (
|
||||||
|
bcryptCost = 11
|
||||||
SELECT * FROM user;
|
)
|
||||||
SELECT * FROM access;
|
|
||||||
|
|
||||||
INSERT INTO user VALUES ('phil','$2a$06$.4W0LI5mcxzxhpjUvpTaNeu0MhRO0T7B.CYnmAkRnlztIy7PrSODu', 'admin');
|
|
||||||
INSERT INTO user VALUES ('ben','$2a$06$skJK/AecWCUmiCjr69ke.Ow/hFA616RdvJJPxnI221zyohsRlyXL.', 'user');
|
|
||||||
INSERT INTO user VALUES ('marian','$2a$10$8U90swQIatvHHI4sw0Wo7.OUy6dUwzMcoOABi6BsS4uF0x3zcSXRW', 'user');
|
|
||||||
|
|
||||||
INSERT INTO access VALUES ('ben','alerts',1,1);
|
|
||||||
INSERT INTO access VALUES ('marian','alerts',1,0);
|
|
||||||
INSERT INTO access VALUES ('','announcements',1,0);
|
|
||||||
INSERT INTO access VALUES ('','write-all',1,1);
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Auther-related queries
|
// Auther-related queries
|
||||||
const (
|
const (
|
||||||
|
@ -77,6 +67,10 @@ type SQLiteAuth struct {
|
||||||
defaultWrite bool
|
defaultWrite bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
allowedUsernameRegex = regexp.MustCompile(`^[-_.@a-zA-Z0-9]+$`)
|
||||||
|
)
|
||||||
|
|
||||||
var _ Auther = (*SQLiteAuth)(nil)
|
var _ Auther = (*SQLiteAuth)(nil)
|
||||||
var _ Manager = (*SQLiteAuth)(nil)
|
var _ Manager = (*SQLiteAuth)(nil)
|
||||||
|
|
||||||
|
@ -105,28 +99,18 @@ func setupNewAuthDB(db *sql.DB) error {
|
||||||
|
|
||||||
func (a *SQLiteAuth) Authenticate(username, password string) (*User, error) {
|
func (a *SQLiteAuth) Authenticate(username, password string) (*User, error) {
|
||||||
if username == Everyone {
|
if username == Everyone {
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthenticated
|
||||||
}
|
}
|
||||||
rows, err := a.db.Query(selectUserQuery, username)
|
user, err := a.User(username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
bcrypt.CompareHashAndPassword([]byte("$2a$11$eX15DeF27FwAgXt9wqJF0uAUMz74XywJcGBH3kP93pzKYv6ATk2ka"),
|
||||||
|
[]byte("intentional slow-down to avoid timing attacks"))
|
||||||
|
return nil, ErrUnauthenticated
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
if err := bcrypt.CompareHashAndPassword([]byte(user.Hash), []byte(password)); err != nil {
|
||||||
var hash, role string
|
return nil, ErrUnauthenticated
|
||||||
if rows.Next() {
|
|
||||||
if err := rows.Scan(&hash, &role); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if err := rows.Err(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
}
|
return user, nil
|
||||||
if err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &User{
|
|
||||||
Name: username,
|
|
||||||
Role: Role(role),
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *SQLiteAuth) Authorize(user *User, topic string, perm Permission) error {
|
func (a *SQLiteAuth) Authorize(user *User, topic string, perm Permission) error {
|
||||||
|
@ -167,7 +151,10 @@ func (a *SQLiteAuth) resolvePerms(read, write bool, perm Permission) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *SQLiteAuth) AddUser(username, password string, role Role) error {
|
func (a *SQLiteAuth) AddUser(username, password string, role Role) error {
|
||||||
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
if !allowedUsernameRegex.MatchString(username) || (role != RoleAdmin && role != RoleUser) {
|
||||||
|
return ErrInvalidArgument
|
||||||
|
}
|
||||||
|
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcryptCost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -178,6 +165,9 @@ func (a *SQLiteAuth) AddUser(username, password string, role Role) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *SQLiteAuth) RemoveUser(username string) error {
|
func (a *SQLiteAuth) RemoveUser(username string) error {
|
||||||
|
if !allowedUsernameRegex.MatchString(username) || username == Everyone {
|
||||||
|
return ErrInvalidArgument
|
||||||
|
}
|
||||||
if _, err := a.db.Exec(deleteUserQuery, username); err != nil {
|
if _, err := a.db.Exec(deleteUserQuery, username); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -224,18 +214,18 @@ func (a *SQLiteAuth) User(username string) (*User, error) {
|
||||||
if username == Everyone {
|
if username == Everyone {
|
||||||
return a.everyoneUser()
|
return a.everyoneUser()
|
||||||
}
|
}
|
||||||
urows, err := a.db.Query(selectUserQuery, username)
|
rows, err := a.db.Query(selectUserQuery, username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer urows.Close()
|
defer rows.Close()
|
||||||
var hash, role string
|
var hash, role string
|
||||||
if !urows.Next() {
|
if !rows.Next() {
|
||||||
return nil, ErrNotFound
|
return nil, ErrNotFound
|
||||||
}
|
}
|
||||||
if err := urows.Scan(&hash, &role); err != nil {
|
if err := rows.Scan(&hash, &role); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if err := urows.Err(); err != nil {
|
} else if err := rows.Err(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
grants, err := a.readGrants(username)
|
grants, err := a.readGrants(username)
|
||||||
|
@ -244,7 +234,7 @@ func (a *SQLiteAuth) User(username string) (*User, error) {
|
||||||
}
|
}
|
||||||
return &User{
|
return &User{
|
||||||
Name: username,
|
Name: username,
|
||||||
Pass: hash,
|
Hash: hash,
|
||||||
Role: Role(role),
|
Role: Role(role),
|
||||||
Grants: grants,
|
Grants: grants,
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -257,7 +247,7 @@ func (a *SQLiteAuth) everyoneUser() (*User, error) {
|
||||||
}
|
}
|
||||||
return &User{
|
return &User{
|
||||||
Name: Everyone,
|
Name: Everyone,
|
||||||
Pass: "",
|
Hash: "",
|
||||||
Role: RoleAnonymous,
|
Role: RoleAnonymous,
|
||||||
Grants: grants,
|
Grants: grants,
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -288,7 +278,7 @@ func (a *SQLiteAuth) readGrants(username string) ([]Grant, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *SQLiteAuth) ChangePassword(username, password string) error {
|
func (a *SQLiteAuth) ChangePassword(username, password string) error {
|
||||||
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcryptCost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -299,6 +289,9 @@ func (a *SQLiteAuth) ChangePassword(username, password string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *SQLiteAuth) ChangeRole(username string, role Role) error {
|
func (a *SQLiteAuth) ChangeRole(username string, role Role) error {
|
||||||
|
if !allowedUsernameRegex.MatchString(username) || (role != RoleAdmin && role != RoleUser) {
|
||||||
|
return ErrInvalidArgument
|
||||||
|
}
|
||||||
if _, err := a.db.Exec(updateUserRoleQuery, string(role), username); err != nil {
|
if _, err := a.db.Exec(updateUserRoleQuery, string(role), username); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
238
auth/auth_sqlite_test.go
Normal file
238
auth/auth_sqlite_test.go
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
package auth_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"heckel.io/ntfy/auth"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSQLiteAuth_FullScenario_Default_DenyAll(t *testing.T) {
|
||||||
|
a := newTestAuth(t, false, false)
|
||||||
|
require.Nil(t, a.AddUser("phil", "phil", auth.RoleAdmin))
|
||||||
|
require.Nil(t, a.AddUser("ben", "ben", auth.RoleUser))
|
||||||
|
require.Nil(t, a.AllowAccess("ben", "mytopic", true, true))
|
||||||
|
require.Nil(t, a.AllowAccess("ben", "readme", true, false))
|
||||||
|
require.Nil(t, a.AllowAccess("ben", "writeme", false, true))
|
||||||
|
require.Nil(t, a.AllowAccess("ben", "everyonewrite", false, false)) // How unfair!
|
||||||
|
require.Nil(t, a.AllowAccess(auth.Everyone, "announcements", true, false))
|
||||||
|
require.Nil(t, a.AllowAccess(auth.Everyone, "everyonewrite", true, true))
|
||||||
|
|
||||||
|
phil, err := a.Authenticate("phil", "phil")
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, "phil", phil.Name)
|
||||||
|
require.True(t, strings.HasPrefix(phil.Hash, "$2a$11$"))
|
||||||
|
require.Equal(t, auth.RoleAdmin, phil.Role)
|
||||||
|
require.Equal(t, []auth.Grant{}, phil.Grants)
|
||||||
|
|
||||||
|
ben, err := a.Authenticate("ben", "ben")
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, "ben", ben.Name)
|
||||||
|
require.True(t, strings.HasPrefix(ben.Hash, "$2a$11$"))
|
||||||
|
require.Equal(t, auth.RoleUser, ben.Role)
|
||||||
|
require.Equal(t, []auth.Grant{
|
||||||
|
{"mytopic", true, true},
|
||||||
|
{"readme", true, false},
|
||||||
|
{"writeme", false, true},
|
||||||
|
{"everyonewrite", false, false},
|
||||||
|
}, ben.Grants)
|
||||||
|
|
||||||
|
notben, err := a.Authenticate("ben", "this is wrong")
|
||||||
|
require.Nil(t, notben)
|
||||||
|
require.Equal(t, auth.ErrUnauthenticated, err)
|
||||||
|
|
||||||
|
// Admin can do everything
|
||||||
|
require.Nil(t, a.Authorize(phil, "sometopic", auth.PermissionWrite))
|
||||||
|
require.Nil(t, a.Authorize(phil, "mytopic", auth.PermissionRead))
|
||||||
|
require.Nil(t, a.Authorize(phil, "readme", auth.PermissionWrite))
|
||||||
|
require.Nil(t, a.Authorize(phil, "writeme", auth.PermissionWrite))
|
||||||
|
require.Nil(t, a.Authorize(phil, "announcements", auth.PermissionWrite))
|
||||||
|
require.Nil(t, a.Authorize(phil, "everyonewrite", auth.PermissionWrite))
|
||||||
|
|
||||||
|
// User cannot do everything
|
||||||
|
require.Nil(t, a.Authorize(ben, "mytopic", auth.PermissionWrite))
|
||||||
|
require.Nil(t, a.Authorize(ben, "mytopic", auth.PermissionRead))
|
||||||
|
require.Nil(t, a.Authorize(ben, "readme", auth.PermissionRead))
|
||||||
|
require.Equal(t, auth.ErrUnauthorized, a.Authorize(ben, "readme", auth.PermissionWrite))
|
||||||
|
require.Equal(t, auth.ErrUnauthorized, a.Authorize(ben, "writeme", auth.PermissionRead))
|
||||||
|
require.Nil(t, a.Authorize(ben, "writeme", auth.PermissionWrite))
|
||||||
|
require.Nil(t, a.Authorize(ben, "writeme", auth.PermissionWrite))
|
||||||
|
require.Equal(t, auth.ErrUnauthorized, a.Authorize(ben, "everyonewrite", auth.PermissionRead))
|
||||||
|
require.Equal(t, auth.ErrUnauthorized, a.Authorize(ben, "everyonewrite", auth.PermissionWrite))
|
||||||
|
require.Nil(t, a.Authorize(ben, "announcements", auth.PermissionRead))
|
||||||
|
require.Equal(t, auth.ErrUnauthorized, a.Authorize(ben, "announcements", auth.PermissionWrite))
|
||||||
|
|
||||||
|
// Everyone else can do barely anything
|
||||||
|
require.Equal(t, auth.ErrUnauthorized, a.Authorize(nil, "sometopicnotinthelist", auth.PermissionRead))
|
||||||
|
require.Equal(t, auth.ErrUnauthorized, a.Authorize(nil, "sometopicnotinthelist", auth.PermissionWrite))
|
||||||
|
require.Equal(t, auth.ErrUnauthorized, a.Authorize(nil, "mytopic", auth.PermissionRead))
|
||||||
|
require.Equal(t, auth.ErrUnauthorized, a.Authorize(nil, "mytopic", auth.PermissionWrite))
|
||||||
|
require.Equal(t, auth.ErrUnauthorized, a.Authorize(nil, "readme", auth.PermissionRead))
|
||||||
|
require.Equal(t, auth.ErrUnauthorized, a.Authorize(nil, "readme", auth.PermissionWrite))
|
||||||
|
require.Equal(t, auth.ErrUnauthorized, a.Authorize(nil, "writeme", auth.PermissionRead))
|
||||||
|
require.Equal(t, auth.ErrUnauthorized, a.Authorize(nil, "writeme", auth.PermissionWrite))
|
||||||
|
require.Equal(t, auth.ErrUnauthorized, a.Authorize(nil, "announcements", auth.PermissionWrite))
|
||||||
|
require.Nil(t, a.Authorize(nil, "announcements", auth.PermissionRead))
|
||||||
|
require.Nil(t, a.Authorize(nil, "everyonewrite", auth.PermissionRead))
|
||||||
|
require.Nil(t, a.Authorize(nil, "everyonewrite", auth.PermissionWrite))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSQLiteAuth_AddUser_Invalid(t *testing.T) {
|
||||||
|
a := newTestAuth(t, false, false)
|
||||||
|
require.Equal(t, auth.ErrInvalidArgument, a.AddUser(" invalid ", "pass", auth.RoleAdmin))
|
||||||
|
require.Equal(t, auth.ErrInvalidArgument, a.AddUser("validuser", "pass", "invalid-role"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSQLiteAuth_AddUser_Timing(t *testing.T) {
|
||||||
|
a := newTestAuth(t, false, false)
|
||||||
|
start := time.Now().UnixMilli()
|
||||||
|
require.Nil(t, a.AddUser("user", "pass", auth.RoleAdmin))
|
||||||
|
require.GreaterOrEqual(t, time.Now().UnixMilli()-start, int64(100)) // Ideally should be > 200ms, but let's not make a brittle
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSQLiteAuth_Authenticate_Timing(t *testing.T) {
|
||||||
|
a := newTestAuth(t, false, false)
|
||||||
|
require.Nil(t, a.AddUser("user", "pass", auth.RoleAdmin))
|
||||||
|
|
||||||
|
// Timing a correct attempt
|
||||||
|
start := time.Now().UnixMilli()
|
||||||
|
_, err := a.Authenticate("user", "pass")
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.GreaterOrEqual(t, time.Now().UnixMilli()-start, int64(100)) // Ideally should be > 200ms, but let's not make a brittle
|
||||||
|
|
||||||
|
// Timing an incorrect attempt
|
||||||
|
start = time.Now().UnixMilli()
|
||||||
|
_, err = a.Authenticate("user", "INCORRECT")
|
||||||
|
require.Equal(t, auth.ErrUnauthenticated, err)
|
||||||
|
require.GreaterOrEqual(t, time.Now().UnixMilli()-start, int64(100)) // Ideally should be > 200ms, but let's not make a brittle
|
||||||
|
|
||||||
|
// Timing a non-existing user attempt
|
||||||
|
start = time.Now().UnixMilli()
|
||||||
|
_, err = a.Authenticate("DOES-NOT-EXIST", "hithere")
|
||||||
|
require.Equal(t, auth.ErrUnauthenticated, err)
|
||||||
|
require.GreaterOrEqual(t, time.Now().UnixMilli()-start, int64(100)) // Ideally should be > 200ms, but let's not make a brittle
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSQLiteAuth_UserManagement(t *testing.T) {
|
||||||
|
a := newTestAuth(t, false, false)
|
||||||
|
require.Nil(t, a.AddUser("phil", "phil", auth.RoleAdmin))
|
||||||
|
require.Nil(t, a.AddUser("ben", "ben", auth.RoleUser))
|
||||||
|
require.Nil(t, a.AllowAccess("ben", "mytopic", true, true))
|
||||||
|
require.Nil(t, a.AllowAccess("ben", "readme", true, false))
|
||||||
|
require.Nil(t, a.AllowAccess("ben", "writeme", false, true))
|
||||||
|
require.Nil(t, a.AllowAccess("ben", "everyonewrite", false, false)) // How unfair!
|
||||||
|
require.Nil(t, a.AllowAccess(auth.Everyone, "announcements", true, false))
|
||||||
|
require.Nil(t, a.AllowAccess(auth.Everyone, "everyonewrite", true, true))
|
||||||
|
|
||||||
|
// Query user details
|
||||||
|
phil, err := a.User("phil")
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, "phil", phil.Name)
|
||||||
|
require.True(t, strings.HasPrefix(phil.Hash, "$2a$11$"))
|
||||||
|
require.Equal(t, auth.RoleAdmin, phil.Role)
|
||||||
|
require.Equal(t, []auth.Grant{}, phil.Grants)
|
||||||
|
|
||||||
|
ben, err := a.User("ben")
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, "ben", ben.Name)
|
||||||
|
require.True(t, strings.HasPrefix(ben.Hash, "$2a$11$"))
|
||||||
|
require.Equal(t, auth.RoleUser, ben.Role)
|
||||||
|
require.Equal(t, []auth.Grant{
|
||||||
|
{"mytopic", true, true},
|
||||||
|
{"readme", true, false},
|
||||||
|
{"writeme", false, true},
|
||||||
|
{"everyonewrite", false, false},
|
||||||
|
}, ben.Grants)
|
||||||
|
|
||||||
|
everyone, err := a.User(auth.Everyone)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, "*", everyone.Name)
|
||||||
|
require.Equal(t, "", everyone.Hash)
|
||||||
|
require.Equal(t, auth.RoleAnonymous, everyone.Role)
|
||||||
|
require.Equal(t, []auth.Grant{
|
||||||
|
{"announcements", true, false},
|
||||||
|
{"everyonewrite", true, true},
|
||||||
|
}, everyone.Grants)
|
||||||
|
|
||||||
|
// Ben: Before revoking
|
||||||
|
require.Nil(t, a.AllowAccess("ben", "mytopic", true, true))
|
||||||
|
require.Nil(t, a.AllowAccess("ben", "readme", true, false))
|
||||||
|
require.Nil(t, a.AllowAccess("ben", "writeme", false, true))
|
||||||
|
require.Nil(t, a.Authorize(ben, "mytopic", auth.PermissionRead))
|
||||||
|
require.Nil(t, a.Authorize(ben, "mytopic", auth.PermissionWrite))
|
||||||
|
require.Nil(t, a.Authorize(ben, "readme", auth.PermissionRead))
|
||||||
|
require.Nil(t, a.Authorize(ben, "writeme", auth.PermissionWrite))
|
||||||
|
|
||||||
|
// Revoke access for "ben" to "mytopic", then check again
|
||||||
|
require.Nil(t, a.ResetAccess("ben", "mytopic"))
|
||||||
|
require.Equal(t, auth.ErrUnauthorized, a.Authorize(ben, "mytopic", auth.PermissionWrite)) // Revoked
|
||||||
|
require.Equal(t, auth.ErrUnauthorized, a.Authorize(ben, "mytopic", auth.PermissionRead)) // Revoked
|
||||||
|
require.Nil(t, a.Authorize(ben, "readme", auth.PermissionRead)) // Unchanged
|
||||||
|
require.Nil(t, a.Authorize(ben, "writeme", auth.PermissionWrite)) // Unchanged
|
||||||
|
|
||||||
|
// Revoke rest of the access
|
||||||
|
require.Nil(t, a.ResetAccess("ben", ""))
|
||||||
|
require.Equal(t, auth.ErrUnauthorized, a.Authorize(ben, "readme", auth.PermissionRead)) // Revoked
|
||||||
|
require.Equal(t, auth.ErrUnauthorized, a.Authorize(ben, "wrtiteme", auth.PermissionWrite)) // Revoked
|
||||||
|
|
||||||
|
// User list
|
||||||
|
users, err := a.Users()
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, 3, len(users))
|
||||||
|
require.Equal(t, "phil", users[0].Name)
|
||||||
|
require.Equal(t, "ben", users[1].Name)
|
||||||
|
require.Equal(t, "*", users[2].Name)
|
||||||
|
|
||||||
|
// Remove user
|
||||||
|
require.Nil(t, a.RemoveUser("ben"))
|
||||||
|
_, err = a.User("ben")
|
||||||
|
require.Equal(t, auth.ErrNotFound, err)
|
||||||
|
|
||||||
|
users, err = a.Users()
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, 2, len(users))
|
||||||
|
require.Equal(t, "phil", users[0].Name)
|
||||||
|
require.Equal(t, "*", users[1].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSQLiteAuth_ChangePassword(t *testing.T) {
|
||||||
|
a := newTestAuth(t, false, false)
|
||||||
|
require.Nil(t, a.AddUser("phil", "phil", auth.RoleAdmin))
|
||||||
|
|
||||||
|
_, err := a.Authenticate("phil", "phil")
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
require.Nil(t, a.ChangePassword("phil", "newpass"))
|
||||||
|
_, err = a.Authenticate("phil", "phil")
|
||||||
|
require.Equal(t, auth.ErrUnauthenticated, err)
|
||||||
|
_, err = a.Authenticate("phil", "newpass")
|
||||||
|
require.Nil(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSQLiteAuth_ChangeRole(t *testing.T) {
|
||||||
|
a := newTestAuth(t, false, false)
|
||||||
|
require.Nil(t, a.AddUser("ben", "ben", auth.RoleUser))
|
||||||
|
require.Nil(t, a.AllowAccess("ben", "mytopic", true, true))
|
||||||
|
require.Nil(t, a.AllowAccess("ben", "readme", true, false))
|
||||||
|
|
||||||
|
ben, err := a.User("ben")
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, auth.RoleUser, ben.Role)
|
||||||
|
require.Equal(t, 2, len(ben.Grants))
|
||||||
|
|
||||||
|
require.Nil(t, a.ChangeRole("ben", auth.RoleAdmin))
|
||||||
|
|
||||||
|
ben, err = a.User("ben")
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, auth.RoleAdmin, ben.Role)
|
||||||
|
require.Equal(t, 0, len(ben.Grants))
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTestAuth(t *testing.T, defaultRead, defaultWrite bool) *auth.SQLiteAuth {
|
||||||
|
filename := filepath.Join(t.TempDir(), "user.db")
|
||||||
|
a, err := auth.NewSQLiteAuth(filename, defaultRead, defaultWrite)
|
||||||
|
require.Nil(t, err)
|
||||||
|
return a
|
||||||
|
}
|
Loading…
Reference in a new issue