From c2e9d540baf6f0ce725c459706eae33f32377b85 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Fri, 29 Nov 2019 17:13:33 +0100 Subject: [PATCH] proxy: add auth whitelist for paths --- proxy/proxy.go | 7 ++++--- proxy/service.go | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/proxy/proxy.go b/proxy/proxy.go index 2a7f057..b1921d7 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -91,14 +91,15 @@ func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Determine auth level required to access service and dispatch request // accordingly. + authLevel := target.AuthRequired(r) switch { - case target.Auth.IsOn(): + case authLevel.IsOn(): if !p.authenticator.Accept(&r.Header, target.Name) { prefixLog.Infof("Authentication failed. Sending 402.") p.handlePaymentRequired(w, r, target.Name) return } - case target.Auth.IsFreebie(): + case authLevel.IsFreebie(): // We only need to respect the freebie counter if the user // is not authenticated at all. if !p.authenticator.Accept(&r.Header, target.Name) { @@ -127,7 +128,7 @@ func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } } - case target.Auth.IsOff(): + case authLevel.IsOff(): } // If we got here, it means everything is OK to pass the request to the diff --git a/proxy/service.go b/proxy/service.go index ec38b26..0c54266 100644 --- a/proxy/service.go +++ b/proxy/service.go @@ -5,6 +5,8 @@ import ( "encoding/hex" "fmt" "io/ioutil" + "net/http" + "regexp" "strings" "github.com/lightninglabs/kirin/auth" @@ -67,9 +69,33 @@ type Service struct { // correspond to the caveat's condition. Constraints map[string]string `long:"constraints" description:"The service constraints to enforce at the base tier"` + // AuthWhitelistPaths is an optional list of regular expressions that + // are matched against the path of the URL of a request. If the request + // URL matches any of those regular expressions, the call is treated as + // if Auth was set to "off". This allows certain RPC methods to not + // require an LSAT token. E.g. the path for a gRPC call looks like this: + // /package_name.ServiceName/MethodName + AuthWhitelistPaths []string `long:"authwhitelistpaths" description:"List of regular expressions for paths that don't require authentication'"` + freebieDb freebie.DB } +// AuthRequired determines the auth level required for a given request. +func (s *Service) AuthRequired(r *http.Request) auth.Level { + // Does the request match any whitelist entry? + for _, pathRegexp := range s.AuthWhitelistPaths { + pathRegexp := regexp.MustCompile(pathRegexp) + if pathRegexp.MatchString(r.URL.Path) { + log.Tracef("Req path [%s] matches whitelist entry "+ + "[%s].", r.URL.Path, pathRegexp) + return auth.LevelOff + } + } + + // By default we always return the service level auth setting. + return s.Auth +} + // prepareServices prepares the backend service configurations to be used by the // proxy. func prepareServices(services []*Service) error { @@ -117,6 +143,15 @@ func prepareServices(services []*Service) error { "format %s", value) } } + + // Make sure all whitelist regular expression entries actually + // compile so we run into an eventual panic during startup and + // not only when the request happens. + for _, entry := range service.AuthWhitelistPaths { + _, err := regexp.Compile(entry) + return fmt.Errorf("error validating auth whitelist: %v", + err) + } } return nil }