From aef413da0adb45a7bfd0b92c9222241ef8b39a03 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Fri, 15 Nov 2019 16:58:19 +0100 Subject: [PATCH] auth+proxy: forward auth to backend --- auth/authenticator.go | 26 ++++++++++++++++++++++---- proxy/proxy.go | 17 +++++++++++++---- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/auth/authenticator.go b/auth/authenticator.go index be91a1f..e7d2123 100644 --- a/auth/authenticator.go +++ b/auth/authenticator.go @@ -29,6 +29,7 @@ const ( var ( authRegex = regexp.MustCompile("LSAT (.*?):([a-f0-9]{64})") + authFormat = "LSAT %s:%s" opWildcard = "*" ) @@ -65,7 +66,7 @@ func (l *LsatAuthenticator) Accept(header *http.Header) bool { // Try reading the macaroon and preimage from the HTTP header. This can // be in different header fields depending on the implementation and/or // protocol. - mac, preimageBytes, err := authFromHeader(header) + mac, preimageBytes, err := FromHeader(header) if err != nil { log.Debugf("Deny: %v", err) return false @@ -125,7 +126,7 @@ func (l *LsatAuthenticator) FreshChallengeHeader(r *http.Request) ( return header, nil } -// authFromHeader tries to extract authentication information from HTTP headers. +// FromHeader tries to extract authentication information from HTTP headers. // There are two supported formats that can be sent in three different header // fields: // 1. Authorization: LSAT : @@ -133,7 +134,7 @@ func (l *LsatAuthenticator) FreshChallengeHeader(r *http.Request) ( // 3. Macaroon: // If only the macaroon is sent in header 2 or three then it is expected to have // a caveat with the preimage attached to it. -func authFromHeader(header *http.Header) (*macaroon.Macaroon, []byte, error) { +func FromHeader(header *http.Header) (*macaroon.Macaroon, []byte, error) { var authHeader string switch { @@ -165,7 +166,7 @@ func authFromHeader(header *http.Header) (*macaroon.Macaroon, []byte, error) { mac := &macaroon.Macaroon{} err = mac.UnmarshalBinary(macBytes) if err != nil { - return nil, nil, fmt.Errorf("unable to unmarshal " + + return nil, nil, fmt.Errorf("unable to unmarshal "+ "macaroon: %v", err) } preimageBytes, err := hex.DecodeString(preimageHex) @@ -216,3 +217,20 @@ func authFromHeader(header *http.Header) (*macaroon.Macaroon, []byte, error) { return mac, preimageBytes, nil } + +// SetHeader sets the provided authentication elements as the default/standard +// HTTP header for the LSAT protocol. +func SetHeader(header *http.Header, mac *macaroon.Macaroon, + preimage []byte) error { + + macBytes, err := mac.MarshalBinary() + if err != nil { + return err + } + value := fmt.Sprintf( + authFormat, base64.StdEncoding.EncodeToString(macBytes), + hex.EncodeToString(preimage), + ) + header.Set(HeaderAuthorization, value) + return nil +} diff --git a/proxy/proxy.go b/proxy/proxy.go index f2749d0..c1c30be 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -19,7 +19,7 @@ const ( // formatPattern is the pattern in which the request log will be // printed. This is loosely oriented on the apache log format. // An example entry would look like this: - // 2019-11-09 04:07:55.072 [INF] PRXY: 66.249.69.89 - - + // 2019-11-09 04:07:55.072 [INF] PRXY: 66.249.69.89 - - // "GET /availability/v1/btc.json HTTP/1.1" "" "Mozilla/5.0 ..." formatPattern = "- - \"%s %s %s\" \"%s\" \"%s\"" hdrContentType = "Content-Type" @@ -181,9 +181,18 @@ func (p *Proxy) director(req *http.Request) { req.URL.Host = target.Address req.URL.Scheme = target.Protocol - // Don't forward the authorization header since the - // services won't know what it is. - req.Header.Del("Authorization") + // Make sure we always forward the authorization in the correct/ + // default format so the backend knows what to do with it. + mac, preimage, err := auth.FromHeader(&req.Header) + if err == nil { + // It could be that there is no auth information because + // none is needed for this particular request. So we + // only continue if no error is set. + err := auth.SetHeader(&req.Header, mac, preimage) + if err != nil { + log.Errorf("could not set header: %v", err) + } + } // Now overwrite header fields of the client request // with the fields from the configuration file.