http.go 3.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. package service
  2. import (
  3. "context"
  4. "fmt"
  5. "log"
  6. "net/http"
  7. "strings"
  8. )
  9. // POTENTIAL BREAKING CHANGE notice. Context keys used will change to a name-spaced strings to avoid clashes.
  10. // If you are using the constants service.CTXKeyAuthenticated and service.CTXKeyCredentials
  11. // defined below when retrieving data from the request context your code will be unaffected.
  12. // However if, for example, you are retrieving context like this: r.Context().Value(1) then
  13. // you will need to update to replace the 1 with service.CTXKeyCredentials.
  14. type ctxKey int
  15. const (
  16. // spnegoNegTokenRespKRBAcceptCompleted - The response on successful authentication always has this header. Capturing as const so we don't have marshaling and encoding overhead.
  17. spnegoNegTokenRespKRBAcceptCompleted = "Negotiate oRQwEqADCgEAoQsGCSqGSIb3EgECAg=="
  18. // spnegoNegTokenRespReject - The response on a failed authentication always has this rejection header. Capturing as const so we don't have marshaling and encoding overhead.
  19. spnegoNegTokenRespReject = "Negotiate oQcwBaADCgEC"
  20. // CTXKeyAuthenticated is the request context key holding a boolean indicating if the request has been authenticated.
  21. CTXKeyAuthenticated ctxKey = 0
  22. // CTXKeyCredentials is the request context key holding the credentials gopkg.in/jcmturner/goidentity.v2/Identity object.
  23. CTXKeyCredentials ctxKey = 1
  24. // HTTPHeaderAuthRequest is the header that will hold authn/z information.
  25. HTTPHeaderAuthRequest = "Authorization"
  26. // HTTPHeaderAuthResponse is the header that will hold SPNEGO data from the server.
  27. HTTPHeaderAuthResponse = "WWW-Authenticate"
  28. // HTTPHeaderAuthResponseValueKey is the key in the auth header for SPNEGO.
  29. HTTPHeaderAuthResponseValueKey = "Negotiate"
  30. // UnauthorizedMsg is the message returned in the body when authentication fails.
  31. UnauthorizedMsg = "Unauthorised.\n"
  32. )
  33. // SPNEGOKRB5Authenticate is a Kerberos SPNEGO authentication HTTP handler wrapper.
  34. func SPNEGOKRB5Authenticate(f http.Handler, c *Config, l *log.Logger) http.Handler {
  35. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  36. s := strings.SplitN(r.Header.Get(HTTPHeaderAuthRequest), " ", 2)
  37. if len(s) != 2 || s[0] != HTTPHeaderAuthResponseValueKey {
  38. w.Header().Set(HTTPHeaderAuthResponse, HTTPHeaderAuthResponseValueKey)
  39. w.WriteHeader(401)
  40. w.Write([]byte(UnauthorizedMsg))
  41. return
  42. }
  43. id, authned, err := c.Authenticate(s[1], r.RemoteAddr)
  44. if err != nil {
  45. rejectSPNEGO(w, l, fmt.Sprintf("%v - %v", r.RemoteAddr, err))
  46. return
  47. }
  48. if authned {
  49. ctx := r.Context()
  50. ctx = context.WithValue(ctx, CTXKeyCredentials, id)
  51. ctx = context.WithValue(ctx, CTXKeyAuthenticated, true)
  52. if l != nil {
  53. l.Printf("%v %s@%s - SPNEGO authentication succeeded", r.RemoteAddr, id.UserName(), id.Domain())
  54. }
  55. spnegoResponseAcceptCompleted(w)
  56. f.ServeHTTP(w, r.WithContext(ctx))
  57. } else {
  58. rejectSPNEGO(w, l, fmt.Sprintf("%v - SPNEGO Kerberos authentication failed: %v", r.RemoteAddr, err))
  59. return
  60. }
  61. return
  62. })
  63. }
  64. // Set the headers for a rejected SPNEGO negotiation and return an unauthorized status code.
  65. func rejectSPNEGO(w http.ResponseWriter, l *log.Logger, logMsg string) {
  66. if l != nil {
  67. l.Println(logMsg)
  68. }
  69. spnegoResponseReject(w)
  70. }
  71. func spnegoResponseReject(w http.ResponseWriter) {
  72. w.Header().Set(HTTPHeaderAuthResponse, spnegoNegTokenRespReject)
  73. w.WriteHeader(http.StatusUnauthorized)
  74. w.Write([]byte(UnauthorizedMsg))
  75. }
  76. func spnegoResponseAcceptCompleted(w http.ResponseWriter) {
  77. w.Header().Set(HTTPHeaderAuthResponse, spnegoNegTokenRespKRBAcceptCompleted)
  78. }