auth.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. package auth
  2. import (
  3. "errors"
  4. "regexp"
  5. )
  6. // Auther is a generic interface to implement password-based authentication and authorization
  7. type Auther interface {
  8. // Authenticate checks username and password and returns a user if correct. The method
  9. // returns in constant-ish time, regardless of whether the user exists or the password is
  10. // correct or incorrect.
  11. Authenticate(username, password string) (*User, error)
  12. // Authorize returns nil if the given user has access to the given topic using the desired
  13. // permission. The user param may be nil to signal an anonymous user.
  14. Authorize(user *User, topic string, perm Permission) error
  15. }
  16. // Manager is an interface representing user and access management
  17. type Manager interface {
  18. // AddUser adds a user with the given username, password and role. The password should be hashed
  19. // before it is stored in a persistence layer.
  20. AddUser(username, password string, role Role) error
  21. // RemoveUser deletes the user with the given username. The function returns nil on success, even
  22. // if the user did not exist in the first place.
  23. RemoveUser(username string) error
  24. // Users returns a list of users. It always also returns the Everyone user ("*").
  25. Users() ([]*User, error)
  26. // User returns the user with the given username if it exists, or ErrNotFound otherwise.
  27. // You may also pass Everyone to retrieve the anonymous user and its Grant list.
  28. User(username string) (*User, error)
  29. // ChangePassword changes a user's password
  30. ChangePassword(username, password string) error
  31. // ChangeRole changes a user's role. When a role is changed from RoleUser to RoleAdmin,
  32. // all existing access control entries (Grant) are removed, since they are no longer needed.
  33. ChangeRole(username string, role Role) error
  34. // AllowAccess adds or updates an entry in th access control list for a specific user. It controls
  35. // read/write access to a topic. The parameter topicPattern may include wildcards (*).
  36. AllowAccess(username string, topicPattern string, read bool, write bool) error
  37. // ResetAccess removes an access control list entry for a specific username/topic, or (if topic is
  38. // empty) for an entire user. The parameter topicPattern may include wildcards (*).
  39. ResetAccess(username string, topicPattern string) error
  40. // DefaultAccess returns the default read/write access if no access control entry matches
  41. DefaultAccess() (read bool, write bool)
  42. }
  43. // User is a struct that represents a user
  44. type User struct {
  45. Name string
  46. Hash string // password hash (bcrypt)
  47. Role Role
  48. Grants []Grant
  49. }
  50. // Grant is a struct that represents an access control entry to a topic
  51. type Grant struct {
  52. Topic string
  53. Read bool
  54. Write bool
  55. }
  56. // Permission represents a read or write permission to a topic
  57. type Permission int
  58. // Permissions to a topic
  59. const (
  60. PermissionRead = Permission(1)
  61. PermissionWrite = Permission(2)
  62. )
  63. // Role represents a user's role, either admin or regular user
  64. type Role string
  65. // User roles
  66. const (
  67. RoleAdmin = Role("admin")
  68. RoleUser = Role("user")
  69. RoleAnonymous = Role("anonymous")
  70. )
  71. // Everyone is a special username representing anonymous users
  72. const (
  73. Everyone = "*"
  74. )
  75. var (
  76. allowedUsernameRegex = regexp.MustCompile(`^[-_.@a-zA-Z0-9]+$`) // Does not include Everyone (*)
  77. allowedTopicPatternRegex = regexp.MustCompile(`^[-_*A-Za-z0-9]{1,64}$`) // Adds '*' for wildcards!
  78. )
  79. // AllowedRole returns true if the given role can be used for new users
  80. func AllowedRole(role Role) bool {
  81. return role == RoleUser || role == RoleAdmin
  82. }
  83. // AllowedUsername returns true if the given username is valid
  84. func AllowedUsername(username string) bool {
  85. return allowedUsernameRegex.MatchString(username)
  86. }
  87. // AllowedTopicPattern returns true if the given topic pattern is valid; this includes the wildcard character (*)
  88. func AllowedTopicPattern(username string) bool {
  89. return allowedTopicPatternRegex.MatchString(username)
  90. }
  91. // Error constants used by the package
  92. var (
  93. ErrUnauthenticated = errors.New("unauthenticated")
  94. ErrUnauthorized = errors.New("unauthorized")
  95. ErrInvalidArgument = errors.New("invalid argument")
  96. ErrNotFound = errors.New("not found")
  97. )