Jonathan Turner před 9 roky
rodič
revize
017bdf9859
5 změnil soubory, kde provedl 63 přidání a 24 odebrání
  1. 2 2
      GSSAPI/NegotiationToken.go
  2. 2 2
      GSSAPI/gssapi.go
  3. 8 3
      client/http.go
  4. 38 5
      debug.go
  5. 13 12
      service/http.go

+ 2 - 2
GSSAPI/NegotiationToken.go

@@ -76,14 +76,14 @@ func UnmarshalNegToken(b []byte) (bool, interface{}, error) {
 		var negToken NegTokenInit
 		_, err = asn1.Unmarshal(a.Bytes, &negToken)
 		if err != nil {
-			return false, nil, fmt.Errorf("Error unmarshalling NegotiationToken type %d: %v", a.Tag, err)
+			return false, nil, fmt.Errorf("Error unmarshalling NegotiationToken type %d (Init): %v", a.Tag, err)
 		}
 		return true, negToken, nil
 	case 1:
 		var negToken NegTokenResp
 		_, err = asn1.Unmarshal(a.Bytes, &negToken)
 		if err != nil {
-			return false, nil, fmt.Errorf("Error unmarshalling NegotiationToken type %d: %v", a.Tag, err)
+			return false, nil, fmt.Errorf("Error unmarshalling NegotiationToken type %d (Resp/Targ): %v", a.Tag, err)
 		}
 		return false, negToken, nil
 	default:

+ 2 - 2
GSSAPI/gssapi.go

@@ -46,13 +46,13 @@ func (s *SPNEGO) Unmarshal(b []byte) error {
 	case 0:
 		_, err = asn1.Unmarshal(a.Bytes, &s.NegTokenInit)
 		if err != nil {
-			return fmt.Errorf("Error unmarshalling NegotiationToken type %d: %v", a.Tag, err)
+			return fmt.Errorf("Error unmarshalling NegotiationToken type %d (Init): %v", a.Tag, err)
 		}
 		s.Init = true
 	case 1:
 		_, err = asn1.Unmarshal(a.Bytes, &s.NegTokenResp)
 		if err != nil {
-			return fmt.Errorf("Error unmarshalling NegotiationToken type %d: %v", a.Tag, err)
+			return fmt.Errorf("Error unmarshalling NegotiationToken type %d (Resp/Targ): %v", a.Tag, err)
 		}
 		s.Resp = true
 	default:

+ 8 - 3
client/http.go

@@ -5,11 +5,16 @@ import (
 	"fmt"
 	"github.com/jcmturner/gokrb5/GSSAPI"
 	"net/http"
+	"strings"
 )
 
-// Get service ticket and set as the SPNEGO authorization header on HTTP request object
-func (cl *Client) SetSPNEGOHeader(HTTPReq *http.Request) error {
-	tkt, skey, err := cl.GetServiceTicket("HTTP/" + HTTPReq.Host)
+// Get service ticket and set as the SPNEGO authorization header on HTTP request object.
+// To auto generate the SPN from the request object pass a null string "".
+func (cl *Client) SetSPNEGOHeader(HTTPReq *http.Request, spn string) error {
+	if spn == "" {
+		spn = "HTTP/" + strings.SplitN(HTTPReq.Host, ":", 2)[0]
+	}
+	tkt, skey, err := cl.GetServiceTicket(spn)
 	if err != nil {
 		return fmt.Errorf("Could not get service ticket: %v", err)
 	}

+ 38 - 5
debug.go

@@ -6,8 +6,12 @@ import (
 	"github.com/jcmturner/gokrb5/client"
 	"github.com/jcmturner/gokrb5/config"
 	"github.com/jcmturner/gokrb5/keytab"
+	"github.com/jcmturner/gokrb5/service"
 	"github.com/jcmturner/gokrb5/testdata"
+	"io/ioutil"
+	"log"
 	"net/http"
+	"net/http/httptest"
 	"os"
 	"time"
 )
@@ -34,7 +38,10 @@ const krb5conf = `[libdefaults]
  `
 
 func main() {
-	httpRequest()
+	s := httpServer(false)
+	defer s.Close()
+	//httpRequest("http://host.test.gokrb5/index.html")
+	httpRequest(s.URL)
 	//runClient()
 }
 
@@ -61,7 +68,7 @@ func runClient() {
 	}
 }
 
-func httpRequest() {
+func httpRequest(url string) {
 	b, err := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
 	kt, _ := keytab.Parse(b)
 	c, _ := config.NewConfigFromString(krb5conf)
@@ -72,8 +79,34 @@ func httpRequest() {
 	if err != nil {
 		fmt.Fprintf(os.Stderr, "Error on AS_REQ: %v\n", err)
 	}
-	r, _ := http.NewRequest("GET", "http://host.test.gokrb5/index.html", nil)
-	cl.SetSPNEGOHeader(r)
+	r, _ := http.NewRequest("GET", url, nil)
+	err = cl.SetSPNEGOHeader(r, "HTTP/host.test.gokrb5")
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Error setting client SPNEGO header: %v", err)
+	}
 	httpResp, err := http.DefaultClient.Do(r)
-	fmt.Fprintf(os.Stderr, "RESPONSE CODE: %v\n", httpResp.StatusCode)
+	fmt.Fprintf(os.Stderr, "Request error: %v\n", err)
+	fmt.Fprintf(os.Stdout, "RESPONSE CODE: %v\n", httpResp.StatusCode)
+	content, _ := ioutil.ReadAll(httpResp.Body)
+	fmt.Fprintf(os.Stdout, "ResponseBody: %s\n", content)
+}
+
+func httpServer(tls bool) *httptest.Server {
+	l := log.New(os.Stderr, "GOKRB5: ", log.Ldate|log.Ltime|log.Lshortfile)
+	ks := "0502000000580002000b544553542e474f4b5242350004485454500010686f73742e746573742e676f6b7262350000000158e7d0360300120020c2bcd4abcde0d2608d5f505e7ab5dc92df5f627e5819703c0b0f1d2c05d51c1600000003000000480002000b544553542e474f4b5242350004485454500010686f73742e746573742e676f6b7262350000000158e7d0360300110010da152175c7a73f49e5ce4ece7068856400000003000000500002000b544553542e474f4b5242350004485454500010686f73742e746573742e676f6b7262350000000158e7d03603001000187fc8ef5276e083da6bf89e676d7f98fd1acb9ec2cb20083d00000003000000480002000b544553542e474f4b5242350004485454500010686f73742e746573742e676f6b7262350000000158e7d0360300170010011f2ef8e75e8378a94154beb002163200000003000000580002000b544553542e474f4b5242350004485454500010686f73742e746573742e676f6b7262350000000158e7d03603001a0020f9db4e36aad9688d9ea30dbcc269c7ee46bf4f8bd6250f203a9f3836f0a673a600000003000000480002000b544553542e474f4b5242350004485454500010686f73742e746573742e676f6b7262350000000158e7d0360300190010434981c9dce61ae1012f808bb60fc1c900000003000000400002000b544553542e474f4b5242350004485454500010686f73742e746573742e676f6b7262350000000158e7d03603000800080b0d4f31e061529800000003000000400002000b544553542e474f4b5242350004485454500010686f73742e746573742e676f6b7262350000000158e7d0360300030008f7df40f457aec42c00000003"
+	b, _ := hex.DecodeString(ks)
+	kt, _ := keytab.Parse(b)
+	th := http.HandlerFunc(testAppHandler)
+	if tls {
+		s := httptest.NewTLSServer(service.SPNEGOKRB5Authenticate(th, kt, l))
+		return s
+	} else {
+		s := httptest.NewServer(service.SPNEGOKRB5Authenticate(th, kt, l))
+		return s
+	}
+}
+
+func testAppHandler(w http.ResponseWriter, r *http.Request) {
+	w.WriteHeader(http.StatusOK)
+	fmt.Fprintln(w, "TEST.GOKRB5 Handler")
 }

+ 13 - 12
service/http.go

@@ -13,6 +13,7 @@ import (
 	"github.com/jcmturner/gokrb5/types"
 	"log"
 	"net/http"
+	"os"
 	"strings"
 	"time"
 )
@@ -24,8 +25,8 @@ const (
 )
 
 // SPNEGO Kerberos HTTP handler wrapper
-func SPNEGOKRB5Authenticate(f http.HandlerFunc, ktab keytab.Keytab, l *log.Logger) http.HandlerFunc {
-	return func(w http.ResponseWriter, r *http.Request) {
+func SPNEGOKRB5Authenticate(f http.Handler, ktab keytab.Keytab, l *log.Logger) http.Handler {
+	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
 		if len(s) != 2 || s[0] != "Negotiate" {
 			w.Header().Set("WWW-Authenticate", "Negotiate")
@@ -38,18 +39,18 @@ func SPNEGOKRB5Authenticate(f http.HandlerFunc, ktab keytab.Keytab, l *log.Logge
 			rejectSPNEGO(w, l, fmt.Sprintf("%v - SPNEGO error in base64 decoding negotiation header: %v", r.RemoteAddr, err))
 			return
 		}
-		isInit, nt, err := GSSAPI.UnmarshalNegToken(b)
-		if err != nil || !isInit {
+		var spnego GSSAPI.SPNEGO
+		err = spnego.Unmarshal(b)
+		if !spnego.Init {
 			rejectSPNEGO(w, l, fmt.Sprintf("%v - SPNEGO negotiation token is not a NegTokenInit: %v", r.RemoteAddr, err))
 			return
 		}
-		nInit := nt.(GSSAPI.NegTokenInit)
-		if !nInit.MechTypes[0].Equal(GSSAPI.MechTypeOID_Krb5) {
+		if !spnego.NegTokenInit.MechTypes[0].Equal(GSSAPI.MechTypeOID_Krb5) {
 			rejectSPNEGO(w, l, fmt.Sprintf("%v - SPNEGO OID of MechToken is not of type KRB5", r.RemoteAddr))
 			return
 		}
 		var mt GSSAPI.MechToken
-		err = mt.Unmarshal(nInit.MechToken)
+		err = mt.Unmarshal(spnego.NegTokenInit.MechToken)
 		if err != nil {
 			rejectSPNEGO(w, l, fmt.Sprintf("%v - SPNEGO error unmarshaling MechToken: %v", r.RemoteAddr, err))
 			return
@@ -84,13 +85,13 @@ func SPNEGOKRB5Authenticate(f http.HandlerFunc, ktab keytab.Keytab, l *log.Logge
 				l.Printf("SPNEGO authentication succeeded: %v %s@%s", r.RemoteAddr, cnameStr, a.CRealm)
 			}
 			w.Header().Set("WWW-Authenticate", SPNEGO_NegTokenResp_Krb_Accept_Completed)
-
-			f(w, r.WithContext(ctx))
+			fmt.Fprintln(os.Stderr, "AUTHED")
+			f.ServeHTTP(w, r.WithContext(ctx))
 		} else {
 			rejectSPNEGO(w, l, fmt.Sprintf("%v - SPNEGO Kerberos authentication failed: %v", r.RemoteAddr, err))
 			return
 		}
-	}
+	})
 }
 
 func validateAPREQ(a types.Authenticator, APReq messages.APReq) (bool, error) {
@@ -134,7 +135,7 @@ func validateAPREQ(a types.Authenticator, APReq messages.APReq) (bool, error) {
 		err := messages.NewKRBError(APReq.Ticket.SName, APReq.Ticket.Realm, errorcode.KRB_AP_ERR_TKT_EXPIRED, "Service ticket provided has expired")
 		return false, err
 	}
-	return true
+	return true, nil
 }
 
 func rejectSPNEGO(w http.ResponseWriter, l *log.Logger, logMsg string) {
@@ -142,6 +143,6 @@ func rejectSPNEGO(w http.ResponseWriter, l *log.Logger, logMsg string) {
 		l.Println(logMsg)
 	}
 	w.Header().Set("WWW-Authenticate", SPNEGO_NegTokenResp_Reject)
-	w.WriteHeader(401)
+	w.WriteHeader(http.StatusUnauthorized)
 	w.Write([]byte("Unauthorised.\n"))
 }