From 78debf05d9d3519472ef9e1bf2c807e11adee3dc Mon Sep 17 00:00:00 2001 From: Umputun Date: Tue, 15 Jan 2019 13:09:56 -0600 Subject: [PATCH] auth 0.3.3 prevnets expired headers to pe passed in --- backend/Gopkg.lock | 6 +- backend/vendor/github.com/go-pkgz/auth/go.mod | 11 +++- backend/vendor/github.com/go-pkgz/auth/go.sum | 42 ++++++------- .../go-pkgz/auth/middleware/auth.go | 59 ++++++++++++------- .../go-pkgz/auth/provider/direct.go | 2 +- .../go-pkgz/auth/provider/oauth2.go | 4 +- .../go-pkgz/auth/provider/service.go | 2 +- .../github.com/go-pkgz/auth/token/jwt.go | 10 +++- 8 files changed, 81 insertions(+), 55 deletions(-) diff --git a/backend/Gopkg.lock b/backend/Gopkg.lock index d088decf..5ca426a2 100644 --- a/backend/Gopkg.lock +++ b/backend/Gopkg.lock @@ -112,7 +112,7 @@ version = "v1.0.0" [[projects]] - digest = "1:1e397244efaf3322184d8fe59caa62dae159d925aa74a5efafa670964d860d67" + digest = "1:5048ee5f04267e166b81a65f6944575750ebc1fc896124d1cf3e57f5d710e49d" name = "github.com/go-pkgz/auth" packages = [ ".", @@ -122,8 +122,8 @@ "token", ] pruneopts = "UT" - revision = "06e223a293c64ebcaaccda26edfeaf7fba1b8746" - version = "v0.3.2" + revision = "203b40f77cd2d1941d1a8fcdd8474c3bec3cc6b5" + version = "v0.3.3" [[projects]] digest = "1:1933dabfb0e07548ed9684fdef857cc6f2413bbbb74ba838a7c1f77407b8fd90" diff --git a/backend/vendor/github.com/go-pkgz/auth/go.mod b/backend/vendor/github.com/go-pkgz/auth/go.mod index c66749f5..611b11f0 100644 --- a/backend/vendor/github.com/go-pkgz/auth/go.mod +++ b/backend/vendor/github.com/go-pkgz/auth/go.mod @@ -2,16 +2,23 @@ module github.com/go-pkgz/auth require ( cloud.google.com/go v0.34.0 // indirect + github.com/boltdb/bolt v1.3.1 // indirect github.com/coreos/bbolt v1.3.0 github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 - github.com/go-pkgz/lgr v0.1.4 + github.com/go-pkgz/lgr v0.2.2 github.com/go-pkgz/mongo v1.0.0 github.com/go-pkgz/rest v1.2.0 + github.com/hashicorp/golang-lru v0.5.0 + github.com/kr/pretty v0.1.0 // indirect github.com/nullrocks/identicon v0.0.0-20180626043057-7875f45b0022 github.com/pkg/errors v0.8.1 - github.com/stretchr/objx v0.1.1 // indirect + github.com/stretchr/testify v1.3.0 golang.org/x/image v0.0.0-20181116024801-cd38e8056d9b golang.org/x/net v0.0.0-20190107210223-45ffb0cd1ba0 // indirect golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890 + golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect + golang.org/x/sys v0.0.0-20190109145017-48ac38b7c8cb // indirect + google.golang.org/appengine v1.4.0 // indirect + gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect ) diff --git a/backend/vendor/github.com/go-pkgz/auth/go.sum b/backend/vendor/github.com/go-pkgz/auth/go.sum index 2d7bf913..1792f34e 100644 --- a/backend/vendor/github.com/go-pkgz/auth/go.sum +++ b/backend/vendor/github.com/go-pkgz/auth/go.sum @@ -1,5 +1,7 @@ cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= +github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/coreos/bbolt v1.3.0 h1:HIgH5xUWXT914HCI671AxuTTqjj64UOFr7pHn48LUTI= github.com/coreos/bbolt v1.3.0/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -9,28 +11,21 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumC github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/go-pkgz/lgr v0.0.0-20190107224007-7d791fb529cb h1:HBzmL2t7mb8A14Vc1uMInWQlKAY5rq1i1M4svUIQTNQ= -github.com/go-pkgz/lgr v0.0.0-20190107224007-7d791fb529cb/go.mod h1:hBM1NM/SoYdlrykgdgJWGrZ/TM/XaZIjRbJfx7NkMm8= -github.com/go-pkgz/lgr v0.1.0 h1:JzSBxyNW9gli9PMVGI8IUhmFsQZaK2usJ62pmUGj0BY= -github.com/go-pkgz/lgr v0.1.0/go.mod h1:hBM1NM/SoYdlrykgdgJWGrZ/TM/XaZIjRbJfx7NkMm8= -github.com/go-pkgz/lgr v0.1.3 h1:jGPFbzfXWSt3r8qyjXnuKFNM6J10bs3YnD8wPSGdsww= -github.com/go-pkgz/lgr v0.1.3/go.mod h1:hBM1NM/SoYdlrykgdgJWGrZ/TM/XaZIjRbJfx7NkMm8= -github.com/go-pkgz/lgr v0.1.4 h1:mOV129LVgHLq65kYs1Abz0dSk3Sba6PuuJ/S+x2yDaw= -github.com/go-pkgz/lgr v0.1.4/go.mod h1:hBM1NM/SoYdlrykgdgJWGrZ/TM/XaZIjRbJfx7NkMm8= +github.com/go-pkgz/lgr v0.2.2 h1:HSOqMVoetAfvA40Gpy/X/HGyV0UUafIMPgp+SdZends= +github.com/go-pkgz/lgr v0.2.2/go.mod h1:hBM1NM/SoYdlrykgdgJWGrZ/TM/XaZIjRbJfx7NkMm8= github.com/go-pkgz/mongo v1.0.0 h1:9jijAK7prCRMetiyTu3c1rv/2lMypzuf2DWcVpTlwzw= github.com/go-pkgz/mongo v1.0.0/go.mod h1:R9si/F2aJsjz4MUxhzuppIHY8yLV3YCeuCpgcI50cu4= -github.com/go-pkgz/rest v1.1.3 h1:rMf+xJn8i1Ip9OKohusZsRxwntM0BwYu8OX8BuEwN80= -github.com/go-pkgz/rest v1.1.3/go.mod h1:DIxxm3vSt6e+IY+UQUOFsfB2YaHLmGoOfPLWN5pxQSA= -github.com/go-pkgz/rest v1.1.4 h1:/Lrg9kBWBjNah7nmCDHLszRAfVVBIy5ajf0vVgpHPi0= -github.com/go-pkgz/rest v1.1.4/go.mod h1:DIxxm3vSt6e+IY+UQUOFsfB2YaHLmGoOfPLWN5pxQSA= -github.com/go-pkgz/rest v1.1.5 h1:5br4mnscfLb27yxv5hJFLBVmAt09PrmIBP+meA3CfHc= -github.com/go-pkgz/rest v1.1.5/go.mod h1:DIxxm3vSt6e+IY+UQUOFsfB2YaHLmGoOfPLWN5pxQSA= -github.com/go-pkgz/rest v1.1.6 h1:Sqm7uW0X29iEmt4S/vJ82bslQXa6jMMNTaRvHzjTcjo= -github.com/go-pkgz/rest v1.1.6/go.mod h1:fFcrWsYgEp5Xx6HxRFzfV6zTiytCeYv1Jceg8TxorOs= github.com/go-pkgz/rest v1.2.0 h1:75GVv25NmkV2l4dBr/io/ZApJ6zWQu5aZ4wFJA6QQCw= github.com/go-pkgz/rest v1.2.0/go.mod h1:COazNj35u3RXAgQNBr6neR599tYP3URiOpsu9p0rOtk= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/nullrocks/identicon v0.0.0-20180626043057-7875f45b0022 h1:Ys0rDzh8s4UMlGaDa1UTA0sfKgvF0hQZzTYX8ktjiDc= github.com/nullrocks/identicon v0.0.0-20180626043057-7875f45b0022/go.mod h1:x4NsS+uc7ecH/Cbm9xKQ6XzmJM57rWTkjywjfB2yQ18= github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= @@ -40,16 +35,21 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE 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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= golang.org/x/image v0.0.0-20181116024801-cd38e8056d9b h1:VHyIDlv3XkfCa5/a81uzaoDkHH4rr81Z62g+xlnO8uM= golang.org/x/image v0.0.0-20181116024801-cd38e8056d9b/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3 h1:eH6Eip3UpmR+yM/qI9Ijluzb1bNv/cAU/n+6l8tRSis= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190107210223-45ffb0cd1ba0 h1:1DW40AJQ7AP4nY6ORUGUdkpXyEC9W2GAXcOPaMZK0K8= golang.org/x/net v0.0.0-20190107210223-45ffb0cd1ba0/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890 h1:uESlIz09WIHT2I+pasSXcpLYqYK8wHcdCetU3VuMBJE= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190109145017-48ac38b7c8cb h1:1w588/yEchbPNpa9sEvOcMZYbWHedwJjg4VOAdDHWHk= +golang.org/x/sys v0.0.0-20190109145017-48ac38b7c8cb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/backend/vendor/github.com/go-pkgz/auth/middleware/auth.go b/backend/vendor/github.com/go-pkgz/auth/middleware/auth.go index 82990751..593d872d 100644 --- a/backend/vendor/github.com/go-pkgz/auth/middleware/auth.go +++ b/backend/vendor/github.com/go-pkgz/auth/middleware/auth.go @@ -2,10 +2,11 @@ package middleware import ( - "math/rand" "net/http" + "sync" "github.com/go-pkgz/lgr" + lru "github.com/hashicorp/golang-lru" "github.com/pkg/errors" "github.com/go-pkgz/auth/provider" @@ -20,12 +21,19 @@ type Authenticator struct { Validator token.Validator AdminPasswd string RefreshFactor int + + refresh struct { + cache *lru.Cache + once sync.Once + } } +const refreshCacheSize = 1000 + // TokenService defines interface accessing tokens type TokenService interface { Parse(tokenString string) (claims token.Claims, err error) - Set(w http.ResponseWriter, claims token.Claims) error + Set(w http.ResponseWriter, claims token.Claims) (token.Claims, error) Get(r *http.Request) (claims token.Claims, token string, err error) IsExpired(claims token.Claims) bool Reset(w http.ResponseWriter) @@ -83,7 +91,7 @@ func (a *Authenticator) auth(reqAuth bool) func(http.Handler) http.Handler { } if claims.User == nil { - onError(h, w, r, errors.New("failed auth, no user info presented in the claim")) + onError(h, w, r, errors.New("no user info presented in the claim")) return } @@ -95,13 +103,12 @@ func (a *Authenticator) auth(reqAuth bool) func(http.Handler) http.Handler { return } - if a.shouldRefresh(claims) { - if claims, err = a.refreshExpiredToken(w, claims); err != nil { + if a.JWTService.IsExpired(claims) { + if claims, err = a.refreshExpiredToken(w, claims, tkn); err != nil { a.JWTService.Reset(w) onError(h, w, r, errors.Wrap(err, "can't refresh token")) return } - a.Logf("[DEBUG] token refreshed for %+v", claims.User) } r = token.SetUserInfo(r, *claims.User) // populate user info to request context @@ -115,27 +122,35 @@ func (a *Authenticator) auth(reqAuth bool) func(http.Handler) http.Handler { } // refreshExpiredToken makes a new token with passed claims -func (a *Authenticator) refreshExpiredToken(w http.ResponseWriter, claims token.Claims) (token.Claims, error) { - claims.ExpiresAt = 0 // this will cause now+duration for refreshed token - if err := a.JWTService.Set(w, claims); err != nil { +func (a *Authenticator) refreshExpiredToken(w http.ResponseWriter, claims token.Claims, tkn string) (token.Claims, error) { + + a.refresh.once.Do(func() { + var e error + if a.refresh.cache, e = lru.New(refreshCacheSize); e != nil { + a.Logf("[WARN] can't make refresh cache, %v", e) + a.refresh.cache = nil + } + }) + + if a.refresh.cache != nil { + if c, ok := a.refresh.cache.Get(tkn); ok { + // already in cache + return c.(token.Claims), nil + } + } + + claims.ExpiresAt = 0 // this will cause now+duration for refreshed token + c, err := a.JWTService.Set(w, claims) // Set changes token + if err != nil { return token.Claims{}, err } - return claims, nil -} -// shouldRefresh checks if token expired with an optional random rejection of refresh. -// the goal is to prevent multiple refresh request executed at the same time by allowing only some of them -func (a *Authenticator) shouldRefresh(claims token.Claims) bool { - if !a.JWTService.IsExpired(claims) { - return false + if a.refresh.cache != nil { + a.refresh.cache.Add(tkn, c) } - // disable randomizing with 0 factor - if a.RefreshFactor == 0 { - return true - } - - return rand.Int31n(int32(a.RefreshFactor)) == 0 // randomize selection + a.Logf("[DEBUG] token refreshed for %+v", claims.User) + return c, nil } // AdminOnly middleware allows access for admins only diff --git a/backend/vendor/github.com/go-pkgz/auth/provider/direct.go b/backend/vendor/github.com/go-pkgz/auth/provider/direct.go index 8fba2405..31721e46 100644 --- a/backend/vendor/github.com/go-pkgz/auth/provider/direct.go +++ b/backend/vendor/github.com/go-pkgz/auth/provider/direct.go @@ -65,7 +65,7 @@ func (p DirectHandler) LoginHandler(w http.ResponseWriter, r *http.Request) { SessionOnly: sessOnly, } - if err = p.TokenService.Set(w, claims); err != nil { + if _, err = p.TokenService.Set(w, claims); err != nil { rest.SendErrorJSON(w, r, p.L, http.StatusInternalServerError, err, "failed to set token") return } diff --git a/backend/vendor/github.com/go-pkgz/auth/provider/oauth2.go b/backend/vendor/github.com/go-pkgz/auth/provider/oauth2.go index 896607eb..796c8f4b 100644 --- a/backend/vendor/github.com/go-pkgz/auth/provider/oauth2.go +++ b/backend/vendor/github.com/go-pkgz/auth/provider/oauth2.go @@ -105,7 +105,7 @@ func (p Oauth2Handler) LoginHandler(w http.ResponseWriter, r *http.Request) { }, } - if err := p.JwtService.Set(w, claims); err != nil { + if _, err := p.JwtService.Set(w, claims); err != nil { rest.SendErrorJSON(w, r, p.L, http.StatusInternalServerError, err, "failed to set token") return } @@ -192,7 +192,7 @@ func (p Oauth2Handler) AuthHandler(w http.ResponseWriter, r *http.Request) { SessionOnly: oauthClaims.SessionOnly, } - if err = p.JwtService.Set(w, claims); err != nil { + if _, err = p.JwtService.Set(w, claims); err != nil { rest.SendErrorJSON(w, r, p.L, http.StatusInternalServerError, err, "failed to set token") return } diff --git a/backend/vendor/github.com/go-pkgz/auth/provider/service.go b/backend/vendor/github.com/go-pkgz/auth/provider/service.go index 0915e2f1..d5a7ee10 100644 --- a/backend/vendor/github.com/go-pkgz/auth/provider/service.go +++ b/backend/vendor/github.com/go-pkgz/auth/provider/service.go @@ -30,7 +30,7 @@ type AvatarSaver interface { // TokenService defines interface accessing tokens type TokenService interface { Parse(tokenString string) (claims token.Claims, err error) - Set(w http.ResponseWriter, claims token.Claims) error + Set(w http.ResponseWriter, claims token.Claims) (token.Claims, error) Get(r *http.Request) (claims token.Claims, token string, err error) Reset(w http.ResponseWriter) } diff --git a/backend/vendor/github.com/go-pkgz/auth/token/jwt.go b/backend/vendor/github.com/go-pkgz/auth/token/jwt.go index d5598a7c..d49097b4 100644 --- a/backend/vendor/github.com/go-pkgz/auth/token/jwt.go +++ b/backend/vendor/github.com/go-pkgz/auth/token/jwt.go @@ -175,7 +175,7 @@ func (j *Service) validate(claims *Claims) error { // Set creates token cookie with xsrf cookie and put it to ResponseWriter // accepts claims and sets expiration if none defined. permanent flag means long-living cookie, // false makes it session only. -func (j *Service) Set(w http.ResponseWriter, claims Claims) error { +func (j *Service) Set(w http.ResponseWriter, claims Claims) (Claims, error) { if claims.ExpiresAt == 0 { claims.ExpiresAt = time.Now().Add(j.TokenDuration).Unix() } @@ -190,7 +190,7 @@ func (j *Service) Set(w http.ResponseWriter, claims Claims) error { tokenString, err := j.Token(claims) if err != nil { - return errors.Wrap(err, "failed to make token token") + return Claims{}, errors.Wrap(err, "failed to make token token") } cookieExpiration := 0 // session cookie @@ -206,7 +206,7 @@ func (j *Service) Set(w http.ResponseWriter, claims Claims) error { MaxAge: cookieExpiration, Secure: j.SecureCookies} http.SetCookie(w, &xsrfCookie) - return nil + return claims, nil } // Get token from url, header or cookie @@ -241,6 +241,10 @@ func (j *Service) Get(r *http.Request) (Claims, string, error) { return Claims{}, "", errors.Wrap(err, "failed to get token") } + if !fromCookie && j.IsExpired(claims) { + return Claims{}, "", errors.New("token expired") + } + if j.DisableXSRF { return claims, tokenString, nil }