Skip to content

Commit

Permalink
Merge pull request #11371 from enj/enj/f/sspi
Browse files Browse the repository at this point in the history
Implement SSPI Support on Windows (oc Kerberos)
  • Loading branch information
openshift-merge-robot authored Jul 13, 2018
2 parents a8ae00e + 919477b commit fdde50e
Show file tree
Hide file tree
Showing 33 changed files with 3,618 additions and 63 deletions.
13 changes: 9 additions & 4 deletions glide.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions glide.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ import:
# auth (for oc kerberos on linux + mac)
- package: github.com/apcera/gssapi
version: release-2.6.3
# auth (for oc kerberos on windows)
- package: github.com/alexbrainman/sspi
version: e580b900e9f5657daa5473021296289be6da2661
# new-app
- package: github.com/joho/godotenv
version: 6d367c18edf6ca7fd004efd6863e4c5728fa858e
Expand Down
9 changes: 7 additions & 2 deletions pkg/oc/cli/cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,13 @@ func (o VersionOptions) RunVersion() error {
}
if tokencmd.GSSAPIEnabled() {
features = append(features, "GSSAPI")
features = append(features, "Kerberos") // GSSAPI or SSPI
features = append(features, "SPNEGO") // GSSAPI or SSPI
}
if tokencmd.SSPIEnabled() {
features = append(features, "SSPI")
}
if tokencmd.GSSAPIEnabled() || tokencmd.SSPIEnabled() {
features = append(features, "Kerberos")
features = append(features, "SPNEGO")
}
fmt.Printf("features: %s\n", strings.Join(features, " "))
}
Expand Down
22 changes: 11 additions & 11 deletions pkg/oc/util/tokencmd/negotiate.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (
"github.com/golang/glog"
)

// Negotiater defines the minimal interface needed to interact with GSSAPI to perform a negotiate challenge/response
type Negotiater interface {
// Negotiator defines the minimal interface needed to interact with GSSAPI to perform a negotiate challenge/response
type Negotiator interface {
// Load gives the negotiator a chance to load any resources needed to handle a challenge/response sequence.
// It may be invoked multiple times. If an error is returned, InitSecContext and IsComplete are not called, but Release() is.
Load() error
Expand All @@ -28,11 +28,11 @@ type Negotiater interface {
// NegotiateChallengeHandler manages a challenge negotiation session
// it is single-host, single-use only, and not thread-safe
type NegotiateChallengeHandler struct {
negotiater Negotiater
negotiator Negotiator
}

func NewNegotiateChallengeHandler(negotiater Negotiater) ChallengeHandler {
return &NegotiateChallengeHandler{negotiater: negotiater}
func NewNegotiateChallengeHandler(negotiator Negotiator) ChallengeHandler {
return &NegotiateChallengeHandler{negotiator: negotiator}
}

func (c *NegotiateChallengeHandler) CanHandle(headers http.Header) bool {
Expand All @@ -41,7 +41,7 @@ func (c *NegotiateChallengeHandler) CanHandle(headers http.Header) bool {
return false
}
// Make sure our negotiator can initialize
if err := c.negotiater.Load(); err != nil {
if err := c.negotiator.Load(); err != nil {
return false
}
return true
Expand All @@ -55,7 +55,7 @@ func (c *NegotiateChallengeHandler) HandleChallenge(requestURL string, headers h
}

// Process the token
outgoingToken, err := c.negotiater.InitSecContext(requestURL, incomingToken)
outgoingToken, err := c.negotiator.InitSecContext(requestURL, incomingToken)
if err != nil {
glog.V(5).Infof("InitSecContext returned error: %v", err)
return nil, false, err
Expand All @@ -68,7 +68,7 @@ func (c *NegotiateChallengeHandler) HandleChallenge(requestURL string, headers h
}

func (c *NegotiateChallengeHandler) CompleteChallenge(requestURL string, headers http.Header) error {
if c.negotiater.IsComplete() {
if c.negotiator.IsComplete() {
return nil
}
glog.V(5).Infof("continue needed")
Expand All @@ -83,19 +83,19 @@ func (c *NegotiateChallengeHandler) CompleteChallenge(requestURL string, headers
}

// Process the token
_, err = c.negotiater.InitSecContext(requestURL, incomingToken)
_, err = c.negotiator.InitSecContext(requestURL, incomingToken)
if err != nil {
glog.V(5).Infof("InitSecContext returned error during final negotiation: %v", err)
return err
}
if !c.negotiater.IsComplete() {
if !c.negotiator.IsComplete() {
return errors.New("InitSecContext did not indicate final negotiation completed")
}
return nil
}

func (c *NegotiateChallengeHandler) Release() error {
return c.negotiater.Release()
return c.negotiator.Release()
}

const negotiateScheme = "negotiate"
Expand Down
39 changes: 39 additions & 0 deletions pkg/oc/util/tokencmd/negotiate_helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package tokencmd

import (
"errors"
"net/url"
)

func getServiceName(sep rune, requestURL string) (string, error) {
u, err := url.Parse(requestURL)
if err != nil {
return "", err
}

return "HTTP" + string(sep) + u.Hostname(), nil
}

type negotiateUnsupported struct {
error
}

func newUnsupportedNegotiator(name string) Negotiator {
return &negotiateUnsupported{error: errors.New(name + " support is not enabled")}
}

func (n *negotiateUnsupported) Load() error {
return n
}

func (n *negotiateUnsupported) InitSecContext(requestURL string, challengeToken []byte) ([]byte, error) {
return nil, n
}

func (*negotiateUnsupported) IsComplete() bool {
return false
}

func (n *negotiateUnsupported) Release() error {
return n
}
12 changes: 2 additions & 10 deletions pkg/oc/util/tokencmd/negotiator_gssapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ package tokencmd

import (
"errors"
"net"
"net/url"
"runtime"
"sync"
"time"
Expand Down Expand Up @@ -46,7 +44,7 @@ type gssapiNegotiator struct {
complete bool
}

func NewGSSAPINegotiator(principalName string) Negotiater {
func NewGSSAPINegotiator(principalName string) Negotiator {
return &gssapiNegotiator{principalName: principalName}
}

Expand Down Expand Up @@ -90,17 +88,11 @@ func (g *gssapiNegotiator) InitSecContext(requestURL string, challengeToken []by
g.cred = lib.GSS_C_NO_CREDENTIAL
}

u, err := url.Parse(requestURL)
serviceName, err := getServiceName('@', requestURL)
if err != nil {
return nil, err
}

hostname := u.Host
if h, _, err := net.SplitHostPort(u.Host); err == nil {
hostname = h
}

serviceName := "HTTP@" + hostname
glog.V(5).Infof("importing service name %s", serviceName)
nameBuf, err := lib.MakeBufferString(serviceName)
if err != nil {
Expand Down
21 changes: 2 additions & 19 deletions pkg/oc/util/tokencmd/negotiator_gssapi_unsupported.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,10 @@

package tokencmd

import "errors"

func GSSAPIEnabled() bool {
return false
}

type gssapiUnsupported struct{}

func NewGSSAPINegotiator(principalName string) Negotiater {
return &gssapiUnsupported{}
}

func (g *gssapiUnsupported) Load() error {
return errors.New("GSSAPI support is not enabled")
}
func (g *gssapiUnsupported) InitSecContext(requestURL string, challengeToken []byte) (tokenToSend []byte, err error) {
return nil, errors.New("GSSAPI support is not enabled")
}
func (g *gssapiUnsupported) IsComplete() bool {
return false
}
func (g *gssapiUnsupported) Release() error {
return errors.New("GSSAPI support is not enabled")
func NewGSSAPINegotiator(string) Negotiator {
return newUnsupportedNegotiator("GSSAPI")
}
Loading

0 comments on commit fdde50e

Please sign in to comment.