github.com/coreos/goproxy@v0.0.0-20190513173959-f8dc2d7ba04e/ext/auth/basic.go (about) 1 package auth 2 3 import ( 4 "bytes" 5 "encoding/base64" 6 "io/ioutil" 7 "net/http" 8 "strings" 9 10 "github.com/elazarl/goproxy" 11 ) 12 13 var unauthorizedMsg = []byte("407 Proxy Authentication Required") 14 15 func BasicUnauthorized(req *http.Request, realm string) *http.Response { 16 // TODO(elazar): verify realm is well formed 17 return &http.Response{ 18 StatusCode: 407, 19 ProtoMajor: 1, 20 ProtoMinor: 1, 21 Request: req, 22 Header: http.Header{"Proxy-Authenticate": []string{"Basic realm=" + realm}}, 23 Body: ioutil.NopCloser(bytes.NewBuffer(unauthorizedMsg)), 24 ContentLength: int64(len(unauthorizedMsg)), 25 } 26 } 27 28 var proxyAuthorizationHeader = "Proxy-Authorization" 29 30 func auth(req *http.Request, f func(user, passwd string) bool) bool { 31 authheader := strings.SplitN(req.Header.Get(proxyAuthorizationHeader), " ", 2) 32 req.Header.Del(proxyAuthorizationHeader) 33 if len(authheader) != 2 || authheader[0] != "Basic" { 34 return false 35 } 36 userpassraw, err := base64.StdEncoding.DecodeString(authheader[1]) 37 if err != nil { 38 return false 39 } 40 userpass := strings.SplitN(string(userpassraw), ":", 2) 41 if len(userpass) != 2 { 42 return false 43 } 44 return f(userpass[0], userpass[1]) 45 } 46 47 // Basic returns a basic HTTP authentication handler for requests 48 // 49 // You probably want to use auth.ProxyBasic(proxy) to enable authentication for all proxy activities 50 func Basic(realm string, f func(user, passwd string) bool) goproxy.ReqHandler { 51 return goproxy.FuncReqHandler(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { 52 if !auth(req, f) { 53 return nil, BasicUnauthorized(req, realm) 54 } 55 return req, nil 56 }) 57 } 58 59 // BasicConnect returns a basic HTTP authentication handler for CONNECT requests 60 // 61 // You probably want to use auth.ProxyBasic(proxy) to enable authentication for all proxy activities 62 func BasicConnect(realm string, f func(user, passwd string) bool) goproxy.HttpsHandler { 63 return goproxy.FuncHttpsHandler(func(host string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) { 64 if !auth(ctx.Req, f) { 65 ctx.Resp = BasicUnauthorized(ctx.Req, realm) 66 return goproxy.RejectConnect, host 67 } 68 return goproxy.OkConnect, host 69 }) 70 } 71 72 // ProxyBasic will force HTTP authentication before any request to the proxy is processed 73 func ProxyBasic(proxy *goproxy.ProxyHttpServer, realm string, f func(user, passwd string) bool) { 74 proxy.OnRequest().Do(Basic(realm, f)) 75 proxy.OnRequest().HandleConnect(BasicConnect(realm, f)) 76 }