Jelajahi Sumber

fix spnego authenticator and config

Jonathan Turner 7 tahun lalu
induk
melakukan
30d8772898

+ 1 - 1
examples/example-AD.go

@@ -66,7 +66,7 @@ func httpServer() *httptest.Server {
 	b, _ := hex.DecodeString(testdata.SYSHTTP_KEYTAB)
 	kt, _ := keytab.Parse(b)
 	th := http.HandlerFunc(testAppHandler)
-	c := service.NewSPNEGOAuthenticator(kt)
+	c := service.NewSPNEGOConfig(kt)
 	c.ServicePrincipal = "sysHTTP"
 	s := httptest.NewServer(service.SPNEGOKRB5Authenticate(th, c, l))
 	return s

+ 3 - 3
examples/example.go

@@ -66,7 +66,7 @@ func httpServer() *httptest.Server {
 	b, _ := hex.DecodeString(testdata.HTTP_KEYTAB)
 	kt, _ := keytab.Parse(b)
 	th := http.HandlerFunc(testAppHandler)
-	c := service.NewSPNEGOAuthenticator(kt)
+	c := service.NewSPNEGOConfig(kt)
 	s := httptest.NewServer(service.SPNEGOKRB5Authenticate(th, c, l))
 	return s
 }
@@ -76,8 +76,8 @@ func testAppHandler(w http.ResponseWriter, r *http.Request) {
 	fmt.Fprint(w, "<html>\n<p><h1>TEST.GOKRB5 Handler</h1></p>\n")
 	if validuser, ok := ctx.Value(service.CTXKeyAuthenticated).(bool); ok && validuser {
 		if creds, ok := ctx.Value(service.CTXKeyCredentials).(goidentity.Identity); ok {
-			fmt.Fprintf(w, "<ul><li>Authenticed user: %s</li>\n", creds.Username)
-			fmt.Fprintf(w, "<li>User's realm: %s</li></ul>\n", creds.Realm)
+			fmt.Fprintf(w, "<ul><li>Authenticed user: %s</li>\n", creds.UserName())
+			fmt.Fprintf(w, "<li>User's realm: %s</li></ul>\n", creds.Domain())
 		}
 
 	} else {

+ 1 - 1
examples/httpServer.go

@@ -34,7 +34,7 @@ func main() {
 
 	// Set up handler mappings wrapping in the SPNEGOKRB5Authenticate handler wrapper
 	mux := http.NewServeMux()
-	c := service.NewSPNEGOAuthenticator(kt)
+	c := service.NewSPNEGOConfig(kt)
 	mux.Handle("/", service.SPNEGOKRB5Authenticate(th, c, l))
 
 	// Start up the web server

+ 6 - 6
service/APExchange.go

@@ -13,9 +13,9 @@ import (
 )
 
 // ValidateAPREQ validates an AP_REQ sent to the service. Returns a boolean for if the AP_REQ is valid and the client's principal name and realm.
-func ValidateAPREQ(APReq messages.APReq, c *SPNEGOAuthenticator) (bool, credentials.Credentials, error) {
+func ValidateAPREQ(APReq messages.APReq, sa SPNEGOAuthenticator) (bool, credentials.Credentials, error) {
 	var creds credentials.Credentials
-	err := APReq.Ticket.DecryptEncPart(*c.Keytab, c.ServicePrincipal)
+	err := APReq.Ticket.DecryptEncPart(sa.Config.Keytab, sa.Config.ServicePrincipal)
 	if err != nil {
 		return false, creds, krberror.Errorf(err, krberror.DecryptingError, "error decrypting encpart of service ticket provided")
 	}
@@ -34,7 +34,7 @@ func ValidateAPREQ(APReq messages.APReq, c *SPNEGOAuthenticator) (bool, credenti
 		//address of the client.  If no match is found or the server insists on
 		//ticket addresses but none are present in the ticket, the
 		//KRB_AP_ERR_BADADDR error is returned.
-		h, err := types.GetHostAddress(c.ClientAddr)
+		h, err := types.GetHostAddress(sa.ClientAddr)
 		if err != nil {
 			err := messages.NewKRBError(APReq.Ticket.SName, APReq.Ticket.Realm, errorcode.KRB_AP_ERR_BADADDR, err.Error())
 			return false, creds, err
@@ -43,7 +43,7 @@ func ValidateAPREQ(APReq messages.APReq, c *SPNEGOAuthenticator) (bool, credenti
 			err := messages.NewKRBError(APReq.Ticket.SName, APReq.Ticket.Realm, errorcode.KRB_AP_ERR_BADADDR, "Client address not within the list contained in the service ticket")
 			return false, creds, err
 		}
-	} else if c.RequireHostAddr {
+	} else if sa.Config.RequireHostAddr {
 		err := messages.NewKRBError(APReq.Ticket.SName, APReq.Ticket.Realm, errorcode.KRB_AP_ERR_BADADDR, "ticket does not contain HostAddress values required")
 		return false, creds, err
 	}
@@ -82,8 +82,8 @@ func ValidateAPREQ(APReq messages.APReq, c *SPNEGOAuthenticator) (bool, credenti
 	creds.SetValidUntil(APReq.Ticket.DecryptedEncPart.EndTime)
 
 	//PAC decoding
-	if !c.DisablePACDecoding {
-		isPAC, pac, err := APReq.Ticket.GetPACType(*c.Keytab, c.ServicePrincipal)
+	if !sa.Config.DisablePACDecoding {
+		isPAC, pac, err := APReq.Ticket.GetPACType(sa.Config.Keytab, sa.Config.ServicePrincipal)
 		if isPAC && err != nil {
 			return false, creds, err
 		}

+ 26 - 8
service/authenticator.go

@@ -17,20 +17,33 @@ import (
 
 // SPNEGOAuthenticator implements gopkg.in/jcmturner/goidentity.v3.Authenticator interface
 type SPNEGOAuthenticator struct {
-	SPNEGOHeaderValue  string
-	Keytab             *keytab.Keytab
+	SPNEGOHeaderValue string
+	ClientAddr        string
+	Config            *SPNEGOConfig
+}
+
+type SPNEGOConfig struct {
+	Keytab             keytab.Keytab
 	ServicePrincipal   string
-	ClientAddr         string
 	RequireHostAddr    bool
 	DisablePACDecoding bool
 }
 
-func NewSPNEGOAuthenticator(kt keytab.Keytab) *SPNEGOAuthenticator {
-	return &SPNEGOAuthenticator{Keytab: &kt}
+func NewSPNEGOAuthenticator(kt keytab.Keytab) (a SPNEGOAuthenticator) {
+	a.Config = NewSPNEGOConfig(kt)
+	return
 }
 
-// Authenticate and retrieve a goidentity.Identity. In this case it is a pointer to a credentials.Credentials
-func (a SPNEGOAuthenticator) Authenticate() (i goidentity.Identity, ok bool, err error) {
+func NewSPNEGOConfig(kt keytab.Keytab) *SPNEGOConfig {
+	return &SPNEGOConfig{Keytab: kt}
+}
+
+func (c *SPNEGOConfig) Authenticate(neg, addr string) (i goidentity.Identity, ok bool, err error) {
+	a := SPNEGOAuthenticator{
+		SPNEGOHeaderValue: neg,
+		ClientAddr:        addr,
+		Config:            c,
+	}
 	b, err := base64.StdEncoding.DecodeString(a.SPNEGOHeaderValue)
 	if err != nil {
 		err = fmt.Errorf("SPNEGO error in base64 decoding negotiation header: %v", err)
@@ -57,7 +70,7 @@ func (a SPNEGOAuthenticator) Authenticate() (i goidentity.Identity, ok bool, err
 		return
 	}
 
-	ok, creds, err := ValidateAPREQ(mt.APReq, &a)
+	ok, creds, err := ValidateAPREQ(mt.APReq, a)
 	if err != nil {
 		err = fmt.Errorf("SPNEGO validation error: %v", err)
 		return
@@ -66,6 +79,11 @@ func (a SPNEGOAuthenticator) Authenticate() (i goidentity.Identity, ok bool, err
 	return
 }
 
+// Authenticate and retrieve a goidentity.Identity. In this case it is a pointer to a credentials.Credentials
+func (a SPNEGOAuthenticator) Authenticate() (i goidentity.Identity, ok bool, err error) {
+	return a.Config.Authenticate(a.SPNEGOHeaderValue, a.ClientAddr)
+}
+
 // Mechanism returns the authentication mechanism.
 func (a SPNEGOAuthenticator) Mechanism() string {
 	return "SPNEGO Kerberos"

+ 2 - 3
service/http.go

@@ -35,7 +35,7 @@ const (
 )
 
 // SPNEGOKRB5Authenticate is a Kerberos SPNEGO authentication HTTP handler wrapper.
-func SPNEGOKRB5Authenticate(f http.Handler, c *SPNEGOAuthenticator, l *log.Logger) http.Handler {
+func SPNEGOKRB5Authenticate(f http.Handler, c *SPNEGOConfig, l *log.Logger) http.Handler {
 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		s := strings.SplitN(r.Header.Get(HTTPHeaderAuthRequest), " ", 2)
 		if len(s) != 2 || s[0] != HTTPHeaderAuthResponseValueKey {
@@ -44,8 +44,7 @@ func SPNEGOKRB5Authenticate(f http.Handler, c *SPNEGOAuthenticator, l *log.Logge
 			w.Write([]byte(UnauthorizedMsg))
 			return
 		}
-		c.SPNEGOHeaderValue = s[1]
-		id, authned, err := c.Authenticate()
+		id, authned, err := c.Authenticate(s[1], r.RemoteAddr)
 		if err != nil {
 			rejectSPNEGO(w, l, fmt.Sprintf("%v - %v", r.RemoteAddr, err))
 			return

+ 1 - 1
service/http_test.go

@@ -246,7 +246,7 @@ func httpServer() *httptest.Server {
 	b, _ := hex.DecodeString(testdata.HTTP_KEYTAB)
 	kt, _ := keytab.Parse(b)
 	th := http.HandlerFunc(testAppHandler)
-	c := NewSPNEGOAuthenticator(kt)
+	c := NewSPNEGOConfig(kt)
 	s := httptest.NewServer(SPNEGOKRB5Authenticate(th, c, l))
 	return s
 }