diff --git a/client/internal/auth/device_flow_test.go b/client/internal/auth/device_flow_test.go index dc950ac63..466645ee9 100644 --- a/client/internal/auth/device_flow_test.go +++ b/client/internal/auth/device_flow_test.go @@ -3,15 +3,17 @@ package auth import ( "context" "fmt" - "github.com/golang-jwt/jwt" - "github.com/netbirdio/netbird/client/internal" - "github.com/stretchr/testify/require" "io" "net/http" "net/url" "strings" "testing" "time" + + "github.com/golang-jwt/jwt/v5" + "github.com/stretchr/testify/require" + + "github.com/netbirdio/netbird/client/internal" ) type mockHTTPClient struct { diff --git a/go.mod b/go.mod index 556218845..6beed2ff5 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,6 @@ require ( cunicu.li/go-rosenpass v0.4.0 github.com/cenkalti/backoff/v4 v4.3.0 github.com/cloudflare/circl v1.3.3 // indirect - github.com/golang-jwt/jwt v3.2.2+incompatible github.com/golang/protobuf v1.5.4 github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.0 @@ -48,6 +47,7 @@ require ( github.com/fsnotify/fsnotify v1.7.0 github.com/gliderlabs/ssh v0.3.8 github.com/godbus/dbus/v5 v5.1.0 + github.com/golang-jwt/jwt/v5 v5.3.0 github.com/golang/mock v1.6.0 github.com/google/go-cmp v0.7.0 github.com/google/gopacket v1.1.19 diff --git a/go.sum b/go.sum index 49fe92639..5a8236332 100644 --- a/go.sum +++ b/go.sum @@ -246,8 +246,8 @@ github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -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-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= +github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= diff --git a/management/server/auth/jwt/extractor.go b/management/server/auth/jwt/extractor.go index fab429125..d270d0ff1 100644 --- a/management/server/auth/jwt/extractor.go +++ b/management/server/auth/jwt/extractor.go @@ -5,7 +5,7 @@ import ( "net/url" "time" - "github.com/golang-jwt/jwt" + "github.com/golang-jwt/jwt/v5" log "github.com/sirupsen/logrus" nbcontext "github.com/netbirdio/netbird/management/server/context" diff --git a/management/server/auth/jwt/validator.go b/management/server/auth/jwt/validator.go index 5b38ca786..239447b96 100644 --- a/management/server/auth/jwt/validator.go +++ b/management/server/auth/jwt/validator.go @@ -17,7 +17,7 @@ import ( "sync" "time" - "github.com/golang-jwt/jwt" + "github.com/golang-jwt/jwt/v5" log "github.com/sirupsen/logrus" ) @@ -63,12 +63,10 @@ type Validator struct { } var ( - errKeyNotFound = errors.New("unable to find appropriate key") - errInvalidAudience = errors.New("invalid audience") - errInvalidIssuer = errors.New("invalid issuer") - errTokenEmpty = errors.New("required authorization token not found") - errTokenInvalid = errors.New("token is invalid") - errTokenParsing = errors.New("token could not be parsed") + errKeyNotFound = errors.New("unable to find appropriate key") + errTokenEmpty = errors.New("required authorization token not found") + errTokenInvalid = errors.New("token is invalid") + errTokenParsing = errors.New("token could not be parsed") ) func NewValidator(issuer string, audienceList []string, keysLocation string, idpSignkeyRefreshEnabled bool) *Validator { @@ -88,24 +86,6 @@ func NewValidator(issuer string, audienceList []string, keysLocation string, idp func (v *Validator) getKeyFunc(ctx context.Context) jwt.Keyfunc { return func(token *jwt.Token) (interface{}, error) { - // Verify 'aud' claim - var checkAud bool - for _, audience := range v.audienceList { - checkAud = token.Claims.(jwt.MapClaims).VerifyAudience(audience, false) - if checkAud { - break - } - } - if !checkAud { - return token, errInvalidAudience - } - - // Verify 'issuer' claim - checkIss := token.Claims.(jwt.MapClaims).VerifyIssuer(v.issuer, false) - if !checkIss { - return token, errInvalidIssuer - } - // If keys are rotated, verify the keys prior to token validation if v.idpSignkeyRefreshEnabled { // If the keys are invalid, retrieve new ones @@ -144,7 +124,7 @@ func (v *Validator) getKeyFunc(ctx context.Context) jwt.Keyfunc { } // ValidateAndParse validates the token and returns the parsed token -func (m *Validator) ValidateAndParse(ctx context.Context, token string) (*jwt.Token, error) { +func (v *Validator) ValidateAndParse(ctx context.Context, token string) (*jwt.Token, error) { // If the token is empty... if token == "" { // If we get here, the required token is missing @@ -153,7 +133,13 @@ func (m *Validator) ValidateAndParse(ctx context.Context, token string) (*jwt.To } // Now parse the token - parsedToken, err := jwt.Parse(token, m.getKeyFunc(ctx)) + parsedToken, err := jwt.Parse( + token, + v.getKeyFunc(ctx), + jwt.WithAudience(v.audienceList...), + jwt.WithIssuer(v.issuer), + jwt.WithIssuedAt(), + ) // Check if there was an error in parsing... if err != nil { diff --git a/management/server/auth/manager.go b/management/server/auth/manager.go index 53d479c90..ece9dc321 100644 --- a/management/server/auth/manager.go +++ b/management/server/auth/manager.go @@ -7,7 +7,7 @@ import ( "fmt" "hash/crc32" - "github.com/golang-jwt/jwt" + "github.com/golang-jwt/jwt/v5" "github.com/netbirdio/netbird/base62" nbjwt "github.com/netbirdio/netbird/management/server/auth/jwt" diff --git a/management/server/auth/manager_mock.go b/management/server/auth/manager_mock.go index bc7066548..30a7a7161 100644 --- a/management/server/auth/manager_mock.go +++ b/management/server/auth/manager_mock.go @@ -3,7 +3,7 @@ package auth import ( "context" - "github.com/golang-jwt/jwt" + "github.com/golang-jwt/jwt/v5" nbcontext "github.com/netbirdio/netbird/management/server/context" "github.com/netbirdio/netbird/management/server/types" diff --git a/management/server/auth/manager_test.go b/management/server/auth/manager_test.go index 55fb1e31a..c8015eb37 100644 --- a/management/server/auth/manager_test.go +++ b/management/server/auth/manager_test.go @@ -12,7 +12,7 @@ import ( "testing" "time" - "github.com/golang-jwt/jwt" + "github.com/golang-jwt/jwt/v5" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/management/server/http/middleware/auth_middleware.go b/management/server/http/middleware/auth_middleware.go index f221e64a9..6091a4c31 100644 --- a/management/server/http/middleware/auth_middleware.go +++ b/management/server/http/middleware/auth_middleware.go @@ -13,9 +13,9 @@ import ( "github.com/netbirdio/netbird/management/server/auth" nbcontext "github.com/netbirdio/netbird/management/server/context" "github.com/netbirdio/netbird/management/server/http/middleware/bypass" + "github.com/netbirdio/netbird/management/server/types" "github.com/netbirdio/netbird/shared/management/http/util" "github.com/netbirdio/netbird/shared/management/status" - "github.com/netbirdio/netbird/management/server/types" ) type EnsureAccountFunc func(ctx context.Context, userAuth nbcontext.UserAuth) (string, string, error) diff --git a/management/server/http/middleware/auth_middleware_test.go b/management/server/http/middleware/auth_middleware_test.go index 2285ed244..d815f5422 100644 --- a/management/server/http/middleware/auth_middleware_test.go +++ b/management/server/http/middleware/auth_middleware_test.go @@ -8,16 +8,15 @@ import ( "testing" "time" - "github.com/golang-jwt/jwt" + "github.com/golang-jwt/jwt/v5" "github.com/stretchr/testify/assert" "github.com/netbirdio/netbird/management/server/auth" nbjwt "github.com/netbirdio/netbird/management/server/auth/jwt" nbcontext "github.com/netbirdio/netbird/management/server/context" - "github.com/netbirdio/netbird/management/server/util" - "github.com/netbirdio/netbird/management/server/http/middleware/bypass" "github.com/netbirdio/netbird/management/server/types" + "github.com/netbirdio/netbird/management/server/util" ) const ( diff --git a/management/server/http/testing/testing_tools/tools.go b/management/server/http/testing/testing_tools/tools.go index e308f100f..1b82b156e 100644 --- a/management/server/http/testing/testing_tools/tools.go +++ b/management/server/http/testing/testing_tools/tools.go @@ -14,7 +14,7 @@ import ( "testing" "time" - "github.com/golang-jwt/jwt" + "github.com/golang-jwt/jwt/v5" "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/assert" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" diff --git a/management/server/idp/auth0.go b/management/server/idp/auth0.go index 497f1944f..1eb8434d3 100644 --- a/management/server/idp/auth0.go +++ b/management/server/idp/auth0.go @@ -4,6 +4,7 @@ import ( "bytes" "compress/gzip" "context" + "encoding/base64" "encoding/json" "fmt" "io" @@ -16,7 +17,6 @@ import ( "github.com/netbirdio/netbird/management/server/telemetry" - "github.com/golang-jwt/jwt" log "github.com/sirupsen/logrus" ) @@ -231,7 +231,7 @@ func (c *Auth0Credentials) parseRequestJWTResponse(rawBody io.ReadCloser) (JWTTo if jwtToken.ExpiresIn == 0 && jwtToken.AccessToken == "" { return jwtToken, fmt.Errorf("error while reading response body, expires_in: %d and access_token: %s", jwtToken.ExpiresIn, jwtToken.AccessToken) } - data, err := jwt.DecodeSegment(strings.Split(jwtToken.AccessToken, ".")[1]) + data, err := base64.RawURLEncoding.DecodeString(strings.Split(jwtToken.AccessToken, ".")[1]) if err != nil { return jwtToken, err } diff --git a/management/server/idp/auth0_test.go b/management/server/idp/auth0_test.go index f8a0e1210..66c16870b 100644 --- a/management/server/idp/auth0_test.go +++ b/management/server/idp/auth0_test.go @@ -11,12 +11,11 @@ import ( "testing" "time" + "github.com/golang-jwt/jwt/v5" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/netbirdio/netbird/management/server/telemetry" - - "github.com/golang-jwt/jwt" - "github.com/stretchr/testify/assert" ) type mockHTTPClient struct { diff --git a/management/server/idp/authentik.go b/management/server/idp/authentik.go index 00d30d645..2f87a9bba 100644 --- a/management/server/idp/authentik.go +++ b/management/server/idp/authentik.go @@ -2,6 +2,7 @@ package idp import ( "context" + "encoding/base64" "fmt" "io" "net/http" @@ -11,7 +12,6 @@ import ( "sync" "time" - "github.com/golang-jwt/jwt" log "github.com/sirupsen/logrus" "goauthentik.io/api/v3" @@ -166,7 +166,7 @@ func (ac *AuthentikCredentials) parseRequestJWTResponse(rawBody io.ReadCloser) ( return jwtToken, fmt.Errorf("error while reading response body, expires_in: %d and access_token: %s", jwtToken.ExpiresIn, jwtToken.AccessToken) } - data, err := jwt.DecodeSegment(strings.Split(jwtToken.AccessToken, ".")[1]) + data, err := base64.RawURLEncoding.DecodeString(strings.Split(jwtToken.AccessToken, ".")[1]) if err != nil { return jwtToken, err } diff --git a/management/server/idp/azure.go b/management/server/idp/azure.go index 35b86764d..393a39e3e 100644 --- a/management/server/idp/azure.go +++ b/management/server/idp/azure.go @@ -2,6 +2,7 @@ package idp import ( "context" + "encoding/base64" "fmt" "io" "net/http" @@ -10,7 +11,6 @@ import ( "sync" "time" - "github.com/golang-jwt/jwt" log "github.com/sirupsen/logrus" "github.com/netbirdio/netbird/management/server/telemetry" @@ -168,7 +168,7 @@ func (ac *AzureCredentials) parseRequestJWTResponse(rawBody io.ReadCloser) (JWTT return jwtToken, fmt.Errorf("error while reading response body, expires_in: %d and access_token: %s", jwtToken.ExpiresIn, jwtToken.AccessToken) } - data, err := jwt.DecodeSegment(strings.Split(jwtToken.AccessToken, ".")[1]) + data, err := base64.RawURLEncoding.DecodeString(strings.Split(jwtToken.AccessToken, ".")[1]) if err != nil { return jwtToken, err } diff --git a/management/server/idp/keycloak.go b/management/server/idp/keycloak.go index 07d84058c..c611317ab 100644 --- a/management/server/idp/keycloak.go +++ b/management/server/idp/keycloak.go @@ -2,6 +2,7 @@ package idp import ( "context" + "encoding/base64" "fmt" "io" "net/http" @@ -11,7 +12,6 @@ import ( "sync" "time" - "github.com/golang-jwt/jwt" log "github.com/sirupsen/logrus" "github.com/netbirdio/netbird/management/server/telemetry" @@ -158,7 +158,7 @@ func (kc *KeycloakCredentials) parseRequestJWTResponse(rawBody io.ReadCloser) (J return jwtToken, fmt.Errorf("error while reading response body, expires_in: %d and access_token: %s", jwtToken.ExpiresIn, jwtToken.AccessToken) } - data, err := jwt.DecodeSegment(strings.Split(jwtToken.AccessToken, ".")[1]) + data, err := base64.RawURLEncoding.DecodeString(strings.Split(jwtToken.AccessToken, ".")[1]) if err != nil { return jwtToken, err } diff --git a/management/server/idp/zitadel.go b/management/server/idp/zitadel.go index 343357927..24228346a 100644 --- a/management/server/idp/zitadel.go +++ b/management/server/idp/zitadel.go @@ -2,6 +2,7 @@ package idp import ( "context" + "encoding/base64" "errors" "fmt" "io" @@ -12,7 +13,6 @@ import ( "sync" "time" - "github.com/golang-jwt/jwt" log "github.com/sirupsen/logrus" "github.com/netbirdio/netbird/management/server/telemetry" @@ -253,7 +253,7 @@ func (zc *ZitadelCredentials) parseRequestJWTResponse(rawBody io.ReadCloser) (JW return jwtToken, fmt.Errorf("error while reading response body, expires_in: %d and access_token: %s", jwtToken.ExpiresIn, jwtToken.AccessToken) } - data, err := jwt.DecodeSegment(strings.Split(jwtToken.AccessToken, ".")[1]) + data, err := base64.RawURLEncoding.DecodeString(strings.Split(jwtToken.AccessToken, ".")[1]) if err != nil { return jwtToken, err }