fix(server): internal key should have admin access

Ayman Bagabas created

Change summary

server/backend/sqlite/sqlite.go |  7 +++----
server/backend/sqlite/user.go   |  5 ++++-
server/config/config.go         |  6 ++++++
server/server.go                |  8 ++++----
server/ssh.go                   | 11 ++++-------
5 files changed, 21 insertions(+), 16 deletions(-)

Detailed changes

server/backend/sqlite/sqlite.go 🔗

@@ -26,10 +26,9 @@ var (
 // SqliteBackend is a backend that uses a SQLite database as a Soft Serve
 // backend.
 type SqliteBackend struct {
-	cfg              *config.Config
-	dp               string
-	db               *sqlx.DB
-	AdditionalAdmins []string
+	cfg *config.Config
+	dp  string
+	db  *sqlx.DB
 }
 
 var _ backend.Backend = (*SqliteBackend)(nil)

server/backend/sqlite/user.go 🔗

@@ -120,7 +120,10 @@ func (d *SqliteBackend) AccessLevel(repo string, username string) backend.Access
 // It implements backend.Backend.
 func (d *SqliteBackend) AccessLevelByPublicKey(repo string, pk ssh.PublicKey) backend.AccessLevel {
 	ak := backend.MarshalAuthorizedKey(pk)
-	for _, k := range d.AdditionalAdmins {
+	if strings.HasPrefix(d.cfg.InternalPublicKey, ak) {
+		return backend.AdminAccess
+	}
+	for _, k := range d.cfg.InitialAdminKeys {
 		if k == ak {
 			return backend.AdminAccess
 		}

server/config/config.go 🔗

@@ -95,6 +95,12 @@ type Config struct {
 
 	// Backend is the Git backend to use.
 	Backend backend.Backend `yaml:"-"`
+
+	// InternalPublicKey is the public key of the internal SSH key.
+	InternalPublicKey string `yaml:"-"`
+
+	// ClientPublicKey is the public key of the client SSH key.
+	ClientPublicKey string `yaml:"-"`
 }
 
 // ParseConfig parses the configuration from the given file.

server/server.go 🔗

@@ -45,12 +45,10 @@ func NewServer(cfg *config.Config) (*Server, error) {
 			logger.Fatal(err)
 		}
 
-		// Add the initial admin keys to the list of admins.
-		sb.AdditionalAdmins = cfg.InitialAdminKeys
 		cfg = cfg.WithBackend(sb)
 
 		// Create internal key.
-		_, err = keygen.NewWithWrite(
+		ikp, err := keygen.NewWithWrite(
 			filepath.Join(cfg.DataPath, cfg.SSH.InternalKeyPath),
 			nil,
 			keygen.Ed25519,
@@ -58,9 +56,10 @@ func NewServer(cfg *config.Config) (*Server, error) {
 		if err != nil {
 			return nil, err
 		}
+		cfg.InternalPublicKey = string(ikp.PublicKey())
 
 		// Create client key.
-		_, err = keygen.NewWithWrite(
+		ckp, err := keygen.NewWithWrite(
 			filepath.Join(cfg.DataPath, cfg.SSH.ClientKeyPath),
 			nil,
 			keygen.Ed25519,
@@ -68,6 +67,7 @@ func NewServer(cfg *config.Config) (*Server, error) {
 		if err != nil {
 			return nil, err
 		}
+		cfg.ClientPublicKey = string(ckp.PublicKey())
 	}
 
 	srv := &Server{

server/ssh.go 🔗

@@ -148,13 +148,9 @@ func (s *SSHServer) PublicKeyHandler(ctx ssh.Context, pk ssh.PublicKey) (allowed
 		}
 	}
 
-	user, _ := s.cfg.Backend.UserByPublicKey(pk)
-	if user == nil {
-		logger.Debug("public key auth user not found")
-		return s.cfg.Backend.AnonAccess() >= backend.ReadOnlyAccess
-	}
-
-	allowed = s.cfg.Backend.AccessLevel("", user.Username()) >= backend.ReadOnlyAccess
+	ac := s.cfg.Backend.AccessLevelByPublicKey("", pk)
+	logger.Debugf("access level for %s: %d", ak, ac)
+	allowed = ac >= backend.ReadOnlyAccess
 	return
 }
 
@@ -191,6 +187,7 @@ func (s *SSHServer) Middleware(cfg *config.Config) wish.Middleware {
 						return
 					}
 
+					logger.Debug("git middleware", "cmd", gc, "access", access.String())
 					repoDir := filepath.Join(reposDir, repo)
 					switch gc {
 					case receivePackBin: