Skip to content

Commit

Permalink
Implement GSSAPI auth
Browse files Browse the repository at this point in the history
  • Loading branch information
bersace committed May 16, 2024
1 parent 86784f9 commit 6307936
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 9 deletions.
4 changes: 3 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,10 @@ jobs:
environment:
PGVERSION: "<< parameters.pgversion >>"
DIST: "<< parameters.dist >>"
COMPOSE_FILE: docker-compose.yml:test/docker-compose.yml
command: |
COMPOSE_FILE=docker-compose.yml:test/docker-compose.yml docker compose up --exit-code-from=test
docker compose pull
docker compose up --exit-code-from=test
pkg:
parameters:
Expand Down
9 changes: 9 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,27 @@ require (

require (
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gosimple/unidecode v1.0.1 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
github.com/jcmturner/gofork v1.7.6 // indirect
github.com/jcmturner/goidentity/v6 v6.0.1 // indirect
github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 h1:TQcrn6Wq+sKGkpyPvppOz99zsM
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/gosimple/slug v1.14.0 h1:RtTL/71mJNDfpUbCOmnf/XFkzKRtD6wL6Uy+3akm4Es=
github.com/gosimple/slug v1.14.0/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ=
Expand Down
34 changes: 34 additions & 0 deletions internal/ldap/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import (
"log/slog"
"net"
"net/url"
"os"
"strings"
"time"

"github.com/avast/retry-go/v4"
"github.com/dalibo/ldap2pg/internal/perf"
ldap3 "github.com/go-ldap/ldap/v3"
"github.com/go-ldap/ldap/v3/gssapi"
)

type Client struct {
Expand Down Expand Up @@ -90,6 +92,38 @@ func Connect() (client Client, err error) {
}
slog.Debug("LDAP SASL/DIGEST-MD5 bind.", "authcid", client.SaslAuthCID, "host", parsedURI.Host)
err = client.Conn.MD5Bind(parsedURI.Host, client.SaslAuthCID, password)
case "GSSAPI":
// Get the principal
client.SaslAuthCID = k.String("SASL_AUTHCID")
ccache, ok := os.LookupEnv("KRB5CCNAME")
if ok {
ccache = strings.TrimPrefix(ccache, "FILE:")
} else {
uid := os.Getuid()
ccache = fmt.Sprintf("/tmp/krb5cc_%d", uid)
}
krb5confPath, ok := os.LookupEnv("KRB5_CONFIG")
if !ok {
krb5confPath = "/etc/krb5.conf"
}
slog.Debug("Initial SSPI client.", "ccache", ccache, "krb5conf", krb5confPath)
sspiClient, err := gssapi.NewClientFromCCache(ccache, krb5confPath)
if err != nil {
return client, err
}
defer sspiClient.Close()
// Build service Principal from URI.
var parsedURI *url.URL
parsedURI, err = url.Parse(client.URI)
if err != nil {
return client, err
}
spn := "ldap/" + strings.Split(parsedURI.Host, ":")[0]
slog.Debug("LDAP SASL/GSSAPI bind.", "principal", client.SaslAuthCID, "spn", spn)
err = client.Conn.GSSAPIBind(sspiClient, spn, client.SaslAuthCID)
if err != nil {
return client, err
}
default:
err = fmt.Errorf("unhandled SASL_MECH")
}
Expand Down
11 changes: 11 additions & 0 deletions test/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
version: '3'

services:
samba1:
labels:
# Disable dnsdock on test.
com.dnsdock.alias: samba1.test.ldap2pg.docker
networks:
default:
aliases:
# Fake dnsdock for CI.
# This value is used in test/krb5.conf for KDC.
- samba1.ldap2pg.docker

test:
image: dalibo/buildpack-python:${DIST-rockylinux8}
volumes:
Expand Down
5 changes: 4 additions & 1 deletion test/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ psql -tc "SELECT version();"
# ldap-utils on CentOS does not read properly current ldaprc. Linking it in ~
# workaround this.
ln -fsv "${PWD}/ldaprc" ~/ldaprc
retry ldapsearch -x -v -w "${LDAPPASSWORD}" -z none
retry ldapsearch -x -v -w "${LDAPPASSWORD}" -z none >/dev/null

export KRB5_CONFIG="${PWD}/test/krb5.conf"
kinit -V -k -t "${PWD}/test/samba.keytab" Administrator
LDAPURI="${LDAPURI/ldaps:/ldap:}" ldapsearch -v -Y GSSAPI -U Administrator >/dev/null
"$python" -m pytest test/ "$@"
1 change: 1 addition & 0 deletions test/krb5.conf
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

[realms]
BRIDOULOU.FR = {
# Requires dnsdock on network alias as in test/docker-compose.yml
kdc = samba1.ldap2pg.docker
admin_server = samba1.ldap2pg.docker
}
Expand Down
13 changes: 6 additions & 7 deletions test/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,15 @@ def test_stdin(ldap2pg, capsys):
assert 'stdinuser' in err


@pytest.mark.xfail(reason="Samba does not support SASL DIGEST-MD5.")
@pytest.mark.xfail(
'CI' not in os.environ,
reason="Set CI=true to run GSSAPI test."
)
def test_sasl(ldap2pg, capsys):
env = dict(
os.environ,
# py-ldap2pg reads non-standard var USER.
LDAPUSER='testsasl',
# ldap2pg requires explicit SASL_MECH, and standard SASL_AUTHID.
LDAPSASL_MECH='DIGEST-MD5',
LDAPSASL_AUTHCID='testsasl',
LDAPPASSWORD='voyage',
LDAPSASL_MECH='GSSAPI',
LDAPSASL_AUTHCID='Administrator',
)
ldap2pg(config='ldap2pg.yml', verbose=True, _env=env)

Expand Down

0 comments on commit 6307936

Please sign in to comment.