Skip to content

Commit

Permalink
Merge pull request #972 from AGWA-forks/master
Browse files Browse the repository at this point in the history
Move Kerberos support to separate module
  • Loading branch information
maddyblue authored Jun 8, 2020
2 parents d408f9c + 83d7d7f commit 65babff
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 62 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
* Unix socket support
* Notifications: `LISTEN`/`NOTIFY`
* pgpass support
* GSS (Kerberos) auth

## Optional Features

* GSS (Kerberos) auth (to use, see GoDoc)

## Tests

Expand Down
8 changes: 8 additions & 0 deletions auth/kerberos/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module github.com/lib/pq/auth/kerberos

go 1.13

require (
github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5
github.com/jcmturner/gokrb5/v8 v8.2.0
)
40 changes: 40 additions & 0 deletions auth/kerberos/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5 h1:P5U+E4x5OkVEKQDklVPmzs71WM56RTTRqV4OrDC//Y4=
github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5/go.mod h1:976q2ETgjT2snVCf2ZaBnyBbVoPERGjUz+0sofzEfro=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ=
github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8=
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o=
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
github.com/jcmturner/gokrb5/v8 v8.2.0 h1:lzPl/30ZLkTveYsYZPKMcgXc8MbnE6RsTd4F9KgiLtk=
github.com/jcmturner/gokrb5/v8 v8.2.0/go.mod h1:T1hnNppQsBtxW0tCHMHTkAt8n/sABdzZgZdoFrZaZNM=
github.com/jcmturner/rpc/v2 v2.0.2 h1:gMB4IwRXYsWw4Bc6o/az2HJgFUA1ffSh90i26ZJ6Xl0=
github.com/jcmturner/rpc/v2 v2.0.2/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200117160349-530e935923ad h1:Jh8cai0fqIK+f6nG0UgPW5wFk8wmiMhM3AyciDBdtQg=
golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa h1:F+8P+gmewFQYRk6JoLQLwjBCTu3mcIURZfNkVweuRKA=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
29 changes: 29 additions & 0 deletions auth/kerberos/krb.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package kerberos

import (
"net"
"strings"
)

/*
* Find the A record associated with a hostname
* In general, hostnames supplied to the driver should be
* canonicalized because the KDC usually only has one
* principal and not one per potential alias of a host.
*/
func canonicalizeHostname(host string) (string, error) {
canon := host

name, err := net.LookupCNAME(host)
if err != nil {
return "", err
}

name = strings.TrimSuffix(name, ".")

if name != "" {
canon = name
}

return canon, nil
}
18 changes: 9 additions & 9 deletions krb_unix.go → auth/kerberos/krb_unix.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// +build !windows

package pq
package kerberos

import (
"fmt"
Expand All @@ -19,13 +19,13 @@ import (
* implementation
*/

// Implements the Gss interface
type gss struct {
// Implements the pq.Gss interface
type Gss struct {
cli *client.Client
}

func NewGSS() (Gss, error) {
g := &gss{}
func NewGSS() (*Gss, error) {
g := &Gss{}
err := g.init()

if err != nil {
Expand All @@ -35,7 +35,7 @@ func NewGSS() (Gss, error) {
return g, nil
}

func (g *gss) init() error {
func (g *Gss) init() error {
cfgPath, ok := os.LookupEnv("KRB5_CONFIG")
if !ok {
cfgPath = "/etc/krb5.conf"
Expand Down Expand Up @@ -75,7 +75,7 @@ func (g *gss) init() error {
return nil
}

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

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

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

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

func (g *gss) Continue(inToken []byte) (done bool, outToken []byte, err error) {
func (g *Gss) Continue(inToken []byte) (done bool, outToken []byte, err error) {
t := &spnego.SPNEGOToken{}
err = t.Unmarshal(inToken)
if err != nil {
Expand Down
17 changes: 9 additions & 8 deletions krb_windows.go → auth/kerberos/krb_windows.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
// +build windows

package pq
package kerberos

import (
"github.com/alexbrainman/sspi"
"github.com/alexbrainman/sspi/negotiate"
)

type gss struct {
// Implements the pq.Gss interface
type Gss struct {
creds *sspi.Credentials
ctx *negotiate.ClientContext
}

func NewGSS() (Gss, error) {
g := &gss{}
func NewGSS() (*Gss, error) {
g := &Gss{}
err := g.init()

if err != nil {
Expand All @@ -23,7 +24,7 @@ func NewGSS() (Gss, error) {
return g, nil
}

func (g *gss) init() error {
func (g *Gss) init() error {
creds, err := negotiate.AcquireCurrentUserCredentials()
if err != nil {
return err
Expand All @@ -33,7 +34,7 @@ func (g *gss) init() error {
return nil
}

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

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

func (g *gss) GetInitTokenFromSpn(spn string) ([]byte, error) {
func (g *Gss) GetInitTokenFromSpn(spn string) ([]byte, error) {
ctx, token, err := negotiate.NewClientContext(g.creds, spn)
if err != nil {
return nil, err
Expand All @@ -56,6 +57,6 @@ func (g *gss) GetInitTokenFromSpn(spn string) ([]byte, error) {
return token, nil
}

func (g *gss) Continue(inToken []byte) (done bool, outToken []byte, err error) {
func (g *Gss) Continue(inToken []byte) (done bool, outToken []byte, err error) {
return g.ctx.Update(inToken)
}
5 changes: 4 additions & 1 deletion conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -1158,7 +1158,10 @@ func (cn *conn) auth(r *readBuf, o values) {
errorf("unexpected authentication response: %q", t)
}
case 7: // GSSAPI, startup
cli, err := NewGSS()
if newGss == nil {
errorf("kerberos error: no GSSAPI provider registered (import github.com/lib/pq/auth/kerberos if you need Kerberos support)")
}
cli, err := newGss()
if err != nil {
errorf("kerberos error: %s", err.Error())
}
Expand Down
16 changes: 16 additions & 0 deletions doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,5 +243,21 @@ bytes by the PostgreSQL server.
You can find a complete, working example of Listener usage at
https://godoc.org/github.com/lib/pq/example/listen.
Kerberos Support
If you need support for Kerberos authentication, add the following to your main
package:
import "github.com/lib/pq/auth/kerberos"
func init() {
pq.RegisterGSSProvider(func() (pq.Gss, error) { return kerberos.NewGSS() })
}
This package is in a separate module so that users who don't need Kerberos
don't have to download unnecessary dependencies.
*/
package pq
11 changes: 0 additions & 11 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,14 +1,3 @@
module github.com/lib/pq

go 1.13

require (
github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5 // indirect
github.com/jcmturner/gokrb5/v8 v8.2.0
golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4 // indirect
gopkg.in/jcmturner/aescts.v1 v1.0.1 // indirect
gopkg.in/jcmturner/dnsutils.v1 v1.0.1 // indirect
gopkg.in/jcmturner/goidentity.v3 v3.0.0 // indirect
gopkg.in/jcmturner/gokrb5.v7 v7.5.0
gopkg.in/jcmturner/rpc.v1 v1.1.0 // indirect
)
53 changes: 21 additions & 32 deletions krb.go
Original file line number Diff line number Diff line change
@@ -1,40 +1,29 @@
package pq

import (
"net"
"strings"
)

/*
* Basic GSSAPI interface to abstract Windows (SSPI) from Unix
* APIs within the driver
*/
// A function that creates a GSS authentication provider,
// for use with RegisterGSSProvider.
type NewGSSFunc func() (Gss, error)

var newGss NewGSSFunc

// Register the function for creating a GSS authentication provider.
// For example, if you need to use Kerberos to authenticate with your server,
// add this to your main package:
//
// import "github.com/lib/pq/auth/kerberos"
//
// func init() {
// pq.RegisterGSSProvider(func() (pq.Gss, error) { return kerberos.NewGSS() })
// }
func RegisterGSSProvider(newGssArg NewGSSFunc) {
newGss = newGssArg
}

// An interface for providing GSSAPI authentication (e.g. Kerberos).
// You only need to care about this interface if you are writing a
// GSS authentication provider.
type Gss interface {
GetInitToken(host string, service string) ([]byte, error)
GetInitTokenFromSpn(spn string) ([]byte, error)
Continue(inToken []byte) (done bool, outToken []byte, err error)
}

/*
* Find the A record associated with a hostname
* In general, hostnames supplied to the driver should be
* canonicalized because the KDC usually only has one
* principal and not one per potential alias of a host.
*/
func canonicalizeHostname(host string) (string, error) {
canon := host

name, err := net.LookupCNAME(host)
if err != nil {
return "", err
}

name = strings.TrimSuffix(name, ".")

if name != "" {
canon = name
}

return canon, nil
}

0 comments on commit 65babff

Please sign in to comment.