diff --git a/src/glide.lock b/src/glide.lock index 121979c..aa53b6d 100644 --- a/src/glide.lock +++ b/src/glide.lock @@ -1,8 +1,8 @@ -hash: 3e052176a2e00802c359524ef4756a1343050da4ba41c7771265095502adffa3 -updated: 2019-04-02T14:37:57.259693-07:00 +hash: 5b247947da0b452333719cbb9b4bd9b2312194aa7e7ecc1eb7a9826115892f37 +updated: 2019-05-09T15:54:04.202218-07:00 imports: - name: github.com/armon/go-metrics - version: 783273d703149aaeb9897cf58613d5af48861c25 + version: f0300d1749da6fa982027e449ec0c7a145510c3c - name: github.com/aws/aws-sdk-go version: 7be45195c3af1b54a609812f90c05a7e492e2491 subpackages: @@ -41,9 +41,16 @@ imports: version: 19cb9f127a9c8d2034cf59ccb683cdb94b9deb6c subpackages: - linux +- name: github.com/Comcast/comcast-bascule + version: d07d9e49941c9a0998295574bf6b885148666742 + subpackages: + - bascule + - bascule/basculehttp + - bascule/key - name: github.com/Comcast/webpa-common - version: 723a128f40c78e45ca079dd113ebb2cf798b7aef + version: f5fa67d65cf557eb746e2799100fe8356c7b5753 subpackages: + - basculechecks - capacitor - clock - concurrent @@ -88,7 +95,7 @@ imports: subpackages: - spew - name: github.com/fsnotify/fsnotify - version: c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9 + version: ccc981bf80385c528a65fbfdd49bf2d8da22aa23 - name: github.com/go-ini/ini version: bda519ae5f4cbc60d391ff8610711627a08b86ae - name: github.com/go-kit/kit @@ -118,9 +125,11 @@ imports: - name: github.com/go-logfmt/logfmt version: 390ab7935ee28ec6b286364bba9b4dd6410cb3d5 - name: github.com/golang/protobuf - version: 925541529c1fa6821df4e44ce2723319eb2be768 + version: b4deda0973fb4c70b50d226b1af49f3da59f5265 subpackages: - proto +- name: github.com/goph/emperror + version: ae59d9fdc3f0c4814bc5fac2d4a68441dcff5a17 - name: github.com/gorilla/context version: 08b5f424b9271eedf6f9f0ce86cb9396ed337a42 - name: github.com/gorilla/mux @@ -134,15 +143,15 @@ imports: - name: github.com/hashicorp/go-cleanhttp version: e8ab9daed8d1ddd2d3c4efba338fe2eeae2e4f18 - name: github.com/hashicorp/go-immutable-radix - version: 7f3cd4390caab3250a57f30efdb2a65dd7649ecf + version: 27df80928bb34bb1b0d6d0e01b9e679902e7a6b5 - name: github.com/hashicorp/go-rootcerts version: 6bb64b370b90e7ef1fa532be9e591a81c3493e00 - name: github.com/hashicorp/golang-lru - version: 0fb14efe8c47ae851c0034ed7a448854d3d34cf3 + version: 20f1fb78b0740ba8c3cb143a61e86ba5c8669768 subpackages: - simplelru - name: github.com/hashicorp/hcl - version: ef8a98b0bbce4a65b5aa4c368430a80ddc533168 + version: 65a6292f0157eff210d03ed1bf6c59b190b8b906 subpackages: - hcl/ast - hcl/parser @@ -154,11 +163,11 @@ imports: - json/scanner - json/token - name: github.com/hashicorp/serf - version: 80ab48778deee28e4ea2dc4ef1ebb2c5f4063996 + version: 48d57945817366b5484d99353f1f33e990bd142d subpackages: - coordinate - name: github.com/influxdata/influxdb - version: de58584ce723da61d6cce6c4b92131143c06eea4 + version: 8d679cf0c36edf5aaede7a0ea068cf9d0c9be409 subpackages: - client/v2 - models @@ -172,7 +181,7 @@ imports: - name: github.com/kr/logfmt version: b84e30acd515aadc4b783ad4ff83aff3299bdfe0 - name: github.com/magiconair/properties - version: 2c9e9502788518c97fe44e8955cd069417ee89df + version: c2353362d570a7bfa228149c62842019201cfb71 - name: github.com/matttproud/golang_protobuf_extensions version: c12348ce28de40eed0136aa2b644d0ee0650e56c subpackages: @@ -180,13 +189,15 @@ imports: - name: github.com/miekg/dns version: ba6747e8a94115e9dc7738afb87850687611df1b - name: github.com/mitchellh/go-homedir - version: b8bc1bf767474819792c23f32d8286a45736f1c6 + version: ae18d6b8b3205b561c79e8e5f69bff09736185f4 - name: github.com/mitchellh/mapstructure - version: 00c29f56e2386353d58c599509e8dc3801b0d716 + version: fa473d140ef3c6adf42d6b391fe76707f1f243c8 - name: github.com/pelletier/go-toml - version: 66540cf1fcd2c3aee6f6787dfa32a6ae9a870f12 + version: 78b76feda6f35b2c5c1d283513f6419e59086729 +- name: github.com/pkg/errors + version: 2233dee583dcf88f3c8b22cb7a33f05a499800d8 - name: github.com/pmezard/go-difflib - version: d8ed2627bdf02c080bf22230dbb337003b7aba2d + version: 792786c7400a136282c1664665ae0a8db921c6c2 subpackages: - difflib - name: github.com/prometheus/client_golang @@ -196,11 +207,11 @@ imports: - prometheus/internal - prometheus/promhttp - name: github.com/prometheus/client_model - version: 99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c + version: 5c3871d89910bfb32f5fcab2aa4b9ec68e65a99f subpackages: - go - name: github.com/prometheus/common - version: d811d2e9bf898806ecfb6ef6296774b13ffc314c + version: c7de2306084e37d54b8be01f3541a8464345e9a5 subpackages: - expfmt - internal/bitbucket.org/ww/goautoneg @@ -224,26 +235,24 @@ imports: - name: github.com/spaolacci/murmur3 version: 0d12bf811670bf6a1a63828dfbd003eded177fce - name: github.com/spf13/afero - version: 63644898a8da0bc22138abf860edaf5277b6102e + version: d40851caa0d747393da1ffb28f7f9d8b4eeffebd subpackages: - mem - name: github.com/spf13/cast version: 8965335b8c7107321228e3e3702cab9832751bac - name: github.com/spf13/jwalterweatherman - version: 7c0cea34c8ece3fbeb2b27ab9b59511d360fb394 + version: 4a4406e478ca629068e7768fc33f3f044173c0a6 - name: github.com/spf13/pflag version: e57e3eeb33f795204c1ca35f56c44f83227c6e66 - name: github.com/spf13/viper version: 6d33b5a963d922d182c91e8a1c88d81fd150cfd4 - name: github.com/stretchr/objx - version: cbeaeb16a013161a98496fad62933b1d21786672 + version: ef50b0de28773081167c97fc27cf29a0bf8b8c71 - name: github.com/stretchr/testify version: 12b6f73e6084dad08a7c6e575284b177ecafbc71 subpackages: - assert - - linux - mock - - require - name: github.com/ugorji/go version: e5e69e061d4f7ee3a69b793cf9c1b41afe21918e subpackages: @@ -264,11 +273,11 @@ imports: - ipv4 - ipv6 - name: golang.org/x/sys - version: 7dfd1290c7917b7ba22824b9d24954ab3002fe24 + version: 90868a75fefd03942536221d7c0e2f84ec62a668 subpackages: - unix - name: golang.org/x/text - version: 7922cc490dd5a7dbaa7fd5d6196b49db59ac042f + version: 905a57155faa8230500121607930ebb9dd8e139c subpackages: - transform - unicode/norm diff --git a/src/glide.yaml b/src/glide.yaml index ffdc472..e812c63 100644 --- a/src/glide.yaml +++ b/src/glide.yaml @@ -1,4 +1,6 @@ package: . import: - package: github.com/Comcast/webpa-common - version: 723a128f40c78e45ca079dd113ebb2cf798b7aef + version: v1.0.1 +- package: github.com/Comcast/comcast-bascule + version: v0.2.5 diff --git a/src/scytale/primaryHandler.go b/src/scytale/primaryHandler.go index b5b7423..8e17873 100644 --- a/src/scytale/primaryHandler.go +++ b/src/scytale/primaryHandler.go @@ -19,15 +19,16 @@ package main import ( "bytes" "context" + "encoding/base64" "errors" "fmt" "net/http" + "github.com/Comcast/comcast-bascule/bascule" + "github.com/Comcast/comcast-bascule/bascule/basculehttp" + "github.com/Comcast/webpa-common/basculechecks" "github.com/Comcast/webpa-common/logging" "github.com/Comcast/webpa-common/logging/logginghttp" - "github.com/Comcast/webpa-common/secure" - "github.com/Comcast/webpa-common/secure/handler" - "github.com/Comcast/webpa-common/secure/key" "github.com/Comcast/webpa-common/service" "github.com/Comcast/webpa-common/service/monitor" "github.com/Comcast/webpa-common/wrp" @@ -39,6 +40,7 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" gokithttp "github.com/go-kit/kit/transport/http" + "github.com/goph/emperror" "github.com/gorilla/mux" "github.com/justinas/alice" "github.com/spf13/viper" @@ -49,73 +51,106 @@ const ( version = "v2" ) +func SetLogger(logger log.Logger) func(delegate http.Handler) http.Handler { + return func(delegate http.Handler) http.Handler { + return http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + ctx := r.WithContext(logging.WithLogger(r.Context(), + log.With(logger, "requestHeaders", r.Header, "requestURL", r.URL.EscapedPath(), "method", r.Method))) + delegate.ServeHTTP(w, ctx) + }) + } +} + +func GetLogger(ctx context.Context) bascule.Logger { + logger := log.With(logging.GetLogger(ctx), "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller) + return logger +} + func populateMessage(ctx context.Context, message *wrp.Message) { - if values, ok := handler.FromContext(ctx); ok { - message.PartnerIDs = values.PartnerIDs + if auth, ok := bascule.FromContext(ctx); ok { + if token := auth.Token; token != nil { + if ids, ok := token.Attributes().Get("partnerIDs"); ok { + if idStr, ok := ids.([]string); ok { + message.PartnerIDs = idStr + } + } + } } } func authChain(v *viper.Viper, logger log.Logger, registry xmetrics.Registry) (alice.Chain, error) { var ( - m = secure.NewJWTValidationMeasures(registry) - validator, err = validators(v, m) + m *basculechecks.JWTValidationMeasures ) - if err != nil { - return alice.Chain{}, err - } - - authHandler := handler.AuthorizationHandler{ - HeaderName: "Authorization", - ForbiddenStatusCode: 403, - Validator: validator, - Logger: logger, + if registry != nil { + m = basculechecks.NewJWTValidationMeasures(registry) } + listener := basculechecks.NewMetricListener(m) - authHandler.DefineMeasures(m) - return alice.New(authHandler.Decorate), nil -} - -func validators(v *viper.Viper, m *secure.JWTValidationMeasures) (validator secure.Validator, err error) { - var jwtVals []JWTValidator - - v.UnmarshalKey("jwtValidators", &jwtVals) + basicAllowed := make(map[string]string) + basicAuth := v.GetStringSlice("authHeader") + for _, a := range basicAuth { + decoded, err := base64.StdEncoding.DecodeString(a) + if err != nil { + logging.Info(logger).Log(logging.MessageKey(), "failed to decode auth header", "authHeader", a, logging.ErrorKey(), err.Error()) + } - // if a JWTKeys section was supplied, configure a JWS validator - // and append it to the chain of validators - validators := make(secure.Validators, 0, len(jwtVals)) + i := bytes.IndexByte(decoded, ':') + logging.Debug(logger).Log(logging.MessageKey(), "decoded string", "string", decoded, "i", i) + if i > 0 { + basicAllowed[string(decoded[:i])] = string(decoded[i+1:]) + } + } + logging.Debug(logger).Log(logging.MessageKey(), "Created list of allowed basic auths", "allowed", basicAllowed, "config", basicAuth) - for _, validatorDescriptor := range jwtVals { - validatorDescriptor.Custom.DefineMeasures(m) + options := []basculehttp.COption{basculehttp.WithCLogger(GetLogger), basculehttp.WithCErrorResponseFunc(listener.OnErrorResponse)} + if len(basicAllowed) > 0 { + options = append(options, basculehttp.WithTokenFactory("Basic", basculehttp.BasicTokenFactory(basicAllowed))) + } + var jwtVal JWTValidator - var keyResolver key.Resolver - keyResolver, err = validatorDescriptor.Keys.NewResolver() + v.UnmarshalKey("jwtValidator", &jwtVal) + if jwtVal.Keys.URI != "" { + resolver, err := jwtVal.Keys.NewResolver() if err != nil { - validator = validators - return + return alice.Chain{}, emperror.With(err, "failed to create resolver") } - validator := secure.JWSValidator{ + options = append(options, basculehttp.WithTokenFactory("Bearer", basculehttp.BearerTokenFactory{ DefaultKeyId: DefaultKeyID, - Resolver: keyResolver, - JWTValidators: []*jwt.Validator{validatorDescriptor.Custom.New()}, - } + Resolver: resolver, + Parser: bascule.DefaultJWSParser, + JWTValidators: []*jwt.Validator{jwtVal.Custom.New()}, + })) + } + + authConstructor := basculehttp.NewConstructor(options...) - validator.DefineMeasures(m) - validators = append(validators, validator) + bearerRules := []bascule.Validator{ + bascule.CreateNonEmptyPrincipalCheck(), + bascule.CreateNonEmptyTypeCheck(), + bascule.CreateValidTypeCheck([]string{"jwt"}), } - basicAuth := v.GetStringSlice("authHeader") - for _, authValue := range basicAuth { - validators = append( - validators, - secure.ExactMatchValidator(authValue), - ) + // only add capability check if the configuration is set + var capabilityConfig basculechecks.CapabilityConfig + v.UnmarshalKey("capabilityConfig", &capabilityConfig) + if capabilityConfig.FirstPiece != "" && capabilityConfig.SecondPiece != "" && capabilityConfig.ThirdPiece != "" { + bearerRules = append(bearerRules, bascule.CreateListAttributeCheck("capabilities", basculechecks.CreateValidCapabilityCheck(capabilityConfig))) } - validator = validators + authEnforcer := basculehttp.NewEnforcer( + basculehttp.WithELogger(GetLogger), + basculehttp.WithRules("Basic", []bascule.Validator{ + bascule.CreateAllowAllCheck(), + }), + basculehttp.WithRules("Bearer", bearerRules), + basculehttp.WithEErrorResponseFunc(listener.OnErrorResponse), + ) - return + return alice.New(SetLogger(logger), authConstructor, authEnforcer, basculehttp.NewListenerDecorator(listener)), nil } // createEndpoints examines the configuration and produces an appropriate fanout.Endpoints, either using the configured @@ -150,6 +185,7 @@ func NewPrimaryHandler(logger log.Logger, v *viper.Viper, registry xmetrics.Regi if err := v.UnmarshalKey("fanout", &cfg); err != nil { return nil, err } + logging.Error(logger).Log(logging.MessageKey(), "creating primary handler") endpoints, err := createEndpoints(logger, cfg, registry, e) if err != nil { diff --git a/src/scytale/scytale.go b/src/scytale/scytale.go index ba9673e..d9c2fbc 100644 --- a/src/scytale/scytale.go +++ b/src/scytale/scytale.go @@ -22,9 +22,9 @@ import ( "os" "os/signal" + "github.com/Comcast/webpa-common/basculechecks" "github.com/Comcast/webpa-common/concurrent" "github.com/Comcast/webpa-common/logging" - "github.com/Comcast/webpa-common/secure" "github.com/Comcast/webpa-common/server" "github.com/Comcast/webpa-common/service" "github.com/Comcast/webpa-common/service/servicecfg" @@ -54,7 +54,7 @@ func scytale(arguments []string) int { f = pflag.NewFlagSet(applicationName, pflag.ContinueOnError) v = viper.New() - logger, metricsRegistry, webPA, err = server.Initialize(applicationName, arguments, f, v, webhook.Metrics, aws.Metrics, secure.Metrics) + logger, metricsRegistry, webPA, err = server.Initialize(applicationName, arguments, f, v, webhook.Metrics, aws.Metrics, basculechecks.Metrics) ) if err != nil { diff --git a/src/scytale/scytale_type.go b/src/scytale/scytale_type.go index b2f4917..43f842a 100644 --- a/src/scytale/scytale_type.go +++ b/src/scytale/scytale_type.go @@ -17,8 +17,8 @@ package main import ( + "github.com/Comcast/comcast-bascule/bascule/key" "github.com/Comcast/webpa-common/secure" - "github.com/Comcast/webpa-common/secure/key" ) //JWTValidator provides a convenient way to define jwt validator through config files