From f0b7ff29d061729e273ba8457b96255594888e0d Mon Sep 17 00:00:00 2001 From: Rob Galanakis Date: Wed, 31 Jul 2024 10:29:22 -0700 Subject: [PATCH] Remove JWT packages These depended on an outdated library, and were meant mostly as aids to that library. Since the libraries are newer, they have different and ideally better ways of doing things, so don't bother trying to do a direct upgrade. --- api/auth0jwt/auth0jwt.go | 139 ------------------------ api/auth0jwt/auth0jwt_test.go | 30 ------ go.mod | 33 +++--- go.sum | 85 +++++++++------ jwtee/jwtee.go | 149 ------------------------- jwtee/jwtee_test.go | 197 ---------------------------------- 6 files changed, 73 insertions(+), 560 deletions(-) delete mode 100644 api/auth0jwt/auth0jwt.go delete mode 100644 api/auth0jwt/auth0jwt_test.go delete mode 100644 jwtee/jwtee.go delete mode 100644 jwtee/jwtee_test.go diff --git a/api/auth0jwt/auth0jwt.go b/api/auth0jwt/auth0jwt.go deleted file mode 100644 index 941abf5..0000000 --- a/api/auth0jwt/auth0jwt.go +++ /dev/null @@ -1,139 +0,0 @@ -// Package auth0jwt is a modification of the Auth0 provided Go tutorial: -// https://auth0.com/docs/quickstart/backend/golang -// As you may guess that has several issues, but a lot of what's here has been taken verbatim. -package auth0jwt - -import ( - "crypto/subtle" - "encoding/json" - "errors" - "github.com/auth0/go-jwt-middleware" - "github.com/dgrijalva/jwt-go" - "github.com/labstack/echo/v4" - "net/http" -) - -type Jwks struct { - Keys []JSONWebKeys `json:"keys"` -} - -type JSONWebKeys struct { - Kty string `json:"kty"` - Kid string `json:"kid"` - Use string `json:"use"` - N string `json:"n"` - E string `json:"e"` - X5c []string `json:"x5c"` -} - -type Config struct { - // Aud is used to veirfy the 'aud' claim. It's the identifier of the API in Auth0. - Aud string - // Iss is used to verify the 'iss' claim. - Iss string - // JwksPath is the path to the file like "https://my-application.auth0.com/.well-known/jwks.json". - // See https://auth0.com/docs/tokens/concepts/jwks - JwksPath string -} - -func NewMiddleware(cfg Config) echo.MiddlewareFunc { - mw := jwtmiddleware.New(jwtmiddleware.Options{ - ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) { - checkAud := verifyArrayAudience(token.Claims.(jwt.MapClaims), cfg.Aud, true) - if !checkAud { - return token, echo.NewHTTPError(401, "invalid audience") - } - checkIss := token.Claims.(jwt.MapClaims).VerifyIssuer(cfg.Iss, true) - if !checkIss { - return token, echo.NewHTTPError(401, "invalid issuer") - } - - cert, err := getPemCert(cfg.JwksPath, token) - if err != nil { - return nil, err - } - - result, _ := jwt.ParseRSAPublicKeyFromPEM([]byte(cert)) - return result, nil - }, - UserProperty: "user", - CredentialsOptional: false, - Debug: false, - }) - - return func(next echo.HandlerFunc) echo.HandlerFunc { - return func(c echo.Context) error { - req := c.Request() - // req gets stomped by CheckJWT, to have a new context - err := mw.CheckJWT(c.Response().Writer, req) - if err != nil { - return err - } - user := req.Context().Value(mw.Options.UserProperty) - if user == nil { - panic("why is 'user' nil in jwt context!?") - } - c.Set(mw.Options.UserProperty, user) - return next(c) - } - } -} - -func getPemCert(jwksPath string, token *jwt.Token) (string, error) { - cert := "" - resp, err := http.Get(jwksPath) - - if err != nil { - return cert, err - } - defer resp.Body.Close() - - var jwks = Jwks{} - err = json.NewDecoder(resp.Body).Decode(&jwks) - - if err != nil { - return cert, err - } - - for k := range jwks.Keys { - if token.Header["kid"] == jwks.Keys[k].Kid { - cert = "-----BEGIN CERTIFICATE-----\n" + jwks.Keys[k].X5c[0] + "\n-----END CERTIFICATE-----" - } - } - - if cert == "" { - err := errors.New("unable to find appropriate key") - return cert, err - } - - return cert, nil -} - -// Seehttps://github.com/dgrijalva/jwt-go/pull/308 -// These two methods are straight copy paste -func verifyArrayAudience(m jwt.MapClaims, cmp string, req bool) bool { - switch m["aud"].(type) { - case string: - aud := m["aud"].(string) - return verifyAudHelper(aud, cmp, req) - default: - auds := m["aud"].([]interface{}) - for _, aud := range auds { - if verifyAudHelper(aud.(string), cmp, req) { - return true - } - } - return false - } -} - -func verifyAudHelper(aud string, cmp string, required bool) bool { - if aud == "" { - return !required - } - if subtle.ConstantTimeCompare([]byte(aud), []byte(cmp)) != 0 { - return true - } else { - return false - } -} diff --git a/api/auth0jwt/auth0jwt_test.go b/api/auth0jwt/auth0jwt_test.go deleted file mode 100644 index d5eca98..0000000 --- a/api/auth0jwt/auth0jwt_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package auth0jwt_test - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - "testing" -) - -func TestAuth0Jwt(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "API Suite") -} - -var _ = Describe("auth0jwt", func() { - //var e *echo.Echo - - BeforeEach(func() { - //e = echo.New() - }) - - It("validates against iss", func() { - }) - It("validates against aud string", func() { - }) - It("validates against aud array", func() { - }) - It("adds the user to the echo context", func() { - }) - It("validates against the PEM cert", func() {}) -}) diff --git a/go.mod b/go.mod index e0d7eae..1bb5eb7 100644 --- a/go.mod +++ b/go.mod @@ -3,24 +3,25 @@ module github.com/lithictech/go-aperitif go 1.22 require ( - github.com/auth0/go-jwt-middleware v0.0.0-20200507191422-d30d7b9ece63 - github.com/dgrijalva/jwt-go v3.2.0+incompatible - github.com/google/uuid v1.1.1 - github.com/hashicorp/go-multierror v1.1.0 - github.com/jmoiron/sqlx v1.2.0 + github.com/google/uuid v1.6.0 + github.com/hashicorp/go-multierror v1.1.1 + github.com/jmoiron/sqlx v1.4.0 github.com/labstack/echo/v4 v4.12.0 - github.com/onsi/ginkgo/v2 v2.3.1 - github.com/onsi/gomega v1.22.0 + github.com/onsi/ginkgo/v2 v2.19.1 + github.com/onsi/gomega v1.34.1 github.com/pkg/errors v0.9.1 - github.com/rgalanakis/golangal v1.1.0 + github.com/rgalanakis/golangal v1.2.0 github.com/rgalanakis/validator v0.0.0-20180731224108-4a34a8927f7c - github.com/sirupsen/logrus v1.6.0 - golang.org/x/crypto v0.22.0 + github.com/sirupsen/logrus v1.9.3 + golang.org/x/crypto v0.25.0 ) require ( + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect - github.com/google/go-cmp v0.5.8 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect github.com/labstack/gommon v0.4.2 // indirect @@ -28,11 +29,13 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect - golang.org/x/net v0.24.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/term v0.19.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect + golang.org/x/net v0.27.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/term v0.22.0 // indirect + golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.23.0 // indirect google.golang.org/appengine v1.6.6 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index b998998..55cffea 100644 --- a/go.sum +++ b/go.sum @@ -1,35 +1,41 @@ -github.com/auth0/go-jwt-middleware v0.0.0-20200507191422-d30d7b9ece63 h1:LY/kRH+fCqA090FsM2VfZ+oocD99ogm3HrT1r0WDnCk= -github.com/auth0/go-jwt-middleware v0.0.0-20200507191422-d30d7b9ece63/go.mod h1:mF0ip7kTEFtnhBJbd/gJe62US3jykNN+dcZoZakJCCA= -github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0= -github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= -github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= +github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0= @@ -38,6 +44,7 @@ github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0 github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -45,62 +52,80 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/onsi/ginkgo/v2 v2.3.1 h1:8SbseP7qM32WcvE6VaN6vfXxv698izmsJ1UQX9ve7T8= github.com/onsi/ginkgo/v2 v2.3.1/go.mod h1:Sv4yQXwG5VmF7tm3Q5Z+RWUpPo24LF1mpnz2crUb8Ys= +github.com/onsi/ginkgo/v2 v2.19.1 h1:QXgq3Z8Crl5EL1WBAC98A5sEBHARrAJNzAmMxzLcRF0= +github.com/onsi/ginkgo/v2 v2.19.1/go.mod h1:O3DtEWQkPa/F7fBMgmZQKKsluAy8pd3rEQdrjkPb9zA= github.com/onsi/gomega v1.22.0 h1:AIg2/OntwkBiCg5Tt1ayyiF1ArFrWFoCSMtMi/wdApk= github.com/onsi/gomega v1.22.0/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc= +github.com/onsi/gomega v1.34.0 h1:eSSPsPNp6ZpsG8X1OVmOTxig+CblTc4AxpPBykhe2Os= +github.com/onsi/gomega v1.34.0/go.mod h1:MIKI8c+f+QLWk+hxbePD4i0LMJSExPaZOVfkoex4cAo= +github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= +github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rgalanakis/golangal v1.1.0 h1:JMR5gBHMmcWQ86hYM8mRXp99AC1AeEdWKc4sNfjjA3A= github.com/rgalanakis/golangal v1.1.0/go.mod h1:DT35MZom81QtvdrIerWZ0T3moT/npNBiJmW9cXcufMM= +github.com/rgalanakis/golangal v1.2.0 h1:dDrD6sJR2JbnNl0aDNvBHjzWN6r9lDTfv3XqKTNTMmg= +github.com/rgalanakis/golangal v1.2.0/go.mod h1:DT35MZom81QtvdrIerWZ0T3moT/npNBiJmW9cXcufMM= github.com/rgalanakis/validator v0.0.0-20180731224108-4a34a8927f7c h1:z1J+SUwpje5zEyPfHBIv6N++OxjETBV5wGBwkmO/Wzk= github.com/rgalanakis/validator v0.0.0-20180731224108-4a34a8927f7c/go.mod h1:qIw2dAd/4wMHHnINySB5+y9HPKQXUKmga0oZHSluPKE= github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/assertions v1.1.0 h1:MkTeG1DMwsrdH7QtLXy5W+fUxWq+vmb6cLmyJ7aRtF0= -github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc= -github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= -golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= +golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= +golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/jwtee/jwtee.go b/jwtee/jwtee.go deleted file mode 100644 index 025454d..0000000 --- a/jwtee/jwtee.go +++ /dev/null @@ -1,149 +0,0 @@ -// Package jwtee wraps github.com/dgrijalva/jwt-go -// with some tooling that makes it easier to use -// in most practical usage. -package jwtee - -import ( - "crypto/subtle" - "errors" - "github.com/dgrijalva/jwt-go" - "time" -) - -type Error struct { - msg string -} - -func (e Error) Error() string { - return e.msg -} - -type Jwtee struct { - Secret []byte - Aud string - Iss string - Alg jwt.SigningMethod -} - -type Input struct { - Secret string - Aud string - Iss string - Alg string -} - -func New(input Input) (Jwtee, error) { - j := Jwtee{ - Secret: []byte(input.Secret), - Aud: input.Aud, - Iss: input.Iss, - Alg: jwt.GetSigningMethod(input.Alg), - } - if len(j.Secret) == 0 { - return j, errors.New("secret is required") - } - if j.Aud == "" { - return j, errors.New("aud is required") - } - if j.Iss == "" { - return j, errors.New("iss is required") - } - if j.Alg == nil { - return j, errors.New("valid alg is required") - } - return j, nil -} - -func (j Jwtee) Parse(tokenString string) (*jwt.Token, error) { - return jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { - if token.Method != j.Alg { - return token, Error{msg: "invalid alg"} - } - checkAud := verifyArrayAudience(token.Claims.(jwt.MapClaims), j.Aud, true) - if !checkAud { - return token, Error{msg: "invalid aud"} - } - checkIss := token.Claims.(jwt.MapClaims).VerifyIssuer(j.Iss, true) - if !checkIss { - return token, Error{msg: "invalid iss"} - } - return j.Secret, nil - }) -} - -func (j Jwtee) ParseMapClaims(tokenString string) (jwt.MapClaims, error) { - tok, err := j.Parse(tokenString) - if tok == nil { - panic("token should never be nil") - } - return tok.Claims.(jwt.MapClaims), err -} - -func (j Jwtee) BuildTtl(ttl time.Duration, moreClaims map[string]interface{}) (string, error) { - tok := jwt.New(j.Alg) - mc := tok.Claims.(jwt.MapClaims) - mc["iss"] = j.Iss - mc["aud"] = j.Aud - mc["exp"] = jwt.TimeFunc().Add(ttl).Unix() - for k, v := range moreClaims { - mc[k] = v - } - return tok.SignedString(j.Secret) -} - -func (j Jwtee) Dup(input Input) Jwtee { - if len(input.Secret) > 0 { - j.Secret = []byte(input.Secret) - } - if input.Aud != "" { - j.Aud = input.Aud - } - if input.Iss != "" { - j.Iss = input.Iss - } - if input.Alg != "" { - j.Alg = jwt.GetSigningMethod(input.Alg) - } - return j -} - -// See https://github.com/dgrijalva/jwt-go/pull/308 -// These two methods are straight copy paste -func verifyArrayAudience(m jwt.MapClaims, cmp string, req bool) bool { - switch m["aud"].(type) { - case string: - aud := m["aud"].(string) - return verifyAudHelper(aud, cmp, req) - default: - auds := m["aud"].([]interface{}) - for _, aud := range auds { - if verifyAudHelper(aud.(string), cmp, req) { - return true - } - } - return false - } -} - -func verifyAudHelper(aud string, cmp string, required bool) bool { - if aud == "" { - return !required - } - if subtle.ConstantTimeCompare([]byte(aud), []byte(cmp)) != 0 { - return true - } else { - return false - } -} - -func StringClaim(claims jwt.MapClaims, key string) (string, bool) { - v, ok := claims[key] - if !ok { - return "", false - } - s, ok := v.(string) - if !ok { - return "", false - } - return s, len(s) > 0 -} diff --git a/jwtee/jwtee_test.go b/jwtee/jwtee_test.go deleted file mode 100644 index 3455b93..0000000 --- a/jwtee/jwtee_test.go +++ /dev/null @@ -1,197 +0,0 @@ -package jwtee_test - -import ( - "github.com/dgrijalva/jwt-go" - "github.com/lithictech/go-aperitif/jwtee" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - . "github.com/rgalanakis/golangal" - "testing" - "time" -) - -func TestJwtee(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "jwtee package Suite") -} - -var _ = Describe("jwtee", func() { - secret := "xyz" - aud := "hi" - iss := "there" - alg := "HS256" - - validInput := func() jwtee.Input { - return jwtee.Input{ - Secret: secret, - Aud: aud, - Iss: iss, - Alg: alg, - } - } - - newJwtee := func() jwtee.Jwtee { - j, err := jwtee.New(validInput()) - Expect(err).ToNot(HaveOccurred()) - return j - } - - It("requires secret, aud, iss, and alg", func() { - var err error - var jw jwtee.Jwtee - jw, err = jwtee.New(validInput()) - Expect(err).ToNot(HaveOccurred()) - Expect(jw).To(And( - MatchField("Aud", aud), - MatchField("Iss", iss), - MatchField("Alg", jwt.SigningMethodHS256), - )) - _, err = jwtee.New(jwtee.Input{ - Secret: "", - Aud: aud, - Iss: iss, - Alg: alg, - }) - Expect(err).To(MatchError(ContainSubstring("secret is required"))) - _, err = jwtee.New(jwtee.Input{ - Secret: secret, - Aud: "", - Iss: iss, - Alg: alg, - }) - Expect(err).To(MatchError(ContainSubstring("aud is required"))) - _, err = jwtee.New(jwtee.Input{ - Secret: secret, - Aud: aud, - Iss: "", - Alg: alg, - }) - Expect(err).To(MatchError(ContainSubstring("iss is required"))) - _, err = jwtee.New(jwtee.Input{ - Secret: secret, - Aud: aud, - Iss: iss, - Alg: "", - }) - Expect(err).To(MatchError(ContainSubstring("alg is required"))) - }) - It("can dup itself with non-empty input values", func() { - jw := newJwtee() - jw2 := jw.Dup(jwtee.Input{Aud: "another"}) - Expect(jw.Aud).To(Equal(aud)) - Expect(jw.Iss).To(Equal(iss)) - Expect(jw2.Aud).To(Equal("another")) - Expect(jw2.Iss).To(Equal(iss)) - }) - Describe("parsing", func() { - It("can verify with a string aud claim", func() { - jw := newJwtee() - s := `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJoaSIsImlzcyI6InRoZXJlIiwiaWF0IjoxNTE2MjM5MDIyfQ.kTgZa43Zq9LrjDAEerD8feT2_TrIhzCPO1UC4bBXzgQ` - cl, err := jw.ParseMapClaims(s) - Expect(err).ToNot(HaveOccurred()) - Expect(cl["aud"]).To(Equal("hi")) - }) - - It("can fail with an invalid aud claim", func() { - jw := newJwtee() - s := `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ5byIsImlzcyI6InRoZXJlIiwiaWF0IjoxNTE2MjM5MDIyfQ.BG7D0kCIcdgTfhOFNxArgubEL_2_WQmxE4vpnOv_AlU` - cl, err := jw.ParseMapClaims(s) - Expect(err).To(MatchError("invalid aud")) - Expect(cl["aud"]).To(Equal("yo")) - }) - It("can verify with an array aud claim", func() { - jw := newJwtee() - s := `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiaGkiLCJoZWxsbyJdLCJpc3MiOiJ0aGVyZSIsImlhdCI6MTUxNjIzOTAyMn0.37-1H6f20flFs2vjJ6u2nzh7BQ51kyQyELEX0y_xE3c` - cl, err := jw.ParseMapClaims(s) - Expect(err).ToNot(HaveOccurred()) - Expect(cl["aud"]).To(BeEquivalentTo([]interface{}{"hi", "hello"})) - }) - It("can fail if aud not in array aud claim", func() { - jw := newJwtee() - s := `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsieW8iXSwiaXNzIjoidGhlcmUiLCJpYXQiOjE1MTYyMzkwMjJ9.u-WkwjTF4kxdGB2wtinAtC1usOnIqeTPnDKg2HQ2gJw` - cl, err := jw.ParseMapClaims(s) - Expect(err).To(MatchError("invalid aud")) - Expect(cl["aud"]).To(BeEquivalentTo([]interface{}{"yo"})) - }) - It("can verify against an issuer", func() { - jw := newJwtee() - s := `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJoaSIsImlzcyI6InRoZXJlIiwiaWF0IjoxNTE2MjM5MDIyfQ.kTgZa43Zq9LrjDAEerD8feT2_TrIhzCPO1UC4bBXzgQ` - cl, err := jw.ParseMapClaims(s) - Expect(err).ToNot(HaveOccurred()) - Expect(cl["iss"]).To(Equal("there")) - }) - It("can fail with an invalid issuer", func() { - jw := newJwtee() - s := `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJoaSIsImlzcyI6InlvbmRlciIsImlhdCI6MTUxNjIzOTAyMn0.Wo0zf5P9H4HAnOWTgdUKNN0W-jTTJot0lEl5kE1r3YY` - cl, err := jw.ParseMapClaims(s) - Expect(err).To(MatchError("invalid iss")) - Expect(cl["iss"]).To(Equal("yonder")) - }) - It("validates against the signing method", func() { - jw := newJwtee() - s := `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJoaSIsImlzcyI6InRoZXJlIiwiaWF0IjoxNTE2MjM5MDIyfQ.kTgZa43Zq9LrjDAEerD8feT2_TrIhzCPO1UC4bBXzgQ` - tok, err := jw.Parse(s) - Expect(err).ToNot(HaveOccurred()) - Expect(tok.Header["alg"]).To(Equal("HS256")) - }) - It("can fail with an unexpected signing method", func() { - jw := newJwtee() - s := `eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJoaSIsImlzcyI6InlvbmRlciIsImlhdCI6MTUxNjIzOTAyMn0.7q_DMegJbTO9uxWPy7n2mfDrBgAO3xBSpVmGjqHG6-ubve8QH2Y1d2noYWMk-wjSwkfbVB1K98FCfVDvZxhfGA` - tok, err := jw.Parse(s) - Expect(err).To(MatchError("invalid alg")) - Expect(tok.Header["alg"]).To(Equal("HS512")) - }) - It("can verify an unexpired exp", func() { - jw := newJwtee() - s := `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJoaSIsImlzcyI6InRoZXJlIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1OTc5ODkyMzM1MTR9.bpLset-GCKbOlish900xGamrRCqQzmX06A2e2BtAdJE` - cl, err := jw.ParseMapClaims(s) - Expect(err).ToNot(HaveOccurred()) - Expect(cl["exp"]).To(BeEquivalentTo(1597989233514)) - }) - It("fails expired exp", func() { - jw := newJwtee() - s := `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJoaSIsImlzcyI6InRoZXJlIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjV9.XsqW1BORkEZBwYXzDVgPJmSV-6wDzkFaZ7NacIfDjNY` - cl, err := jw.ParseMapClaims(s) - Expect(err).To(MatchError("Token is expired")) - Expect(cl["exp"]).To(BeEquivalentTo(5)) - }) - }) - Describe("building", func() { - origTime := jwt.TimeFunc - AfterEach(func() { - jwt.TimeFunc = origTime - }) - It("builds a token with the default fields and additional fields", func() { - jwt.TimeFunc = func() time.Time { - return time.Unix(10000, 0) - } - jw := newJwtee() - js, err := jw.BuildTtl(654*time.Second, map[string]interface{}{"sub": 1234}) - Expect(err).ToNot(HaveOccurred()) - expected := `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJoaSIsImV4cCI6MTA2NTQsImlzcyI6InRoZXJlIiwic3ViIjoxMjM0fQ.OgPwnSrNaEpCgSMcILAdATor2NGlupnt7ggbqr32NL0` - Expect(js).To(Equal(expected)) - }) - }) - Describe("StringClaim", func() { - It("extracts a non-empty string claim", func() { - c := jwt.MapClaims{"s": "", "s2": "a", "i": 1} - var s string - var ok bool - s, ok = jwtee.StringClaim(c, "s2") - Expect(ok).To(BeTrue()) - Expect(s).To(Equal("a")) - - s, ok = jwtee.StringClaim(c, "s") - Expect(ok).To(BeFalse()) - Expect(s).To(BeEmpty()) - - s, ok = jwtee.StringClaim(c, "x") - Expect(ok).To(BeFalse()) - Expect(s).To(BeEmpty()) - - s, ok = jwtee.StringClaim(c, "i") - Expect(ok).To(BeFalse()) - Expect(s).To(BeEmpty()) - }) - }) -})