summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Drozdov <idrozdov@gitlab.com>2023-01-23 07:54:09 +0000
committerIgor Drozdov <idrozdov@gitlab.com>2023-01-23 07:54:09 +0000
commit7750f56e0c42d619b2a6354d99601d4b4f311867 (patch)
treee65f58f98c8bb075427ae16aee548410afebeb96
parentad172bf0c9688238bc014d2ded2b181ae0b6e45a (diff)
parent51ea0f50f52d5d1dade02aadff3c163a0a792779 (diff)
downloadgitlab-shell-7750f56e0c42d619b2a6354d99601d4b4f311867.tar.gz
Merge branch '196-add-kerberos-support' into 'main'
Add support for the gssapi-with-mic auth method Closes #196 See merge request https://gitlab.com/gitlab-org/gitlab-shell/-/merge_requests/682 Merged-by: Igor Drozdov <idrozdov@gitlab.com> Approved-by: Alejandro Rodríguez <alejandro@gitlab.com> Approved-by: Patrick Bajao <ebajao@gitlab.com> Approved-by: Costel Maxim <cmaxim@gitlab.com> Approved-by: Igor Drozdov <idrozdov@gitlab.com> Reviewed-by: Alejandro Rodríguez <alejandro@gitlab.com> Reviewed-by: Igor Drozdov <idrozdov@gitlab.com> Reviewed-by: Patrick Bajao <ebajao@gitlab.com> Reviewed-by: Rohit Shambhuni <rshambhuni@gitlab.com> Co-authored-by: Lee Tickett <ltickett@gitlab.com> Co-authored-by: Marin Hannache <git@mareo.fr>
-rw-r--r--cmd/gitlab-shell/command/command.go14
-rw-r--r--cmd/gitlab-sshd/main.go2
-rw-r--r--config.yml.example8
-rw-r--r--go.mod1
-rw-r--r--go.sum2
-rw-r--r--internal/command/commandargs/shell.go13
-rw-r--r--internal/config/config.go8
-rw-r--r--internal/gitlabnet/accessverifier/client.go17
-rw-r--r--internal/gitlabnet/accessverifier/client_test.go10
-rw-r--r--internal/gitlabnet/discover/client.go2
-rw-r--r--internal/gitlabnet/discover/client_test.go17
-rw-r--r--internal/sshd/gssapi.go142
-rw-r--r--internal/sshd/gssapi_test.go27
-rw-r--r--internal/sshd/server_config.go23
-rw-r--r--internal/sshd/server_config_test.go46
-rw-r--r--internal/sshd/session.go19
-rw-r--r--internal/sshd/session_test.go36
-rw-r--r--internal/sshd/sshd.go11
18 files changed, 359 insertions, 39 deletions
diff --git a/cmd/gitlab-shell/command/command.go b/cmd/gitlab-shell/command/command.go
index 08b3af6..b2a0266 100644
--- a/cmd/gitlab-shell/command/command.go
+++ b/cmd/gitlab-shell/command/command.go
@@ -44,6 +44,20 @@ func NewWithKey(gitlabKeyId string, env sshenv.Env, config *config.Config, readW
return nil, disallowedcommand.Error
}
+func NewWithKrb5Principal(gitlabKrb5Principal string, env sshenv.Env, config *config.Config, readWriter *readwriter.ReadWriter) (command.Command, error) {
+ args, err := Parse(nil, env)
+ if err != nil {
+ return nil, err
+ }
+
+ args.GitlabKrb5Principal = gitlabKrb5Principal
+ if cmd := Build(args, config, readWriter); cmd != nil {
+ return cmd, nil
+ }
+
+ return nil, disallowedcommand.Error
+}
+
func Parse(arguments []string, env sshenv.Env) (*commandargs.Shell, error) {
args := &commandargs.Shell{Arguments: arguments, Env: env}
diff --git a/cmd/gitlab-sshd/main.go b/cmd/gitlab-sshd/main.go
index 330c25f..bc931f6 100644
--- a/cmd/gitlab-sshd/main.go
+++ b/cmd/gitlab-sshd/main.go
@@ -71,6 +71,8 @@ func main() {
cfg.GitalyClient.InitSidechannelRegistry(ctx)
+ sshd.LoadGSSAPILib(&cfg.Server.GSSAPI)
+
server, err := sshd.NewServer(cfg)
if err != nil {
log.WithError(err).Fatal("Failed to start GitLab built-in sshd")
diff --git a/config.yml.example b/config.yml.example
index 0154723..886fde0 100644
--- a/config.yml.example
+++ b/config.yml.example
@@ -107,3 +107,11 @@ sshd:
- /run/secrets/ssh-hostkeys/ssh_host_rsa_key-cert.pub
- /run/secrets/ssh-hostkeys/ssh_host_ecdsa_key-cert.pub
- /run/secrets/ssh-hostkeys/ssh_host_ed25519_key-cert.pub
+ # GSSAPI-related settings
+ gssapi:
+ # Enable the gssapi-with-mic authentication method. Defaults to false.
+ enabled: false
+ # Keytab path. Defaults to "", system default (usually /etc/krb5.keytab).
+ keytab: ""
+ # The Kerberos service name to be used by sshd. Defaults to "", accepts any service name in keytab file.
+ service_principal_name: ""
diff --git a/go.mod b/go.mod
index 4a1a5cf..14bde1c 100644
--- a/go.mod
+++ b/go.mod
@@ -9,6 +9,7 @@ require (
github.com/hashicorp/go-retryablehttp v0.7.1
github.com/mattn/go-shellwords v1.0.11
github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a
+ github.com/openshift/gssapi v0.0.0-20161010215902-5fb4217df13b
github.com/otiai10/copy v1.4.2
github.com/pires/go-proxyproto v0.6.2
github.com/prometheus/client_golang v1.13.1
diff --git a/go.sum b/go.sum
index 468372d..bc9a6b5 100644
--- a/go.sum
+++ b/go.sum
@@ -277,6 +277,8 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
+github.com/openshift/gssapi v0.0.0-20161010215902-5fb4217df13b h1:it0YPE/evO6/m8t8wxis9KFI2F/aleOKsI6d9uz0cEk=
+github.com/openshift/gssapi v0.0.0-20161010215902-5fb4217df13b/go.mod h1:tNrEB5k8SI+g5kOlsCmL2ELASfpqEofI0+FLBgBdN08=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
diff --git a/internal/command/commandargs/shell.go b/internal/command/commandargs/shell.go
index 0b1e161..616d7e3 100644
--- a/internal/command/commandargs/shell.go
+++ b/internal/command/commandargs/shell.go
@@ -26,12 +26,13 @@ var (
)
type Shell struct {
- Arguments []string
- GitlabUsername string
- GitlabKeyId string
- SshArgs []string
- CommandType CommandType
- Env sshenv.Env
+ Arguments []string
+ GitlabUsername string
+ GitlabKeyId string
+ GitlabKrb5Principal string
+ SshArgs []string
+ CommandType CommandType
+ Env sshenv.Env
}
func (s *Shell) Parse() error {
diff --git a/internal/config/config.go b/internal/config/config.go
index b52f6f7..207517b 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -23,6 +23,13 @@ const (
type YamlDuration time.Duration
+type GSSAPIConfig struct {
+ Enabled bool `yaml:"enabled,omitempty"`
+ Keytab string `yaml:"keytab,omitempty"`
+ ServicePrincipalName string `yaml:"service_principal_name,omitempty"`
+ LibPath string
+}
+
type ServerConfig struct {
Listen string `yaml:"listen,omitempty"`
ProxyProtocol bool `yaml:"proxy_protocol,omitempty"`
@@ -41,6 +48,7 @@ type ServerConfig struct {
MACs []string `yaml:"macs"`
KexAlgorithms []string `yaml:"kex_algorithms"`
Ciphers []string `yaml:"ciphers"`
+ GSSAPI GSSAPIConfig `yaml:"gssapi,omitempty"`
}
type HttpSettingsConfig struct {
diff --git a/internal/gitlabnet/accessverifier/client.go b/internal/gitlabnet/accessverifier/client.go
index ca81ad1..8554d9b 100644
--- a/internal/gitlabnet/accessverifier/client.go
+++ b/internal/gitlabnet/accessverifier/client.go
@@ -22,13 +22,14 @@ type Client struct {
}
type Request struct {
- Action commandargs.CommandType `json:"action"`
- Repo string `json:"project"`
- Changes string `json:"changes"`
- Protocol string `json:"protocol"`
- KeyId string `json:"key_id,omitempty"`
- Username string `json:"username,omitempty"`
- CheckIp string `json:"check_ip,omitempty"`
+ Action commandargs.CommandType `json:"action"`
+ Repo string `json:"project"`
+ Changes string `json:"changes"`
+ Protocol string `json:"protocol"`
+ KeyId string `json:"key_id,omitempty"`
+ Username string `json:"username,omitempty"`
+ Krb5Principal string `json:"krb5principal,omitempty"`
+ CheckIp string `json:"check_ip,omitempty"`
}
type Gitaly struct {
@@ -81,6 +82,8 @@ func (c *Client) Verify(ctx context.Context, args *commandargs.Shell, action com
if args.GitlabUsername != "" {
request.Username = args.GitlabUsername
+ } else if args.GitlabKrb5Principal != "" {
+ request.Krb5Principal = args.GitlabKrb5Principal
} else {
request.KeyId = args.GitlabKeyId
}
diff --git a/internal/gitlabnet/accessverifier/client_test.go b/internal/gitlabnet/accessverifier/client_test.go
index 6a187f2..f2c88a5 100644
--- a/internal/gitlabnet/accessverifier/client_test.go
+++ b/internal/gitlabnet/accessverifier/client_test.go
@@ -56,7 +56,7 @@ func buildExpectedResponse(who string) *Response {
func TestSuccessfulResponses(t *testing.T) {
okResponse := testResponse{body: responseBody(t, "allowed.json"), status: http.StatusOK}
client := setup(t,
- map[string]testResponse{"first": okResponse},
+ map[string]testResponse{"first": okResponse, "test@TEST.TEST": okResponse},
map[string]testResponse{"1": okResponse},
)
@@ -73,6 +73,10 @@ func TestSuccessfulResponses(t *testing.T) {
desc: "Provide username within the request",
args: &commandargs.Shell{GitlabUsername: "first"},
who: "user-1",
+ }, {
+ desc: "Provide krb5principal within the request",
+ args: &commandargs.Shell{GitlabKrb5Principal: "test@TEST.TEST"},
+ who: "user-1",
},
}
@@ -255,6 +259,10 @@ func setup(t *testing.T, userResponses, keyResponses map[string]testResponse) *C
w.WriteHeader(tr.status)
_, err := w.Write(tr.body)
require.NoError(t, err)
+ } else if tr, ok := userResponses[requestBody.Krb5Principal]; ok {
+ w.WriteHeader(tr.status)
+ _, err := w.Write(tr.body)
+ require.NoError(t, err)
} else if tr, ok := keyResponses[requestBody.KeyId]; ok {
w.WriteHeader(tr.status)
_, err := w.Write(tr.body)
diff --git a/internal/gitlabnet/discover/client.go b/internal/gitlabnet/discover/client.go
index 1e7d33f..75b904b 100644
--- a/internal/gitlabnet/discover/client.go
+++ b/internal/gitlabnet/discover/client.go
@@ -38,6 +38,8 @@ func (c *Client) GetByCommandArgs(ctx context.Context, args *commandargs.Shell)
params.Add("username", args.GitlabUsername)
} else if args.GitlabKeyId != "" {
params.Add("key_id", args.GitlabKeyId)
+ } else if args.GitlabKrb5Principal != "" {
+ params.Add("krb5principal", args.GitlabKrb5Principal)
} else {
// There was no 'who' information, this matches the ruby error
// message.
diff --git a/internal/gitlabnet/discover/client_test.go b/internal/gitlabnet/discover/client_test.go
index 1506eba..6208fb2 100644
--- a/internal/gitlabnet/discover/client_test.go
+++ b/internal/gitlabnet/discover/client_test.go
@@ -38,6 +38,13 @@ func init() {
Name: "Jane Doe",
}
json.NewEncoder(w).Encode(body)
+ } else if r.URL.Query().Get("krb5principal") == "john-doe@TEST.TEST" {
+ body := &Response{
+ UserId: 3,
+ Username: "john-doe",
+ Name: "John Doe",
+ }
+ json.NewEncoder(w).Encode(body)
} else if r.URL.Query().Get("username") == "broken_message" {
w.WriteHeader(http.StatusForbidden)
body := &client.ErrorResponse{
@@ -76,6 +83,16 @@ func TestGetByUsername(t *testing.T) {
require.Equal(t, &Response{UserId: 1, Username: "jane-doe", Name: "Jane Doe"}, result)
}
+func TestGetByKrb5Principal(t *testing.T) {
+ client := setup(t)
+
+ params := url.Values{}
+ params.Add("krb5principal", "john-doe@TEST.TEST")
+ result, err := client.getResponse(context.Background(), params)
+ require.NoError(t, err)
+ require.Equal(t, &Response{UserId: 3, Username: "john-doe", Name: "John Doe"}, result)
+}
+
func TestMissingUser(t *testing.T) {
client := setup(t)
diff --git a/internal/sshd/gssapi.go b/internal/sshd/gssapi.go
new file mode 100644
index 0000000..bf65a15
--- /dev/null
+++ b/internal/sshd/gssapi.go
@@ -0,0 +1,142 @@
+package sshd
+
+import (
+ "fmt"
+
+ "github.com/openshift/gssapi"
+
+ "gitlab.com/gitlab-org/gitlab-shell/v14/internal/config"
+
+ "gitlab.com/gitlab-org/labkit/log"
+)
+
+var lib *gssapi.Lib
+
+func LoadGSSAPILib(config *config.GSSAPIConfig) error {
+ var err error
+
+ if config.Enabled {
+ options := &gssapi.Options{
+ Krb5Ktname: config.Keytab,
+ }
+
+ if config.LibPath != "" {
+ options.LibPath = config.LibPath
+ }
+
+ lib, err = gssapi.Load(options)
+
+ if err != nil {
+ log.WithError(err).Error("Unable to load GSSAPI library, gssapi-with-mic is disabled")
+ config.Enabled = false
+ }
+ }
+
+ return err
+}
+
+type OSGSSAPIServer struct {
+ Keytab string
+ ServicePrincipalName string
+
+ contextId *gssapi.CtxId
+}
+
+func (_ *OSGSSAPIServer) str2name(str string) (*gssapi.Name, error) {
+ strBuffer, err := lib.MakeBufferString(str)
+ if err != nil {
+ return nil, err
+ }
+ defer strBuffer.Release()
+
+ return strBuffer.Name(lib.GSS_C_NO_OID)
+}
+
+func (server *OSGSSAPIServer) AcceptSecContext(
+ token []byte,
+) (
+ outputToken []byte,
+ srcName string,
+ needContinue bool,
+ err error,
+) {
+ tokenBuffer, err := lib.MakeBufferBytes(token)
+ if err != nil {
+ return
+ }
+ defer tokenBuffer.Release()
+
+ var spn *gssapi.CredId = lib.GSS_C_NO_CREDENTIAL
+ if server.ServicePrincipalName != "" {
+ var name *gssapi.Name
+ name, err = server.str2name(server.ServicePrincipalName)
+ if err != nil {
+ return
+ }
+ defer name.Release()
+
+ var actualMech *gssapi.OIDSet
+ spn, actualMech, _, err = lib.AcquireCred(name, 0, lib.GSS_C_NO_OID_SET, gssapi.GSS_C_ACCEPT)
+ if err != nil {
+ return
+ }
+ defer spn.Release()
+ defer actualMech.Release()
+ }
+
+ ctxOut, srcNameName, _, outputTokenBuffer, _, _, _, err := lib.AcceptSecContext(
+ server.contextId,
+ spn,
+ tokenBuffer,
+ nil,
+ )
+ if err == gssapi.ErrContinueNeeded {
+ needContinue = true
+ err = nil
+ } else if err != nil {
+ return
+ }
+ defer outputTokenBuffer.Release()
+ defer srcNameName.Release()
+
+ outputToken = outputTokenBuffer.Bytes()
+ server.contextId = ctxOut
+
+ return outputToken, srcNameName.String(), needContinue, err
+}
+
+func (server *OSGSSAPIServer) VerifyMIC(
+ micField []byte,
+ micToken []byte,
+) error {
+ if server.contextId == nil {
+ return fmt.Errorf("gssapi: uninitialized contextId")
+ }
+
+ micFieldBuffer, err := lib.MakeBufferBytes(micField)
+ if err != nil {
+ return err
+ }
+ defer micFieldBuffer.Release()
+ micTokenBuffer, err := lib.MakeBufferBytes(micToken)
+ if err != nil {
+ return err
+ }
+ defer micTokenBuffer.Release()
+
+ _, err = server.contextId.VerifyMIC(micFieldBuffer, micTokenBuffer)
+ return err
+
+}
+
+func (server *OSGSSAPIServer) DeleteSecContext() error {
+ if server.contextId == nil {
+ return nil
+ }
+
+ err := server.contextId.DeleteSecContext()
+ if err == nil {
+ server.contextId = nil
+ }
+ return err
+}
diff --git a/internal/sshd/gssapi_test.go b/internal/sshd/gssapi_test.go
new file mode 100644
index 0000000..f4f19cf
--- /dev/null
+++ b/internal/sshd/gssapi_test.go
@@ -0,0 +1,27 @@
+package sshd
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "gitlab.com/gitlab-org/gitlab-shell/v14/internal/config"
+)
+
+func TestLoadGSSAPILibSucces(t *testing.T) {
+ config := &config.GSSAPIConfig{Enabled: true}
+ err := LoadGSSAPILib(config)
+
+ require.NotNil(t, lib)
+ require.Nil(t, err)
+ require.True(t, config.Enabled)
+}
+
+func TestLoadGSSAPILibFailure(t *testing.T) {
+ config := &config.GSSAPIConfig{Enabled: true, LibPath: "/invalid"}
+ err := LoadGSSAPILib(config)
+
+ require.Nil(t, lib)
+ require.NotNil(t, err)
+ require.False(t, config.Enabled)
+}
diff --git a/internal/sshd/server_config.go b/internal/sshd/server_config.go
index c8b1e54..3c1fdbf 100644
--- a/internal/sshd/server_config.go
+++ b/internal/sshd/server_config.go
@@ -146,6 +146,26 @@ func (s *serverConfig) getAuthKey(ctx context.Context, user string, key ssh.Publ
}
func (s *serverConfig) get(ctx context.Context) *ssh.ServerConfig {
+ var gssapiWithMICConfig *ssh.GSSAPIWithMICConfig
+ if s.cfg.Server.GSSAPI.Enabled {
+ gssapiWithMICConfig = &ssh.GSSAPIWithMICConfig{
+ AllowLogin: func(conn ssh.ConnMetadata, srcName string) (*ssh.Permissions, error) {
+ if conn.User() != s.cfg.User {
+ return nil, fmt.Errorf("unknown user")
+ }
+
+ return &ssh.Permissions{
+ // Record the Kerberos principal used for authentication.
+ Extensions: map[string]string{
+ "krb5principal": srcName,
+ },
+ }, nil
+ },
+ Server: &OSGSSAPIServer{
+ ServicePrincipalName: s.cfg.Server.GSSAPI.ServicePrincipalName,
+ },
+ }
+ }
sshCfg := &ssh.ServerConfig{
PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
res, err := s.getAuthKey(ctx, conn.User(), key)
@@ -160,7 +180,8 @@ func (s *serverConfig) get(ctx context.Context) *ssh.ServerConfig {
},
}, nil
},
- ServerVersion: "SSH-2.0-GitLab-SSHD",
+ GSSAPIWithMICConfig: gssapiWithMICConfig,
+ ServerVersion: "SSH-2.0-GitLab-SSHD",
}
if len(s.cfg.Server.MACs) > 0 {
diff --git a/internal/sshd/server_config_test.go b/internal/sshd/server_config_test.go
index d98302f..d8e6370 100644
--- a/internal/sshd/server_config_test.go
+++ b/internal/sshd/server_config_test.go
@@ -171,6 +171,52 @@ func TestCustomAlgorithms(t *testing.T) {
require.Equal(t, customCiphers, sshServerConfig.Ciphers)
}
+func TestGSSAPIWithMIC(t *testing.T) {
+ srvCfg := &serverConfig{
+ cfg: &config.Config{
+ Server: config.ServerConfig{
+ GSSAPI: config.GSSAPIConfig{
+ Enabled: true,
+ ServicePrincipalName: "host/test@TEST.TEST",
+ },
+ },
+ },
+ }
+ sshServerConfig := srvCfg.get(context.Background())
+ server := sshServerConfig.GSSAPIWithMICConfig.Server.(*OSGSSAPIServer)
+
+ require.NotNil(t, sshServerConfig.GSSAPIWithMICConfig)
+ require.NotNil(t, sshServerConfig.GSSAPIWithMICConfig.AllowLogin)
+ require.NotNil(t, server)
+ require.Equal(t, server.ServicePrincipalName, "host/test@TEST.TEST")
+
+ sshServerConfig.SetDefaults()
+
+ require.NotNil(t, sshServerConfig.GSSAPIWithMICConfig)
+ require.NotNil(t, sshServerConfig.GSSAPIWithMICConfig.AllowLogin)
+ require.NotNil(t, server)
+ require.Equal(t, server.ServicePrincipalName, "host/test@TEST.TEST")
+}
+
+func TestGSSAPIWithMICDisabled(t *testing.T) {
+ srvCfg := &serverConfig{
+ cfg: &config.Config{
+ Server: config.ServerConfig{
+ GSSAPI: config.GSSAPIConfig{
+ Enabled: false,
+ },
+ },
+ },
+ }
+ sshServerConfig := srvCfg.get(context.Background())
+
+ require.Nil(t, sshServerConfig.GSSAPIWithMICConfig)
+
+ sshServerConfig.SetDefaults()
+
+ require.Nil(t, sshServerConfig.GSSAPIWithMICConfig)
+}
+
func rsaPublicKey(t *testing.T) ssh.PublicKey {
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
require.NoError(t, err)
diff --git a/internal/sshd/session.go b/internal/sshd/session.go
index 48cd86a..3394b2a 100644
--- a/internal/sshd/session.go
+++ b/internal/sshd/session.go
@@ -13,6 +13,7 @@ import (
grpcstatus "google.golang.org/grpc/status"
shellCmd "gitlab.com/gitlab-org/gitlab-shell/v14/cmd/gitlab-shell/command"
+ "gitlab.com/gitlab-org/gitlab-shell/v14/internal/command"
"gitlab.com/gitlab-org/gitlab-shell/v14/internal/command/readwriter"
"gitlab.com/gitlab-org/gitlab-shell/v14/internal/command/shared/disallowedcommand"
"gitlab.com/gitlab-org/gitlab-shell/v14/internal/config"
@@ -23,10 +24,11 @@ import (
type session struct {
// State set up by the connection
- cfg *config.Config
- channel ssh.Channel
- gitlabKeyId string
- remoteAddr string
+ cfg *config.Config
+ channel ssh.Channel
+ gitlabKeyId string
+ gitlabKrb5Principal string
+ remoteAddr string
// State managed by the session
execCmd string
@@ -166,7 +168,14 @@ func (s *session) handleShell(ctx context.Context, req *ssh.Request) (uint32, er
ErrOut: s.channel.Stderr(),
}
- cmd, err := shellCmd.NewWithKey(s.gitlabKeyId, env, s.cfg, rw)
+ var cmd command.Command
+ var err error
+
+ if s.gitlabKrb5Principal != "" {
+ cmd, err = shellCmd.NewWithKrb5Principal(s.gitlabKrb5Principal, env, s.cfg, rw)
+ } else {
+ cmd, err = shellCmd.NewWithKey(s.gitlabKeyId, env, s.cfg, rw)
+ }
if err != nil {
if errors.Is(err, disallowedcommand.Error) {
s.toStderr(ctx, "ERROR: Unknown command: %v\n", s.execCmd)
diff --git a/internal/sshd/session_test.go b/internal/sshd/session_test.go
index fe43342..d1bff7e 100644
--- a/internal/sshd/session_test.go
+++ b/internal/sshd/session_test.go
@@ -130,21 +130,29 @@ func TestHandleExec(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
- out := &bytes.Buffer{}
- f := &fakeChannel{stdErr: out}
- s := &session{
- gitlabKeyId: "root",
- channel: f,
- cfg: &config.Config{GitlabUrl: url},
+ sessions := []*session{
+ {
+ gitlabKeyId: "root",
+ cfg: &config.Config{GitlabUrl: url},
+ },
+ {
+ gitlabKrb5Principal: "test@TEST.TEST",
+ cfg: &config.Config{GitlabUrl: url},
+ },
+ }
+ for _, s := range sessions {
+ out := &bytes.Buffer{}
+ f := &fakeChannel{stdErr: out}
+ r := &ssh.Request{Payload: tc.payload}
+
+ s.channel = f
+ shouldContinue, err := s.handleExec(context.Background(), r)
+
+ require.Equal(t, tc.expectedErr, err)
+ require.Equal(t, false, shouldContinue)
+ require.Equal(t, tc.sentRequestName, f.sentRequestName)
+ require.Equal(t, tc.sentRequestPayload, f.sentRequestPayload)
}
- r := &ssh.Request{Payload: tc.payload}
-
- shouldContinue, err := s.handleExec(context.Background(), r)
-
- require.Equal(t, tc.expectedErr, err)
- require.Equal(t, false, shouldContinue)
- require.Equal(t, tc.sentRequestName, f.sentRequestName)
- require.Equal(t, tc.sentRequestPayload, f.sentRequestPayload)
})
}
}
diff --git a/internal/sshd/sshd.go b/internal/sshd/sshd.go
index d20286a..fbb5052 100644
--- a/internal/sshd/sshd.go
+++ b/internal/sshd/sshd.go
@@ -194,11 +194,12 @@ func (s *Server) handleConn(ctx context.Context, nconn net.Conn) {
conn := newConnection(s.Config, nconn)
conn.handle(ctx, s.serverConfig.get(ctx), func(sconn *ssh.ServerConn, channel ssh.Channel, requests <-chan *ssh.Request) error {
session := &session{
- cfg: s.Config,
- channel: channel,
- gitlabKeyId: sconn.Permissions.Extensions["key-id"],
- remoteAddr: remoteAddr,
- started: time.Now(),
+ cfg: s.Config,
+ channel: channel,
+ gitlabKeyId: sconn.Permissions.Extensions["key-id"],
+ gitlabKrb5Principal: sconn.Permissions.Extensions["krb5principal"],
+ remoteAddr: remoteAddr,
+ started: time.Now(),
}
return session.handle(ctx, requests)