Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
N
Ntfy_archive
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
TeDomum
Ntfy_archive
Commits
89957e70
Commit
89957e70
authored
3 years ago
by
Philipp Heckel
Browse files
Options
Downloads
Patches
Plain Diff
Docblocking
parent
26dde0f2
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
Makefile
+1
-1
1 addition, 1 deletion
Makefile
auth/auth.go
+41
-2
41 additions, 2 deletions
auth/auth.go
auth/auth_sqlite.go
+32
-9
32 additions, 9 deletions
auth/auth_sqlite.go
with
74 additions
and
12 deletions
Makefile
+
1
−
1
View file @
89957e70
...
...
@@ -80,7 +80,7 @@ vet:
go vet ./...
lint
:
which golint
||
go
get
-u
golang.org/x/lint/golint
which golint
||
go
install
golang.org/x/lint/golint
@latest
go list ./... |
grep
-v
/vendor/ | xargs
-L1
golint
-set_exit_status
staticcheck
:
.PHONY
...
...
This diff is collapsed.
Click to expand it.
auth/auth.go
+
41
−
2
View file @
89957e70
...
...
@@ -4,22 +4,53 @@ import "errors"
// Auther is a generic interface to implement password-based authentication and authorization
type
Auther
interface
{
Authenticate
(
user
,
pass
string
)
(
*
User
,
error
)
// Authenticate checks username and password and returns a user if correct. The method
// returns in constant-ish time, regardless of whether the user exists or the password is
// correct or incorrect.
Authenticate
(
username
,
password
string
)
(
*
User
,
error
)
// Authorize returns nil if the given user has access to the given topic using the desired
// permission. The user param may be nil to signal an anonymous user.
Authorize
(
user
*
User
,
topic
string
,
perm
Permission
)
error
}
// Manager is an interface representing user and access management
type
Manager
interface
{
// AddUser adds a user with the given username, password and role. The password should be hashed
// before it is stored in a persistence layer.
AddUser
(
username
,
password
string
,
role
Role
)
error
// RemoveUser deletes the user with the given username. The function returns nil on success, even
// if the user did not exist in the first place.
RemoveUser
(
username
string
)
error
// Users returns a list of users. It always also returns the Everyone user ("*").
Users
()
([]
*
User
,
error
)
// User returns the user with the given username if it exists, or ErrNotFound otherwise.
// You may also pass Everyone to retrieve the anonymous user and its Grant list.
User
(
username
string
)
(
*
User
,
error
)
// ChangePassword changes a user's password
ChangePassword
(
username
,
password
string
)
error
// ChangeRole changes a user's role. When a role is changed from RoleUser to RoleAdmin,
// all existing access control entries (Grant) are removed, since they are no longer needed.
ChangeRole
(
username
string
,
role
Role
)
error
DefaultAccess
()
(
read
bool
,
write
bool
)
// AllowAccess adds or updates an entry in th access control list for a specific user. It controls
// read/write access to a topic.
AllowAccess
(
username
string
,
topic
string
,
read
bool
,
write
bool
)
error
// ResetAccess removes an access control list entry for a specific username/topic, or (if topic is
// empty) for an entire user.
ResetAccess
(
username
string
,
topic
string
)
error
// DefaultAccess returns the default read/write access if no access control entry matches
DefaultAccess
()
(
read
bool
,
write
bool
)
}
// User is a struct that represents a user
type
User
struct
{
Name
string
Hash
string
// password hash (bcrypt)
...
...
@@ -27,35 +58,43 @@ type User struct {
Grants
[]
Grant
}
// Grant is a struct that represents an access control entry to a topic
type
Grant
struct
{
Topic
string
Read
bool
Write
bool
}
// Permission represents a read or write permission to a topic
type
Permission
int
// Permissions to a topic
const
(
PermissionRead
=
Permission
(
1
)
PermissionWrite
=
Permission
(
2
)
)
// Role represents a user's role, either admin or regular user
type
Role
string
// User roles
const
(
RoleAdmin
=
Role
(
"admin"
)
RoleUser
=
Role
(
"user"
)
RoleAnonymous
=
Role
(
"anonymous"
)
)
// Everyone is a special username representing anonymous users
const
(
Everyone
=
"*"
)
// AllowedRole returns true if the given role can be used for new users
func
AllowedRole
(
role
Role
)
bool
{
return
role
==
RoleUser
||
role
==
RoleAdmin
}
// Error constants used by the package
var
(
ErrUnauthenticated
=
errors
.
New
(
"unauthenticated"
)
ErrUnauthorized
=
errors
.
New
(
"unauthorized"
)
...
...
This diff is collapsed.
Click to expand it.
auth/auth_sqlite.go
+
32
−
9
View file @
89957e70
...
...
@@ -61,6 +61,8 @@ const (
deleteTopicAccessQuery
=
`DELETE FROM access WHERE user = ? AND topic = ?`
)
// SQLiteAuth is an implementation of Auther and Manager. It stores users and access control list
// in a SQLite database.
type
SQLiteAuth
struct
{
db
*
sql
.
DB
defaultRead
bool
...
...
@@ -74,6 +76,7 @@ var (
var
_
Auther
=
(
*
SQLiteAuth
)(
nil
)
var
_
Manager
=
(
*
SQLiteAuth
)(
nil
)
// NewSQLiteAuth creates a new SQLiteAuth instance
func
NewSQLiteAuth
(
filename
string
,
defaultRead
,
defaultWrite
bool
)
(
*
SQLiteAuth
,
error
)
{
db
,
err
:=
sql
.
Open
(
"sqlite3"
,
filename
)
if
err
!=
nil
{
...
...
@@ -97,6 +100,9 @@ func setupNewAuthDB(db *sql.DB) error {
return
nil
}
// Authenticate checks username and password and returns a user if correct. The method
// returns in constant-ish time, regardless of whether the user exists or the password is
// correct or incorrect.
func
(
a
*
SQLiteAuth
)
Authenticate
(
username
,
password
string
)
(
*
User
,
error
)
{
if
username
==
Everyone
{
return
nil
,
ErrUnauthenticated
...
...
@@ -113,17 +119,19 @@ func (a *SQLiteAuth) Authenticate(username, password string) (*User, error) {
return
user
,
nil
}
// Authorize returns nil if the given user has access to the given topic using the desired
// permission. The user param may be nil to signal an anonymous user.
func
(
a
*
SQLiteAuth
)
Authorize
(
user
*
User
,
topic
string
,
perm
Permission
)
error
{
if
user
!=
nil
&&
user
.
Role
==
RoleAdmin
{
return
nil
// Admin can do everything
}
// Select the read/write permissions for this user/topic combo. The query may return two
// rows (one for everyone, and one for the user), but prioritizes the user. The value for
// user.Name may be empty (= everyone).
username
:=
Everyone
if
user
!=
nil
{
username
=
user
.
Name
}
// Select the read/write permissions for this user/topic combo. The query may return two
// rows (one for everyone, and one for the user), but prioritizes the user. The value for
// user.Name may be empty (= everyone).
rows
,
err
:=
a
.
db
.
Query
(
selectTopicPermsQuery
,
username
,
topic
)
if
err
!=
nil
{
return
err
...
...
@@ -150,8 +158,10 @@ func (a *SQLiteAuth) resolvePerms(read, write bool, perm Permission) error {
return
ErrUnauthorized
}
// AddUser adds a user with the given username, password and role. The password should be hashed
// before it is stored in a persistence layer.
func
(
a
*
SQLiteAuth
)
AddUser
(
username
,
password
string
,
role
Role
)
error
{
if
!
allowedUsernameRegex
.
MatchString
(
username
)
||
(
role
!=
RoleAdmin
&&
role
!=
RoleUser
)
{
if
!
allowedUsernameRegex
.
MatchString
(
username
)
||
!
AllowedRole
(
role
)
{
return
ErrInvalidArgument
}
hash
,
err
:=
bcrypt
.
GenerateFromPassword
([]
byte
(
password
),
bcryptCost
)
...
...
@@ -164,6 +174,8 @@ func (a *SQLiteAuth) AddUser(username, password string, role Role) error {
return
nil
}
// RemoveUser deletes the user with the given username. The function returns nil on success, even
// if the user did not exist in the first place.
func
(
a
*
SQLiteAuth
)
RemoveUser
(
username
string
)
error
{
if
!
allowedUsernameRegex
.
MatchString
(
username
)
||
username
==
Everyone
{
return
ErrInvalidArgument
...
...
@@ -177,6 +189,7 @@ func (a *SQLiteAuth) RemoveUser(username string) error {
return
nil
}
// Users returns a list of users. It always also returns the Everyone user ("*").
func
(
a
*
SQLiteAuth
)
Users
()
([]
*
User
,
error
)
{
rows
,
err
:=
a
.
db
.
Query
(
selectUsernamesQuery
)
if
err
!=
nil
{
...
...
@@ -210,6 +223,8 @@ func (a *SQLiteAuth) Users() ([]*User, error) {
return
users
,
nil
}
// User returns the user with the given username if it exists, or ErrNotFound otherwise.
// You may also pass Everyone to retrieve the anonymous user and its Grant list.
func
(
a
*
SQLiteAuth
)
User
(
username
string
)
(
*
User
,
error
)
{
if
username
==
Everyone
{
return
a
.
everyoneUser
()
...
...
@@ -277,6 +292,7 @@ func (a *SQLiteAuth) readGrants(username string) ([]Grant, error) {
return
grants
,
nil
}
// ChangePassword changes a user's password
func
(
a
*
SQLiteAuth
)
ChangePassword
(
username
,
password
string
)
error
{
hash
,
err
:=
bcrypt
.
GenerateFromPassword
([]
byte
(
password
),
bcryptCost
)
if
err
!=
nil
{
...
...
@@ -288,8 +304,10 @@ func (a *SQLiteAuth) ChangePassword(username, password string) error {
return
nil
}
// ChangeRole changes a user's role. When a role is changed from RoleUser to RoleAdmin,
// all existing access control entries (Grant) are removed, since they are no longer needed.
func
(
a
*
SQLiteAuth
)
ChangeRole
(
username
string
,
role
Role
)
error
{
if
!
allowedUsernameRegex
.
MatchString
(
username
)
||
(
role
!=
RoleAdmin
&&
role
!=
RoleUser
)
{
if
!
allowedUsernameRegex
.
MatchString
(
username
)
||
!
AllowedRole
(
role
)
{
return
ErrInvalidArgument
}
if
_
,
err
:=
a
.
db
.
Exec
(
updateUserRoleQuery
,
string
(
role
),
username
);
err
!=
nil
{
...
...
@@ -303,10 +321,8 @@ func (a *SQLiteAuth) ChangeRole(username string, role Role) error {
return
nil
}
func
(
a
*
SQLiteAuth
)
DefaultAccess
()
(
read
bool
,
write
bool
)
{
return
a
.
defaultRead
,
a
.
defaultWrite
}
// AllowAccess adds or updates an entry in th access control list for a specific user. It controls
// read/write access to a topic.
func
(
a
*
SQLiteAuth
)
AllowAccess
(
username
string
,
topic
string
,
read
bool
,
write
bool
)
error
{
if
_
,
err
:=
a
.
db
.
Exec
(
upsertUserAccessQuery
,
username
,
topic
,
read
,
write
);
err
!=
nil
{
return
err
...
...
@@ -314,6 +330,8 @@ func (a *SQLiteAuth) AllowAccess(username string, topic string, read bool, write
return
nil
}
// ResetAccess removes an access control list entry for a specific username/topic, or (if topic is
// empty) for an entire user.
func
(
a
*
SQLiteAuth
)
ResetAccess
(
username
string
,
topic
string
)
error
{
if
username
==
""
&&
topic
==
""
{
_
,
err
:=
a
.
db
.
Exec
(
deleteAllAccessQuery
,
username
)
...
...
@@ -325,3 +343,8 @@ func (a *SQLiteAuth) ResetAccess(username string, topic string) error {
_
,
err
:=
a
.
db
.
Exec
(
deleteTopicAccessQuery
,
username
,
topic
)
return
err
}
// DefaultAccess returns the default read/write access if no access control entry matches
func
(
a
*
SQLiteAuth
)
DefaultAccess
()
(
read
bool
,
write
bool
)
{
return
a
.
defaultRead
,
a
.
defaultWrite
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment