diff --git a/gen/go/v1/config.pb.go b/gen/go/v1/config.pb.go
index 050d59c7..d2d92990 100644
--- a/gen/go/v1/config.pb.go
+++ b/gen/go/v1/config.pb.go
@@ -761,7 +761,8 @@ type Auth struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
- Users []*User `protobuf:"bytes,2,rep,name=users,proto3" json:"users,omitempty"` // users to allow access to the UI.
+ Disabled bool `protobuf:"varint,1,opt,name=disabled,proto3" json:"disabled,omitempty"` // disable authentication.
+ Users []*User `protobuf:"bytes,2,rep,name=users,proto3" json:"users,omitempty"` // users to allow access to the UI.
}
func (x *Auth) Reset() {
@@ -796,6 +797,13 @@ func (*Auth) Descriptor() ([]byte, []int) {
return file_v1_config_proto_rawDescGZIP(), []int{6}
}
+func (x *Auth) GetDisabled() bool {
+ if x != nil {
+ return x.Disabled
+ }
+ return false
+}
+
func (x *Auth) GetUsers() []*User {
if x != nil {
return x.Users
@@ -1384,18 +1392,20 @@ var file_v1_config_proto_rawDesc = []byte{
0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x4e, 0x41, 0x50, 0x53, 0x48, 0x4f, 0x54, 0x5f, 0x45, 0x4e,
0x44, 0x10, 0x03, 0x12, 0x1c, 0x0a, 0x18, 0x43, 0x4f, 0x4e, 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e,
0x5f, 0x53, 0x4e, 0x41, 0x50, 0x53, 0x48, 0x4f, 0x54, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10,
- 0x04, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x26, 0x0a, 0x04, 0x41,
- 0x75, 0x74, 0x68, 0x12, 0x1e, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03,
- 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05, 0x75, 0x73,
- 0x65, 0x72, 0x73, 0x22, 0x51, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e,
- 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12,
- 0x29, 0x0a, 0x0f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x62, 0x63, 0x72, 0x79,
- 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0e, 0x70, 0x61, 0x73, 0x73,
- 0x77, 0x6f, 0x72, 0x64, 0x42, 0x63, 0x72, 0x79, 0x70, 0x74, 0x42, 0x0a, 0x0a, 0x08, 0x70, 0x61,
- 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
- 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x72, 0x65, 0x74, 0x68, 0x67, 0x65, 0x6f, 0x72, 0x67,
- 0x65, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x72, 0x65, 0x73, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67,
- 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x04, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x42, 0x0a, 0x04, 0x41,
+ 0x75, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12,
+ 0x1e, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08,
+ 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x22,
+ 0x51, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x29, 0x0a, 0x0f, 0x70,
+ 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x62, 0x63, 0x72, 0x79, 0x70, 0x74, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0e, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64,
+ 0x42, 0x63, 0x72, 0x79, 0x70, 0x74, 0x42, 0x0a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f,
+ 0x72, 0x64, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x2f, 0x67, 0x61, 0x72, 0x65, 0x74, 0x68, 0x67, 0x65, 0x6f, 0x72, 0x67, 0x65, 0x2f, 0x62, 0x61,
+ 0x63, 0x6b, 0x72, 0x65, 0x73, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x31,
+ 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/internal/auth/auth.go b/internal/auth/auth.go
index 3d4307ca..cc8cb911 100644
--- a/internal/auth/auth.go
+++ b/internal/auth/auth.go
@@ -12,21 +12,24 @@ import (
"golang.org/x/crypto/bcrypt"
)
-var defaultUsers = []*v1.User{
- {
+var (
+ anonymousUser = &v1.User{
Name: "default",
Password: &v1.User_PasswordBcrypt{PasswordBcrypt: "JDJhJDEwJDNCdzJoNFlhaWFZQy9TSDN3ZGxSRHVPZHdzV2lsNmtBSHdFSmtIWHk1dS8wYjZuUWJrMGFx"}, // default password is "password"
- },
-}
+ }
+ defaultUsers = []*v1.User{
+ anonymousUser,
+ }
+)
type Authenticator struct {
config config.ConfigStore
key []byte
}
-func NewAuthenticator(key []byte, configProvider config.ConfigStore) *Authenticator {
+func NewAuthenticator(key []byte, config config.ConfigStore) *Authenticator {
return &Authenticator{
- config: configProvider,
+ config: config,
key: key,
}
}
@@ -34,19 +37,17 @@ func NewAuthenticator(key []byte, configProvider config.ConfigStore) *Authentica
var ErrUserNotFound = errors.New("user not found")
var ErrInvalidPassword = errors.New("invalid password")
-func (a *Authenticator) users() []*v1.User {
+func (a *Authenticator) Login(username, password string) (*v1.User, error) {
config, err := a.config.Get()
if err != nil {
- return nil
+ return nil, fmt.Errorf("get config: %w", err)
}
- if len(config.Auth.GetUsers()) != 0 {
- return config.Auth.GetUsers()
+ auth := config.GetAuth()
+ if auth.GetDisabled() {
+ return nil, errors.New("authentication is disabled")
}
- return defaultUsers
-}
-func (a *Authenticator) Login(username, password string) (*v1.User, error) {
- for _, user := range a.users() {
+ for _, user := range auth.GetUsers() {
if user.Name != username {
continue
}
@@ -62,6 +63,15 @@ func (a *Authenticator) Login(username, password string) (*v1.User, error) {
}
func (a *Authenticator) VerifyJWT(token string) (*v1.User, error) {
+ config, err := a.config.Get()
+ if err != nil {
+ return nil, fmt.Errorf("get config: %w", err)
+ }
+ auth := config.GetAuth()
+ if auth == nil {
+ return nil, fmt.Errorf("auth config not set")
+ }
+
t, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {
return a.key, nil
})
@@ -78,7 +88,7 @@ func (a *Authenticator) VerifyJWT(token string) (*v1.User, error) {
return nil, fmt.Errorf("get subject: %w", err)
}
- for _, user := range a.users() {
+ for _, user := range auth.GetUsers() {
if user.Name == subject {
return user, nil
}
diff --git a/internal/auth/middleware.go b/internal/auth/middleware.go
index 22ce652b..8452c4ed 100644
--- a/internal/auth/middleware.go
+++ b/internal/auth/middleware.go
@@ -17,6 +17,16 @@ const UserContextKey contextKey = "user"
func RequireAuthentication(h http.Handler, auth *Authenticator) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ config, err := auth.config.Get()
+ if err != nil {
+ zap.S().Errorf("auth middleware failed to get config: %v", err)
+ http.Error(w, "Internal Server Error", http.StatusInternalServerError)
+ return
+ }
+ if config.GetAuth() == nil || config.GetAuth().GetDisabled() {
+ h.ServeHTTP(w, r)
+ return
+ }
username, password, usesBasicAuth := r.BasicAuth()
if usesBasicAuth {
diff --git a/proto/v1/config.proto b/proto/v1/config.proto
index e2b0ce11..cd752fce 100644
--- a/proto/v1/config.proto
+++ b/proto/v1/config.proto
@@ -120,6 +120,7 @@ message Hook {
}
message Auth {
+ bool disabled = 1 [json_name="disabled"]; // disable authentication.
repeated User users = 2 [json_name="users"]; // users to allow access to the UI.
}
diff --git a/webui/gen/ts/v1/authentication_connect.ts b/webui/gen/ts/v1/authentication_connect.ts
index 3b3e83be..bc813d13 100644
--- a/webui/gen/ts/v1/authentication_connect.ts
+++ b/webui/gen/ts/v1/authentication_connect.ts
@@ -1,4 +1,4 @@
-// @generated by protoc-gen-connect-es v1.3.0 with parameter "target=ts"
+// @generated by protoc-gen-connect-es v1.2.0 with parameter "target=ts"
// @generated from file v1/authentication.proto (package v1, syntax proto3)
/* eslint-disable */
// @ts-nocheck
diff --git a/webui/gen/ts/v1/config_pb.ts b/webui/gen/ts/v1/config_pb.ts
index c8788f60..18c37df4 100644
--- a/webui/gen/ts/v1/config_pb.ts
+++ b/webui/gen/ts/v1/config_pb.ts
@@ -876,6 +876,13 @@ export class Hook_Slack extends Message