Skip to content

Commit 65babff

Browse files
authored
Merge pull request #972 from AGWA-forks/master
Move Kerberos support to separate module
2 parents d408f9c + 83d7d7f commit 65babff

File tree

10 files changed

+140
-62
lines changed

10 files changed

+140
-62
lines changed

README.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@
1919
* Unix socket support
2020
* Notifications: `LISTEN`/`NOTIFY`
2121
* pgpass support
22-
* GSS (Kerberos) auth
22+
23+
## Optional Features
24+
25+
* GSS (Kerberos) auth (to use, see GoDoc)
2326

2427
## Tests
2528

auth/kerberos/go.mod

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module github.com/lib/pq/auth/kerberos
2+
3+
go 1.13
4+
5+
require (
6+
github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5
7+
github.com/jcmturner/gokrb5/v8 v8.2.0
8+
)

auth/kerberos/go.sum

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5 h1:P5U+E4x5OkVEKQDklVPmzs71WM56RTTRqV4OrDC//Y4=
2+
github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5/go.mod h1:976q2ETgjT2snVCf2ZaBnyBbVoPERGjUz+0sofzEfro=
3+
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
4+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5+
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
6+
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
7+
github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ=
8+
github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
9+
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
10+
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
11+
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
12+
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
13+
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
14+
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
15+
github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8=
16+
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
17+
github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o=
18+
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
19+
github.com/jcmturner/gokrb5/v8 v8.2.0 h1:lzPl/30ZLkTveYsYZPKMcgXc8MbnE6RsTd4F9KgiLtk=
20+
github.com/jcmturner/gokrb5/v8 v8.2.0/go.mod h1:T1hnNppQsBtxW0tCHMHTkAt8n/sABdzZgZdoFrZaZNM=
21+
github.com/jcmturner/rpc/v2 v2.0.2 h1:gMB4IwRXYsWw4Bc6o/az2HJgFUA1ffSh90i26ZJ6Xl0=
22+
github.com/jcmturner/rpc/v2 v2.0.2/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
23+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
24+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
25+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
26+
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
27+
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
28+
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
29+
golang.org/x/crypto v0.0.0-20200117160349-530e935923ad h1:Jh8cai0fqIK+f6nG0UgPW5wFk8wmiMhM3AyciDBdtQg=
30+
golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
31+
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
32+
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa h1:F+8P+gmewFQYRk6JoLQLwjBCTu3mcIURZfNkVweuRKA=
33+
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
34+
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
35+
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
36+
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
37+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
38+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
39+
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
40+
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

auth/kerberos/krb.go

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package kerberos
2+
3+
import (
4+
"net"
5+
"strings"
6+
)
7+
8+
/*
9+
* Find the A record associated with a hostname
10+
* In general, hostnames supplied to the driver should be
11+
* canonicalized because the KDC usually only has one
12+
* principal and not one per potential alias of a host.
13+
*/
14+
func canonicalizeHostname(host string) (string, error) {
15+
canon := host
16+
17+
name, err := net.LookupCNAME(host)
18+
if err != nil {
19+
return "", err
20+
}
21+
22+
name = strings.TrimSuffix(name, ".")
23+
24+
if name != "" {
25+
canon = name
26+
}
27+
28+
return canon, nil
29+
}

krb_unix.go auth/kerberos/krb_unix.go

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// +build !windows
22

3-
package pq
3+
package kerberos
44

55
import (
66
"fmt"
@@ -19,13 +19,13 @@ import (
1919
* implementation
2020
*/
2121

22-
// Implements the Gss interface
23-
type gss struct {
22+
// Implements the pq.Gss interface
23+
type Gss struct {
2424
cli *client.Client
2525
}
2626

27-
func NewGSS() (Gss, error) {
28-
g := &gss{}
27+
func NewGSS() (*Gss, error) {
28+
g := &Gss{}
2929
err := g.init()
3030

3131
if err != nil {
@@ -35,7 +35,7 @@ func NewGSS() (Gss, error) {
3535
return g, nil
3636
}
3737

38-
func (g *gss) init() error {
38+
func (g *Gss) init() error {
3939
cfgPath, ok := os.LookupEnv("KRB5_CONFIG")
4040
if !ok {
4141
cfgPath = "/etc/krb5.conf"
@@ -75,7 +75,7 @@ func (g *gss) init() error {
7575
return nil
7676
}
7777

78-
func (g *gss) GetInitToken(host string, service string) ([]byte, error) {
78+
func (g *Gss) GetInitToken(host string, service string) ([]byte, error) {
7979

8080
// Resolve the hostname down to an 'A' record, if required (usually, it is)
8181
if g.cli.Config.LibDefaults.DNSCanonicalizeHostname {
@@ -91,7 +91,7 @@ func (g *gss) GetInitToken(host string, service string) ([]byte, error) {
9191
return g.GetInitTokenFromSpn(spn)
9292
}
9393

94-
func (g *gss) GetInitTokenFromSpn(spn string) ([]byte, error) {
94+
func (g *Gss) GetInitTokenFromSpn(spn string) ([]byte, error) {
9595
s := spnego.SPNEGOClient(g.cli, spn)
9696

9797
st, err := s.InitSecContext()
@@ -107,7 +107,7 @@ func (g *gss) GetInitTokenFromSpn(spn string) ([]byte, error) {
107107
return b, nil
108108
}
109109

110-
func (g *gss) Continue(inToken []byte) (done bool, outToken []byte, err error) {
110+
func (g *Gss) Continue(inToken []byte) (done bool, outToken []byte, err error) {
111111
t := &spnego.SPNEGOToken{}
112112
err = t.Unmarshal(inToken)
113113
if err != nil {

krb_windows.go auth/kerberos/krb_windows.go

+9-8
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
// +build windows
22

3-
package pq
3+
package kerberos
44

55
import (
66
"github.com/alexbrainman/sspi"
77
"github.com/alexbrainman/sspi/negotiate"
88
)
99

10-
type gss struct {
10+
// Implements the pq.Gss interface
11+
type Gss struct {
1112
creds *sspi.Credentials
1213
ctx *negotiate.ClientContext
1314
}
1415

15-
func NewGSS() (Gss, error) {
16-
g := &gss{}
16+
func NewGSS() (*Gss, error) {
17+
g := &Gss{}
1718
err := g.init()
1819

1920
if err != nil {
@@ -23,7 +24,7 @@ func NewGSS() (Gss, error) {
2324
return g, nil
2425
}
2526

26-
func (g *gss) init() error {
27+
func (g *Gss) init() error {
2728
creds, err := negotiate.AcquireCurrentUserCredentials()
2829
if err != nil {
2930
return err
@@ -33,7 +34,7 @@ func (g *gss) init() error {
3334
return nil
3435
}
3536

36-
func (g *gss) GetInitToken(host string, service string) ([]byte, error) {
37+
func (g *Gss) GetInitToken(host string, service string) ([]byte, error) {
3738

3839
host, err := canonicalizeHostname(host)
3940
if err != nil {
@@ -45,7 +46,7 @@ func (g *gss) GetInitToken(host string, service string) ([]byte, error) {
4546
return g.GetInitTokenFromSpn(spn)
4647
}
4748

48-
func (g *gss) GetInitTokenFromSpn(spn string) ([]byte, error) {
49+
func (g *Gss) GetInitTokenFromSpn(spn string) ([]byte, error) {
4950
ctx, token, err := negotiate.NewClientContext(g.creds, spn)
5051
if err != nil {
5152
return nil, err
@@ -56,6 +57,6 @@ func (g *gss) GetInitTokenFromSpn(spn string) ([]byte, error) {
5657
return token, nil
5758
}
5859

59-
func (g *gss) Continue(inToken []byte) (done bool, outToken []byte, err error) {
60+
func (g *Gss) Continue(inToken []byte) (done bool, outToken []byte, err error) {
6061
return g.ctx.Update(inToken)
6162
}

conn.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -1158,7 +1158,10 @@ func (cn *conn) auth(r *readBuf, o values) {
11581158
errorf("unexpected authentication response: %q", t)
11591159
}
11601160
case 7: // GSSAPI, startup
1161-
cli, err := NewGSS()
1161+
if newGss == nil {
1162+
errorf("kerberos error: no GSSAPI provider registered (import github.com/lib/pq/auth/kerberos if you need Kerberos support)")
1163+
}
1164+
cli, err := newGss()
11621165
if err != nil {
11631166
errorf("kerberos error: %s", err.Error())
11641167
}

doc.go

+16
Original file line numberDiff line numberDiff line change
@@ -243,5 +243,21 @@ bytes by the PostgreSQL server.
243243
You can find a complete, working example of Listener usage at
244244
https://godoc.org/github.com/lib/pq/example/listen.
245245
246+
247+
Kerberos Support
248+
249+
250+
If you need support for Kerberos authentication, add the following to your main
251+
package:
252+
253+
import "github.com/lib/pq/auth/kerberos"
254+
255+
func init() {
256+
pq.RegisterGSSProvider(func() (pq.Gss, error) { return kerberos.NewGSS() })
257+
}
258+
259+
This package is in a separate module so that users who don't need Kerberos
260+
don't have to download unnecessary dependencies.
261+
246262
*/
247263
package pq

go.mod

-11
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,3 @@
11
module github.com/lib/pq
22

33
go 1.13
4-
5-
require (
6-
github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5 // indirect
7-
github.com/jcmturner/gokrb5/v8 v8.2.0
8-
golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4 // indirect
9-
gopkg.in/jcmturner/aescts.v1 v1.0.1 // indirect
10-
gopkg.in/jcmturner/dnsutils.v1 v1.0.1 // indirect
11-
gopkg.in/jcmturner/goidentity.v3 v3.0.0 // indirect
12-
gopkg.in/jcmturner/gokrb5.v7 v7.5.0
13-
gopkg.in/jcmturner/rpc.v1 v1.1.0 // indirect
14-
)

krb.go

+21-32
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,29 @@
11
package pq
22

3-
import (
4-
"net"
5-
"strings"
6-
)
7-
8-
/*
9-
* Basic GSSAPI interface to abstract Windows (SSPI) from Unix
10-
* APIs within the driver
11-
*/
3+
// A function that creates a GSS authentication provider,
4+
// for use with RegisterGSSProvider.
5+
type NewGSSFunc func() (Gss, error)
6+
7+
var newGss NewGSSFunc
8+
9+
// Register the function for creating a GSS authentication provider.
10+
// For example, if you need to use Kerberos to authenticate with your server,
11+
// add this to your main package:
12+
//
13+
// import "github.com/lib/pq/auth/kerberos"
14+
//
15+
// func init() {
16+
// pq.RegisterGSSProvider(func() (pq.Gss, error) { return kerberos.NewGSS() })
17+
// }
18+
func RegisterGSSProvider(newGssArg NewGSSFunc) {
19+
newGss = newGssArg
20+
}
1221

22+
// An interface for providing GSSAPI authentication (e.g. Kerberos).
23+
// You only need to care about this interface if you are writing a
24+
// GSS authentication provider.
1325
type Gss interface {
1426
GetInitToken(host string, service string) ([]byte, error)
1527
GetInitTokenFromSpn(spn string) ([]byte, error)
1628
Continue(inToken []byte) (done bool, outToken []byte, err error)
1729
}
18-
19-
/*
20-
* Find the A record associated with a hostname
21-
* In general, hostnames supplied to the driver should be
22-
* canonicalized because the KDC usually only has one
23-
* principal and not one per potential alias of a host.
24-
*/
25-
func canonicalizeHostname(host string) (string, error) {
26-
canon := host
27-
28-
name, err := net.LookupCNAME(host)
29-
if err != nil {
30-
return "", err
31-
}
32-
33-
name = strings.TrimSuffix(name, ".")
34-
35-
if name != "" {
36-
canon = name
37-
}
38-
39-
return canon, nil
40-
}

0 commit comments

Comments
 (0)