Browse code

Test gssapi library load when selecting available challenge handlers

Jordan Liggitt authored on 2016/07/15 12:50:11
Showing 4 changed files
... ...
@@ -11,6 +11,9 @@ import (
11 11
 
12 12
 // Negotiater defines the minimal interface needed to interact with GSSAPI to perform a negotiate challenge/response
13 13
 type Negotiater interface {
14
+	// Load gives the negotiator a chance to load any resources needed to handle a challenge/response sequence.
15
+	// It may be invoked multiple times. If an error is returned, InitSecContext and IsComplete are not called, but Release() is.
16
+	Load() error
14 17
 	// InitSecContext returns the response token for a Negotiate challenge token from a given URL,
15 18
 	// or an error if no response token could be obtained or the incoming token is invalid.
16 19
 	InitSecContext(requestURL string, challengeToken []byte) (tokenToSend []byte, err error)
... ...
@@ -34,8 +37,14 @@ func NewNegotiateChallengeHandler(negotiater Negotiater) ChallengeHandler {
34 34
 
35 35
 func (c *NegotiateChallengeHandler) CanHandle(headers http.Header) bool {
36 36
 	// Make sure this is a negotiate request
37
-	isNegotiate, _, err := getNegotiateToken(headers)
38
-	return err == nil && isNegotiate
37
+	if isNegotiate, _, err := getNegotiateToken(headers); err != nil || !isNegotiate {
38
+		return false
39
+	}
40
+	// Make sure our negotiator can initialize
41
+	if err := c.negotiater.Load(); err != nil {
42
+		return false
43
+	}
44
+	return true
39 45
 }
40 46
 
41 47
 func (c *NegotiateChallengeHandler) HandleChallenge(requestURL string, headers http.Header) (http.Header, bool, error) {
... ...
@@ -49,6 +49,11 @@ func NewGSSAPINegotiator(principalName string) Negotiater {
49 49
 	return &gssapiNegotiator{principalName: principalName}
50 50
 }
51 51
 
52
+func (g *gssapiNegotiator) Load() error {
53
+	_, err := g.loadLib()
54
+	return err
55
+}
56
+
52 57
 func (g *gssapiNegotiator) InitSecContext(requestURL string, challengeToken []byte) (tokenToSend []byte, err error) {
53 58
 	lib, err := g.loadLib()
54 59
 	if err != nil {
... ...
@@ -14,6 +14,9 @@ func NewGSSAPINegotiator(principalName string) Negotiater {
14 14
 	return &gssapiUnsupported{}
15 15
 }
16 16
 
17
+func (g *gssapiUnsupported) Load() error {
18
+	return errors.New("GSSAPI support is not enabled")
19
+}
17 20
 func (g *gssapiUnsupported) InitSecContext(requestURL string, challengeToken []byte) (tokenToSend []byte, err error) {
18 21
 	return nil, errors.New("GSSAPI support is not enabled")
19 22
 }
... ...
@@ -11,10 +11,31 @@ import (
11 11
 	"k8s.io/kubernetes/pkg/client/restclient"
12 12
 )
13 13
 
14
+type unloadableNegotiator struct {
15
+	releaseCalls int
16
+}
17
+
18
+func (n *unloadableNegotiator) Load() error {
19
+	return errors.New("Load failed")
20
+}
21
+func (n *unloadableNegotiator) InitSecContext(requestURL string, challengeToken []byte) (tokenToSend []byte, err error) {
22
+	return nil, errors.New("InitSecContext failed")
23
+}
24
+func (n *unloadableNegotiator) IsComplete() bool {
25
+	return false
26
+}
27
+func (n *unloadableNegotiator) Release() error {
28
+	n.releaseCalls++
29
+	return errors.New("Release failed")
30
+}
31
+
14 32
 type failingNegotiator struct {
15 33
 	releaseCalls int
16 34
 }
17 35
 
36
+func (n *failingNegotiator) Load() error {
37
+	return nil
38
+}
18 39
 func (n *failingNegotiator) InitSecContext(requestURL string, challengeToken []byte) (tokenToSend []byte, err error) {
19 40
 	return nil, errors.New("InitSecContext failed")
20 41
 }
... ...
@@ -29,9 +50,14 @@ func (n *failingNegotiator) Release() error {
29 29
 type successfulNegotiator struct {
30 30
 	rounds              int
31 31
 	initSecContextCalls int
32
+	loadCalls           int
32 33
 	releaseCalls        int
33 34
 }
34 35
 
36
+func (n *successfulNegotiator) Load() error {
37
+	n.loadCalls++
38
+	return nil
39
+}
35 40
 func (n *successfulNegotiator) InitSecContext(requestURL string, challengeToken []byte) (tokenToSend []byte, err error) {
36 41
 	n.initSecContextCalls++
37 42
 
... ...
@@ -94,6 +120,10 @@ func TestRequestToken(t *testing.T) {
94 94
 				if negotiator.releaseCalls != 1 {
95 95
 					t.Errorf("%s: expected one call to Release(), saw %d", test, negotiator.releaseCalls)
96 96
 				}
97
+			case *unloadableNegotiator:
98
+				if negotiator.releaseCalls != 1 {
99
+					t.Errorf("%s: expected one call to Release(), saw %d", test, negotiator.releaseCalls)
100
+				}
97 101
 			default:
98 102
 				t.Errorf("%s: unrecognized negotiator: %#v", test, handler)
99 103
 			}
... ...
@@ -255,6 +285,29 @@ func TestRequestToken(t *testing.T) {
255 255
 			ExpectedError: "client requires final negotiate token, none provided",
256 256
 		},
257 257
 
258
+		// Unloadable negotiate handler
259
+		"unloadable negotiate handler, no challenge, success": {
260
+			Handler: &NegotiateChallengeHandler{negotiater: &unloadableNegotiator{}},
261
+			Requests: []requestResponse{
262
+				{initialRequest, success},
263
+			},
264
+			ExpectedToken: successfulToken,
265
+		},
266
+		"unloadable negotiate handler, negotiate challenge, failure": {
267
+			Handler: &NegotiateChallengeHandler{negotiater: &unloadableNegotiator{}},
268
+			Requests: []requestResponse{
269
+				{initialRequest, negotiateChallenge1},
270
+			},
271
+			ExpectedError: "unhandled challenge",
272
+		},
273
+		"unloadable negotiate handler, basic challenge, failure": {
274
+			Handler: &NegotiateChallengeHandler{negotiater: &unloadableNegotiator{}},
275
+			Requests: []requestResponse{
276
+				{initialRequest, basicChallenge1},
277
+			},
278
+			ExpectedError: "unhandled challenge",
279
+		},
280
+
258 281
 		// Failing negotiate handler
259 282
 		"failing negotiate handler, no challenge, success": {
260 283
 			Handler: &NegotiateChallengeHandler{negotiater: &failingNegotiator{}},