Skip to content

Commit 60e1c81

Browse files
Divjot Aroraskriptble
authored andcommitted
Add support for GSSAPI ServiceHost
GODRIVER-698 Change-Id: I6888326e272ab63ea2594181d09fcf0b9d5c17aa
1 parent 04af4db commit 60e1c81

File tree

6 files changed

+109
-21
lines changed

6 files changed

+109
-21
lines changed

.evergreen/config.yml

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,6 @@ functions:
270270
- command: shell.exec
271271
type: test
272272
params:
273-
silent: true
274273
working_dir: src/go.mongodb.org/mongo-driver
275274
script: |
276275
# DO NOT ECHO WITH XTRACE (which PREPARE_SHELL does)
@@ -291,6 +290,30 @@ functions:
291290
export PATH="${GCC_PATH}:${GO_DIST}/bin:$PATH"
292291
MONGO_GO_DRIVER_COMPRESSOR="${MONGO_GO_DRIVER_COMPRESSOR}" make -s evg-test-auth
293292
293+
run-enterprise-gssapi-service-host-auth-tests:
294+
- command: shell.exec
295+
type: test
296+
params:
297+
working_dir: src/go.mongodb.org/mongo-driver
298+
script: |
299+
# DO NOT ECHO WITH XTRACE (which PREPARE_SHELL does)
300+
if [ "Windows_NT" = "$OS" ]; then
301+
export GOPATH=$(cygpath -w $(dirname $(dirname $(dirname `pwd`))))
302+
export MONGODB_URI="${gssapi_service_host_auth_windows_mongodb_uri}"
303+
else
304+
export GOPATH=$(dirname $(dirname $(dirname `pwd`)))
305+
echo "${gssapi_auth_linux_keytab_base64}" > /tmp/drivers.keytab.base64
306+
base64 --decode /tmp/drivers.keytab.base64 > ${PROJECT_DIRECTORY}/.evergreen/drivers.keytab
307+
mkdir -p ~/.krb5
308+
cat .evergreen/krb5.config | tee -a ~/.krb5/config
309+
kinit -k -t ${PROJECT_DIRECTORY}/.evergreen/drivers.keytab -p "${gssapi_auth_username}"
310+
export MONGODB_URI="${gssapi_service_host_auth_linux_mongodb_uri}"
311+
fi;
312+
export GOPATH="$GOPATH"
313+
export GOROOT="${GO_DIST}"
314+
export PATH="${GCC_PATH}:${GO_DIST}/bin:$PATH"
315+
MONGO_GO_DRIVER_COMPRESSOR="${MONGO_GO_DRIVER_COMPRESSOR}" make -s evg-test-auth
316+
294317
pre:
295318
- func: fetch-source
296319
- func: prepare-resources
@@ -553,6 +576,13 @@ tasks:
553576
vars:
554577
MONGO_GO_DRIVER_COMPRESSOR: "snappy"
555578

579+
- name: test-enterprise-auth-gssapi-service-host
580+
tags: ["test", "enterprise-auth"]
581+
commands:
582+
- func: run-enterprise-gssapi-service-host-auth-tests
583+
vars:
584+
MONGO_GO_DRIVER_COMPRESSOR: "snappy"
585+
556586
- name: go1.8-build
557587
tags: ["compile-check"]
558588
commands:

mongo/options/clientoptions.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,13 @@ type ContextDialer interface {
3939
// Supported values include "SCRAM-SHA-256", "SCRAM-SHA-1", "MONGODB-CR", "PLAIN", "GSSAPI", and "MONGODB-X509".
4040
//
4141
// AuthMechanismProperties specifies additional configuration options which may be used by certain
42-
// authentication mechanisms.
42+
// authentication mechanisms. Supported properties are:
43+
// SERVICE_NAME: Specifies the name of the service. Defaults to mongodb.
44+
// CANONICALIZE_HOST_NAME: If true, tells the driver to canonicalize the given hostname. Defaults to false. This
45+
// property may not be used on Linux and Darwin systems and may not be used at the same time as SERVICE_HOST.
46+
// SERVICE_REALM: Specifies the realm of the service.
47+
// SERVICE_HOST: Specifies a hostname for GSSAPI authentication if it is different from the server's address. For
48+
// authentication mechanisms besides GSSAPI, this property is ignored.
4349
//
4450
// AuthSource specifies the database to authenticate against.
4551
//

x/mongo/driver/auth/gssapi.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ package auth
1111

1212
import (
1313
"context"
14+
"fmt"
15+
"net"
1416

1517
"go.mongodb.org/mongo-driver/x/mongo/driver/auth/internal/gssapi"
1618
"go.mongodb.org/mongo-driver/x/network/description"
@@ -43,7 +45,13 @@ type GSSAPIAuthenticator struct {
4345

4446
// Auth authenticates the connection.
4547
func (a *GSSAPIAuthenticator) Auth(ctx context.Context, desc description.Server, rw wiremessage.ReadWriter) error {
46-
client, err := gssapi.New(desc.Addr.String(), a.Username, a.Password, a.PasswordSet, a.Props)
48+
target := desc.Addr.String()
49+
hostname, _, err := net.SplitHostPort(target)
50+
if err != nil {
51+
return newAuthError(fmt.Sprintf("invalid endpoint (%s) specified: %s", target, err), nil)
52+
}
53+
54+
client, err := gssapi.New(hostname, a.Username, a.Password, a.PasswordSet, a.Props)
4755

4856
if err != nil {
4957
return newAuthError("error creating gssapi", err)

x/mongo/driver/auth/gssapi_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright (C) MongoDB, Inc. 2017-present.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License"); you may
4+
// not use this file except in compliance with the License. You may obtain
5+
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6+
7+
//+build gssapi
8+
9+
package auth
10+
11+
import (
12+
"context"
13+
"testing"
14+
15+
"go.mongodb.org/mongo-driver/x/network/address"
16+
"go.mongodb.org/mongo-driver/x/network/description"
17+
)
18+
19+
func TestGSSAPIAuthenticator(t *testing.T) {
20+
t.Run("PropsError", func(t *testing.T) {
21+
// Cannot specify both CANONICALIZE_HOST_NAME and SERVICE_HOST
22+
23+
authenticator := &GSSAPIAuthenticator{
24+
Username: "foo",
25+
Password: "bar",
26+
PasswordSet: true,
27+
Props: map[string]string{
28+
"CANONICALIZE_HOST_NAME": "true",
29+
"SERVICE_HOST": "localhost",
30+
},
31+
}
32+
err := authenticator.Auth(context.Background(), description.Server{
33+
WireVersion: &description.VersionRange{
34+
Max: 6,
35+
},
36+
Addr: address.Address("foo:27017"),
37+
}, nil)
38+
if err == nil {
39+
t.Fatalf("expected err, got nil")
40+
}
41+
})
42+
43+
}

x/mongo/driver/auth/internal/gssapi/gss.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,12 @@ package gssapi
1919
import "C"
2020
import (
2121
"fmt"
22-
"net"
2322
"runtime"
2423
"strings"
2524
"unsafe"
2625
)
2726

28-
// New creates a new SaslClient.
27+
// New creates a new SaslClient. The target parameter should be a hostname with no port.
2928
func New(target, username, password string, passwordSet bool, props map[string]string) (*SaslClient, error) {
3029
serviceName := "mongodb"
3130

@@ -37,17 +36,14 @@ func New(target, username, password string, passwordSet bool, props map[string]s
3736
return nil, fmt.Errorf("SERVICE_REALM is not supported when using gssapi on %s", runtime.GOOS)
3837
case "SERVICE_NAME":
3938
serviceName = value
39+
case "SERVICE_HOST":
40+
target = value
4041
default:
4142
return nil, fmt.Errorf("unknown mechanism property %s", key)
4243
}
4344
}
4445

45-
hostname, _, err := net.SplitHostPort(target)
46-
if err != nil {
47-
return nil, fmt.Errorf("invalid endpoint (%s) specified: %s", target, err)
48-
}
49-
50-
servicePrincipalName := fmt.Sprintf("%s@%s", serviceName, hostname)
46+
servicePrincipalName := fmt.Sprintf("%s@%s", serviceName, target)
5147

5248
return &SaslClient{
5349
servicePrincipalName: servicePrincipalName,

x/mongo/driver/auth/internal/gssapi/sspi.go

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import (
1919
"unsafe"
2020
)
2121

22-
// New creates a new SaslClient.
22+
// New creates a new SaslClient. The target parameter should be a hostname with no port.
2323
func New(target, username, password string, passwordSet bool, props map[string]string) (*SaslClient, error) {
2424
initOnce.Do(initSSPI)
2525
if initError != nil {
@@ -30,6 +30,7 @@ func New(target, username, password string, passwordSet bool, props map[string]s
3030
serviceName := "mongodb"
3131
serviceRealm := ""
3232
canonicalizeHostName := false
33+
var serviceHostSet bool
3334

3435
for key, value := range props {
3536
switch strings.ToUpper(key) {
@@ -43,25 +44,29 @@ func New(target, username, password string, passwordSet bool, props map[string]s
4344
serviceRealm = value
4445
case "SERVICE_NAME":
4546
serviceName = value
47+
case "SERVICE_HOST":
48+
serviceHostSet = true
49+
target = value
4650
}
4751
}
4852

49-
hostname, _, err := net.SplitHostPort(target)
50-
if err != nil {
51-
return nil, fmt.Errorf("invalid endpoint (%s) specified: %s", target, err)
52-
}
5353
if canonicalizeHostName {
54-
names, err := net.LookupAddr(hostname)
54+
// Should not canonicalize the SERVICE_HOST
55+
if serviceHostSet {
56+
return nil, fmt.Errorf("CANONICALIZE_HOST_NAME and SERVICE_HOST canonot both be specified")
57+
}
58+
59+
names, err := net.LookupAddr(target)
5560
if err != nil || len(names) == 0 {
5661
return nil, fmt.Errorf("unable to canonicalize hostname: %s", err)
5762
}
58-
hostname = names[0]
59-
if hostname[len(hostname)-1] == '.' {
60-
hostname = hostname[:len(hostname)-1]
63+
target = names[0]
64+
if target[len(target)-1] == '.' {
65+
target = target[:len(target)-1]
6166
}
6267
}
6368

64-
servicePrincipalName := fmt.Sprintf("%s/%s", serviceName, hostname)
69+
servicePrincipalName := fmt.Sprintf("%s/%s", serviceName, target)
6570
if serviceRealm != "" {
6671
servicePrincipalName += "@" + serviceRealm
6772
}

0 commit comments

Comments
 (0)