Skip to content

Commit

Permalink
Merge pull request #1758 from umputun/paskal/jwt_v5
Browse files Browse the repository at this point in the history
Update to go-pkgz/auth/v2 and golang-jwt/jwt/v5
  • Loading branch information
umputun authored Dec 10, 2024
2 parents 6402ef9 + e61a46e commit d5162d3
Show file tree
Hide file tree
Showing 80 changed files with 2,127 additions and 1,829 deletions.
2 changes: 1 addition & 1 deletion backend/app/cmd/avatar.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
log "github.com/go-pkgz/lgr"
bolt "go.etcd.io/bbolt"

"github.com/go-pkgz/auth/avatar"
"github.com/go-pkgz/auth/v2/avatar"
)

// AvatarCommand set of flags and command for avatar migration
Expand Down
2 changes: 1 addition & 1 deletion backend/app/cmd/avatar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"os"
"testing"

"github.com/go-pkgz/auth/avatar"
"github.com/go-pkgz/auth/v2/avatar"
"github.com/jessevdk/go-flags"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down
40 changes: 23 additions & 17 deletions backend/app/cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ import (
"github.com/go-pkgz/lcw/v2/eventbus"
log "github.com/go-pkgz/lgr"
ntf "github.com/go-pkgz/notify"
"github.com/golang-jwt/jwt"
"github.com/golang-jwt/jwt/v5"
"github.com/kyokomi/emoji/v2"
bolt "go.etcd.io/bbolt"

"github.com/go-pkgz/auth"
"github.com/go-pkgz/auth/avatar"
"github.com/go-pkgz/auth/provider"
"github.com/go-pkgz/auth/provider/sender"
"github.com/go-pkgz/auth/token"
"github.com/go-pkgz/auth/v2"
"github.com/go-pkgz/auth/v2/avatar"
"github.com/go-pkgz/auth/v2/provider"
"github.com/go-pkgz/auth/v2/provider/sender"
"github.com/go-pkgz/auth/v2/token"
cache "github.com/go-pkgz/lcw/v2"

"github.com/umputun/remark42/backend/app/migrator"
Expand Down Expand Up @@ -1109,10 +1109,10 @@ func (s *ServerCommand) makeNotifyDestinations(authenticator *auth.Service) ([]n
TokenGenFn: func(userID, email, site string) (string, error) {
claims := token.Claims{
Handshake: &token.Handshake{ID: userID + "::" + email},
StandardClaims: jwt.StandardClaims{
Audience: site,
ExpiresAt: time.Now().Add(100 * 365 * 24 * time.Hour).Unix(),
NotBefore: time.Now().Add(-1 * time.Minute).Unix(),
RegisteredClaims: jwt.RegisteredClaims{
Audience: jwt.ClaimStrings{site},
ExpiresAt: jwt.NewNumericDate(time.Now().Add(100 * 365 * 24 * time.Hour)),
NotBefore: jwt.NewNumericDate(time.Now().Add(-1 * time.Minute)),
Issuer: "remark42",
},
}
Expand Down Expand Up @@ -1215,10 +1215,16 @@ func (s *ServerCommand) getAuthenticator(ds *service.DataStore, avas avatar.Stor
if c.User == nil {
return c
}
c.User.SetAdmin(ds.IsAdmin(c.Audience, c.User.ID))
c.User.SetBoolAttr("blocked", ds.IsBlocked(c.Audience, c.User.ID))
// Audience is a slice but we set it to a single element, and situation when there is no audience or there are more than one is unexpected
if len(c.Audience) != 1 {
return c
}
audience := c.Audience[0]

c.User.SetAdmin(ds.IsAdmin(audience, c.User.ID))
c.User.SetBoolAttr("blocked", ds.IsBlocked(audience, c.User.ID))
var err error
c.User.Email, err = ds.GetUserEmail(c.Audience, c.User.ID)
c.User.Email, err = ds.GetUserEmail(audience, c.User.ID)
if err != nil {
log.Printf("[WARN] can't read email for %s, %v", c.User.ID, err)
}
Expand Down Expand Up @@ -1350,11 +1356,11 @@ func newAuthRefreshCache() *authRefreshCache {
}

// Get implements cache getter with key converted to string
func (c *authRefreshCache) Get(key interface{}) (interface{}, bool) {
return c.LoadingCache.Peek(key.(string))
func (c *authRefreshCache) Get(key string) (token.Claims, bool) {
return c.LoadingCache.Peek(key)
}

// Set implements cache setter with key converted to string
func (c *authRefreshCache) Set(key, value interface{}) {
_, _ = c.LoadingCache.Get(key.(string), func() (token.Claims, error) { return value.(token.Claims), nil })
func (c *authRefreshCache) Set(key string, value token.Claims) {
_, _ = c.LoadingCache.Get(key, func() (token.Claims, error) { return value, nil })
}
34 changes: 26 additions & 8 deletions backend/app/cmd/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import (
"testing"
"time"

"github.com/go-pkgz/auth/token"
"github.com/golang-jwt/jwt"
"github.com/go-pkgz/auth/v2/token"
"github.com/golang-jwt/jwt/v5"
"github.com/jessevdk/go-flags"
"go.uber.org/goleak"

Expand Down Expand Up @@ -609,11 +609,11 @@ func TestServerAuthHooks(t *testing.T) {
tkService.TokenDuration = time.Second

claims := token.Claims{
StandardClaims: jwt.StandardClaims{
Audience: "remark",
RegisteredClaims: jwt.RegisteredClaims{
Audience: jwt.ClaimStrings{"remark"},
Issuer: "remark",
ExpiresAt: time.Now().Add(time.Second).Unix(),
NotBefore: time.Now().Add(-1 * time.Minute).Unix(),
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Second)),
NotBefore: jwt.NewNumericDate(time.Now().Add(-1 * time.Minute)),
},
User: &token.User{
ID: "github_dev",
Expand All @@ -639,7 +639,7 @@ func TestServerAuthHooks(t *testing.T) {

// try to add comment with no-aud claim
badClaimsNoAud := claims
badClaimsNoAud.Audience = ""
badClaimsNoAud.Audience = jwt.ClaimStrings{""}
tkNoAud, err := tkService.Token(badClaimsNoAud)
require.NoError(t, err)
t.Logf("no-aud claims: %s", tkNoAud)
Expand All @@ -655,9 +655,27 @@ func TestServerAuthHooks(t *testing.T) {
require.NoError(t, resp.Body.Close())
assert.Equal(t, http.StatusUnauthorized, resp.StatusCode, "user without aud claim rejected, \n"+tkNoAud+"\n"+string(body))

// try to add comment with multiple auds
badClaimsMultipleAud := claims
badClaimsMultipleAud.Audience = jwt.ClaimStrings{"remark", "second_aud"}
tkMultipleAuds, err := tkService.Token(badClaimsMultipleAud)
require.NoError(t, err)
t.Logf("multiple aud claims: %s", tkMultipleAuds)
req, err = http.NewRequest("POST", fmt.Sprintf("http://localhost:%d/api/v1/comment", port),
strings.NewReader(`{"text": "test 123", "locator":{"url": "https://radio-t.com/p/2018/12/29/podcast-631/",
"site": "remark"}}`))
require.NoError(t, err)
req.Header.Set("X-JWT", tkMultipleAuds)
resp, err = client.Do(req)
require.NoError(t, err)
body, err = io.ReadAll(resp.Body)
require.NoError(t, err)
require.NoError(t, resp.Body.Close())
assert.Equal(t, http.StatusUnauthorized, resp.StatusCode, "user with multiple auds claim rejected, \n"+tkMultipleAuds+"\n"+string(body))

// try to add comment without user set
badClaimsNoUser := claims
badClaimsNoUser.Audience = "remark"
badClaimsNoUser.Audience = jwt.ClaimStrings{"remark"}
badClaimsNoUser.User = nil
tkNoUser, err := tkService.Token(badClaimsNoUser)
require.NoError(t, err)
Expand Down
16 changes: 12 additions & 4 deletions backend/app/rest/api/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (

"github.com/go-chi/chi/v5"
"github.com/go-chi/render"
"github.com/go-pkgz/auth"
"github.com/go-pkgz/auth/v2"
cache "github.com/go-pkgz/lcw/v2"
log "github.com/go-pkgz/lgr"
R "github.com/go-pkgz/rest"
Expand Down Expand Up @@ -107,13 +107,21 @@ func (a *admin) deleteMeRequestCtrl(w http.ResponseWriter, r *http.Request) {
return
}

if err = a.dataService.DeleteUserDetail(claims.Audience, claims.User.ID, engine.AllUserDetails); err != nil {
// Audience is a slice but we set it to a single element, and situation when there is no audience or there are more than one is unexpected
if len(claims.Audience) != 1 {
rest.SendErrorJSON(w, r, http.StatusBadRequest, fmt.Errorf("bad request"), "can't process token, claims.Audience expected to be a single element but it's not", rest.ErrActionRejected)
return
}

audience := claims.Audience[0]

if err = a.dataService.DeleteUserDetail(audience, claims.User.ID, engine.AllUserDetails); err != nil {
code := parseError(err, rest.ErrInternal)
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't delete user details for user", code)
return
}

if err = a.dataService.DeleteUser(claims.Audience, claims.User.ID, store.HardDelete); err != nil {
if err = a.dataService.DeleteUser(audience, claims.User.ID, store.HardDelete); err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't delete user", rest.ErrNoAccess)
return
}
Expand All @@ -126,7 +134,7 @@ func (a *admin) deleteMeRequestCtrl(w http.ResponseWriter, r *http.Request) {
}
}

a.cache.Flush(cache.Flusher(claims.Audience).Scopes(claims.Audience, claims.User.ID, lastCommentsScope))
a.cache.Flush(cache.Flusher(audience).Scopes(audience, claims.User.ID, lastCommentsScope))
render.Status(r, http.StatusOK)
render.JSON(w, r, R.JSON{"user_id": claims.User.ID, "site_id": claims.Audience})
}
Expand Down
30 changes: 15 additions & 15 deletions backend/app/rest/api/admin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import (
"testing"
"time"

"github.com/go-pkgz/auth/token"
"github.com/go-pkgz/auth/v2/token"
cache "github.com/go-pkgz/lcw/v2"
R "github.com/go-pkgz/rest"
"github.com/golang-jwt/jwt"
"github.com/golang-jwt/jwt/v5"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

Expand Down Expand Up @@ -708,12 +708,12 @@ func TestAdmin_DeleteMeRequest(t *testing.T) {

claims := token.Claims{
SessionOnly: true,
StandardClaims: jwt.StandardClaims{
Audience: "remark42",
Id: "1234567",
RegisteredClaims: jwt.RegisteredClaims{
Audience: jwt.ClaimStrings{"remark42"},
ID: "1234567",
Issuer: "remark42",
NotBefore: time.Now().Add(-1 * time.Minute).Unix(),
ExpiresAt: time.Now().Add(30 * time.Minute).Unix(),
NotBefore: jwt.NewNumericDate(time.Now().Add(-1 * time.Minute)),
ExpiresAt: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)),
},
User: &token.User{
ID: "user1",
Expand Down Expand Up @@ -777,12 +777,12 @@ func TestAdmin_DeleteMeRequestFailed(t *testing.T) {
// try with bad auth
claims := token.Claims{
SessionOnly: true,
StandardClaims: jwt.StandardClaims{
Audience: "remark42",
Id: "provider1_1234567",
RegisteredClaims: jwt.RegisteredClaims{
Audience: jwt.ClaimStrings{"remark42"},
ID: "provider1_1234567",
Issuer: "remark42",
NotBefore: time.Now().Add(-1 * time.Minute).Unix(),
ExpiresAt: time.Now().Add(30 * time.Minute).Unix(),
NotBefore: jwt.NewNumericDate(time.Now().Add(-1 * time.Minute)),
ExpiresAt: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)),
},
User: &token.User{
ID: "provider1_user1",
Expand Down Expand Up @@ -835,7 +835,7 @@ func TestAdmin_DeleteMeRequestFailed(t *testing.T) {

// try with wrong audience
badClaimsMultipleAudience := claims
badClaimsMultipleAudience.StandardClaims.Audience = "something else"
badClaimsMultipleAudience.RegisteredClaims.Audience = jwt.ClaimStrings{"remark42", "something else"}
tkn, err = srv.Authenticator.TokenService().Token(badClaimsMultipleAudience)
assert.NoError(t, err)
req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%s/api/v1/admin/deleteme?token=%s", ts.URL, tkn), http.NoBody)
Expand All @@ -847,8 +847,8 @@ func TestAdmin_DeleteMeRequestFailed(t *testing.T) {
b, err = io.ReadAll(resp.Body)
assert.NoError(t, err)
assert.NoError(t, resp.Body.Close())
assert.Contains(t, string(b), `site \"something else\" not found`)
badClaimsMultipleAudience.StandardClaims.Audience = "remark42"
assert.Contains(t, string(b), "can't process token, claims.Audience expected to be a single element but it's not")
badClaimsMultipleAudience.RegisteredClaims.Audience = jwt.ClaimStrings{"remark42"}
}

func TestAdmin_GetUserInfo(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion backend/app/rest/api/rest.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
"github.com/go-chi/chi/v5/middleware"
"github.com/go-chi/cors"
"github.com/go-chi/render"
"github.com/go-pkgz/auth"
"github.com/go-pkgz/auth/v2"
"github.com/go-pkgz/lcw/v2"
log "github.com/go-pkgz/lgr"
R "github.com/go-pkgz/rest"
Expand Down
22 changes: 11 additions & 11 deletions backend/app/rest/api/rest_private.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ import (

"github.com/go-chi/chi/v5"
"github.com/go-chi/render"
"github.com/go-pkgz/auth"
"github.com/go-pkgz/auth/token"
"github.com/go-pkgz/auth/v2"
"github.com/go-pkgz/auth/v2/token"
cache "github.com/go-pkgz/lcw/v2"
log "github.com/go-pkgz/lgr"
R "github.com/go-pkgz/rest"
"github.com/golang-jwt/jwt"
"github.com/golang-jwt/jwt/v5"
"github.com/hashicorp/go-multierror"

"github.com/umputun/remark42/backend/app/notify"
Expand Down Expand Up @@ -362,10 +362,10 @@ func (s *private) sendEmailConfirmationCtrl(w http.ResponseWriter, r *http.Reque

claims := token.Claims{
Handshake: &token.Handshake{ID: user.ID + "::" + subscribe.Address},
StandardClaims: jwt.StandardClaims{
Audience: r.URL.Query().Get("site"),
ExpiresAt: time.Now().Add(30 * time.Minute).Unix(),
NotBefore: time.Now().Add(-1 * time.Minute).Unix(),
RegisteredClaims: jwt.RegisteredClaims{
Audience: jwt.ClaimStrings{r.URL.Query().Get("site")},
ExpiresAt: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)),
NotBefore: jwt.NewNumericDate(time.Now().Add(-1 * time.Minute)),
Issuer: "remark42",
},
}
Expand Down Expand Up @@ -704,11 +704,11 @@ func (s *private) deleteMeCtrl(w http.ResponseWriter, r *http.Request) {
siteID := r.URL.Query().Get("site")

claims := token.Claims{
StandardClaims: jwt.StandardClaims{
Audience: siteID,
RegisteredClaims: jwt.RegisteredClaims{
Audience: jwt.ClaimStrings{siteID},
Issuer: "remark42",
ExpiresAt: time.Now().AddDate(0, 3, 0).Unix(),
NotBefore: time.Now().Add(-1 * time.Minute).Unix(),
ExpiresAt: jwt.NewNumericDate(time.Now().AddDate(0, 3, 0)),
NotBefore: jwt.NewNumericDate(time.Now().Add(-1 * time.Minute)),
},
User: &token.User{
ID: user.ID,
Expand Down
12 changes: 6 additions & 6 deletions backend/app/rest/api/rest_private_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ import (
"time"

"github.com/go-chi/render"
"github.com/go-pkgz/auth/token"
"github.com/go-pkgz/auth/v2/token"
"github.com/go-pkgz/lgr"
R "github.com/go-pkgz/rest"
"github.com/golang-jwt/jwt"
"github.com/golang-jwt/jwt/v5"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

Expand Down Expand Up @@ -861,10 +861,10 @@ func TestRest_EmailAndTelegram(t *testing.T) {
// issue good token
claims := token.Claims{
Handshake: &token.Handshake{ID: "provider1_dev::[email protected]"},
StandardClaims: jwt.StandardClaims{
Audience: "remark42",
ExpiresAt: time.Now().Add(10 * time.Minute).Unix(),
NotBefore: time.Now().Add(-1 * time.Minute).Unix(),
RegisteredClaims: jwt.RegisteredClaims{
Audience: jwt.ClaimStrings{"remark42"},
ExpiresAt: jwt.NewNumericDate(time.Now().Add(10 * time.Minute)),
NotBefore: jwt.NewNumericDate(time.Now().Add(-1 * time.Minute)),
Issuer: "remark42",
},
}
Expand Down
8 changes: 4 additions & 4 deletions backend/app/rest/api/rest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ import (
"testing"
"time"

"github.com/go-pkgz/auth"
"github.com/go-pkgz/auth/avatar"
"github.com/go-pkgz/auth/provider"
"github.com/go-pkgz/auth/token"
"github.com/go-pkgz/auth/v2"
"github.com/go-pkgz/auth/v2/avatar"
"github.com/go-pkgz/auth/v2/provider"
"github.com/go-pkgz/auth/v2/token"
cache "github.com/go-pkgz/lcw/v2"
R "github.com/go-pkgz/rest"
"github.com/stretchr/testify/assert"
Expand Down
2 changes: 1 addition & 1 deletion backend/app/rest/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"fmt"
"net/http"

"github.com/go-pkgz/auth/token"
"github.com/go-pkgz/auth/v2/token"

"github.com/umputun/remark42/backend/app/store"
)
Expand Down
4 changes: 2 additions & 2 deletions backend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ require (
github.com/go-chi/chi/v5 v5.1.0
github.com/go-chi/cors v1.2.1
github.com/go-chi/render v1.0.3
github.com/go-pkgz/auth v1.24.3-0.20241007090635-78537e6f812d
github.com/go-pkgz/auth/v2 v2.0.0-20241208183119-88b3a842be9f
github.com/go-pkgz/jrpc v0.3.0
github.com/go-pkgz/lcw/v2 v2.0.0
github.com/go-pkgz/lgr v0.11.1
github.com/go-pkgz/notify v1.2.0
github.com/go-pkgz/repeater v1.2.0
github.com/go-pkgz/rest v1.19.0
github.com/go-pkgz/syncs v1.3.2
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/golang-jwt/jwt/v5 v5.2.1
github.com/google/uuid v1.6.0
github.com/gorilla/feeds v1.2.0
github.com/hashicorp/go-multierror v1.1.1
Expand Down
Loading

0 comments on commit d5162d3

Please sign in to comment.