|
|
@@ -15,6 +15,7 @@ import (
|
|
|
"net/http"
|
|
|
"strings"
|
|
|
"time"
|
|
|
+ "net"
|
|
|
)
|
|
|
|
|
|
const (
|
|
|
@@ -75,7 +76,7 @@ func SPNEGOKRB5Authenticate(f http.Handler, ktab keytab.Keytab, l *log.Logger) h
|
|
|
rejectSPNEGO(w, l, fmt.Sprintf("%v - SPNEGO error unmarshalling the authenticator: %v", r.RemoteAddr, err))
|
|
|
return
|
|
|
}
|
|
|
- if ok, err := validateAPREQ(a, mt.APReq); ok {
|
|
|
+ if ok, err := validateAPREQ(a, mt.APReq, r); ok {
|
|
|
cnameStr := a.CName.GetPrincipalNameString()
|
|
|
ctx := r.Context()
|
|
|
ctx = context.WithValue(ctx, "cname", cnameStr)
|
|
|
@@ -94,18 +95,47 @@ func SPNEGOKRB5Authenticate(f http.Handler, ktab keytab.Keytab, l *log.Logger) h
|
|
|
}
|
|
|
|
|
|
// Validate the AP_REQ provided in the SPNEGO NegTokenInit.
|
|
|
-func validateAPREQ(a types.Authenticator, APReq messages.APReq) (bool, error) {
|
|
|
+func validateAPREQ(a types.Authenticator, APReq messages.APReq, r *http.Request) (bool, error) {
|
|
|
// Check CName in Authenticator is the same as that in the ticket
|
|
|
if !a.CName.Equal(APReq.Ticket.DecryptedEncPart.CName) {
|
|
|
err := messages.NewKRBError(APReq.Ticket.SName, APReq.Ticket.Realm, errorcode.KRB_AP_ERR_BADMATCH, "CName in Authenticator does not match that in service ticket")
|
|
|
return false, err
|
|
|
}
|
|
|
- // TODO client address check
|
|
|
- //The addresses in the ticket (if any) are then
|
|
|
- //searched for an address matching the operating-system reported
|
|
|
- //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.
|
|
|
+ if len(APReq.Ticket.DecryptedEncPart.CAddr) > 0 {
|
|
|
+ //The addresses in the ticket (if any) are then
|
|
|
+ //searched for an address matching the operating-system reported
|
|
|
+ //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.
|
|
|
+ cAddr, _, err := net.SplitHostPort(r.RemoteAddr)
|
|
|
+ if err != nil {
|
|
|
+ err := messages.NewKRBError(APReq.Ticket.SName, APReq.Ticket.Realm, errorcode.KRB_AP_ERR_BADADDR, "Invalid format of client address.")
|
|
|
+ return false, err
|
|
|
+ }
|
|
|
+ ip := net.ParseIP(cAddr)
|
|
|
+ hb, err := ip.MarshalText()
|
|
|
+ if err != nil {
|
|
|
+ err := messages.NewKRBError(APReq.Ticket.SName, APReq.Ticket.Realm, errorcode.KRB_AP_ERR_BADADDR, "Could not marshal client's address into bytes.")
|
|
|
+ return false, err
|
|
|
+ }
|
|
|
+ var ht int
|
|
|
+ if ip.To4() != nil {
|
|
|
+ ht = types.AddrType_IPv4
|
|
|
+ } else if ip.To16() != nil {
|
|
|
+ ht = types.AddrType_IPv6
|
|
|
+ } else {
|
|
|
+ err := messages.NewKRBError(APReq.Ticket.SName, APReq.Ticket.Realm, errorcode.KRB_AP_ERR_BADADDR, "Could not determine client's address type.")
|
|
|
+ return false, err
|
|
|
+ }
|
|
|
+ h := types.HostAddress{
|
|
|
+ AddrType: ht,
|
|
|
+ Address: hb,
|
|
|
+ }
|
|
|
+ if !types.HostAddressesContains(APReq.Ticket.DecryptedEncPart.CAddr, h) {
|
|
|
+ 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, err
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
// Check the clock skew between the client and the service server
|
|
|
ct := a.CTime.Add(time.Duration(a.Cusec) * time.Microsecond)
|