@ -11,11 +11,15 @@ import (
"github.com/go-jose/go-jose/v3"
"github.com/go-jose/go-jose/v3/jwt"
"golang.org/x/oauth2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
authlib "github.com/grafana/authlib/authn"
"github.com/grafana/grafana/pkg/models/roletype"
"github.com/grafana/grafana/pkg/models/usertoken"
"github.com/grafana/grafana/pkg/services/authn"
"github.com/grafana/grafana/pkg/services/login"
"github.com/grafana/grafana/pkg/services/signingkeys"
@ -29,28 +33,45 @@ var (
validPayload = ExtendedJWTClaims {
Claims : jwt . Claims {
Issuer : "http://localhost:3000" ,
Subject : "user:id:2 " ,
Subject : "access-policy:this-uid " ,
Audience : jwt . Audience { "http://localhost:3000" } ,
ID : "1234567890" ,
Expiry : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 3 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
IssuedAt : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 2 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
} ,
ClientID : "grafana" ,
Scopes : [ ] string { "profile" , "groups" } ,
Entitlements : map [ string ] [ ] string {
"dashboards:create" : {
"folders:uid:general" ,
} ,
"folders:read" : {
"folders:uid:general" ,
} ,
"datasources:explore" : nil ,
"datasources.insights:read" : { } ,
Scopes : [ ] string { "profile" , "groups" } ,
DelegatedPermissions : [ ] string { "dashboards:create" , "folders:read" , "datasources:explore" , "datasources.insights:read" } ,
Permissions : [ ] string { "fixed:folders:reader" } ,
}
validIDPayload = ExtendedJWTClaims {
Claims : jwt . Claims {
Issuer : "http://localhost:3000" ,
Subject : "user:2" ,
Audience : jwt . Audience { "http://localhost:3000" } ,
ID : "1234567890" ,
Expiry : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 3 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
IssuedAt : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 2 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
} ,
Scopes : [ ] string { "profile" , "groups" } ,
}
pk , _ = rsa . GenerateKey ( rand . Reader , 4096 )
)
type mockVerifier struct {
Claims [ ] ExtendedJWTClaims
Error error
counter int
}
func ( m * mockVerifier ) Verify ( ctx context . Context , token string ) ( * authlib . Claims [ ExtendedJWTClaims ] , error ) {
m . counter ++
claims := m . Claims [ m . counter - 1 ]
return & authlib . Claims [ ExtendedJWTClaims ] {
Claims : & claims . Claims ,
Rest : claims ,
} , m . Error
}
func TestExtendedJWT_Test ( t * testing . T ) {
type testCase struct {
name string
@ -63,7 +84,9 @@ func TestExtendedJWT_Test(t *testing.T) {
{
name : "should return false when extended jwt is disabled" ,
cfg : & setting . Cfg {
ExtendedJWTAuthEnabled : false ,
ExtJWTAuth : setting . ExtJWTSettings {
Enabled : false ,
} ,
} ,
authHeaderFunc : func ( ) string { return "eyJ" } ,
want : false ,
@ -71,13 +94,13 @@ func TestExtendedJWT_Test(t *testing.T) {
{
name : "should return true when Authorization header contains Bearer prefix" ,
cfg : nil ,
authHeaderFunc : func ( ) string { return "Bearer " + generateToken ( validPayload , pk , jose . RS256 ) } ,
authHeaderFunc : func ( ) string { return "Bearer " + generateToken ( validPayload , pk , jose . RS256 , "at+jwt" ) } ,
want : true ,
} ,
{
name : "should return true when Authorization header only contains the token" ,
cfg : nil ,
authHeaderFunc : func ( ) string { return generateToken ( validPayload , pk , jose . RS256 ) } ,
authHeaderFunc : func ( ) string { return generateToken ( validPayload , pk , jose . RS256 , "at+jwt" ) } ,
want : true ,
} ,
{
@ -95,23 +118,25 @@ func TestExtendedJWT_Test(t *testing.T) {
{
name : "should return false when the issuer does not match the configured issuer" ,
cfg : & setting . Cfg {
ExtendedJWTExpectIssuer : "http://localhost:3000" ,
ExtJWTAuth : setting . ExtJWTSettings {
ExpectIssuer : "http://localhost:3000" ,
} ,
} ,
authHeaderFunc : func ( ) string {
payload := validPayload
payload . Issuer = "http://unknown-issuer"
return generateToken ( payload , pk , jose . RS256 )
return generateToken ( payload , pk , jose . RS256 , "at+jwt" )
} ,
want : false ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
env := setupTestCtx ( t , t c. cfg )
env := setupTestCtx ( tc . cfg )
validHTTPReq := & http . Request {
Header : map [ string ] [ ] string {
"Authorizatio n" : { tc . authHeaderFunc ( ) } ,
"X-Access-Toke n" : { tc . authHeaderFunc ( ) } ,
} ,
}
@ -129,16 +154,39 @@ func TestExtendedJWT_Authenticate(t *testing.T) {
type testCase struct {
name string
payload ExtendedJWTClaims
idPayload * ExtendedJWTClaims
orgID int64
want * authn . Identity
initTestEnv func ( env * testEnv )
wantErr bool
wantErr error
}
testCases := [ ] testCase {
{
name : "successful authentication" ,
name : "successful authentication as service " ,
payload : validPayload ,
orgID : 1 ,
want : & authn . Identity { OrgID : 1 , OrgName : "" ,
OrgRoles : map [ int64 ] roletype . RoleType ( nil ) ,
ID : "access-policy:this-uid" , Login : "" , Name : "" , Email : "" ,
IsGrafanaAdmin : ( * bool ) ( nil ) , AuthenticatedBy : "extendedjwt" ,
AuthID : "access-policy:this-uid" , IsDisabled : false , HelpFlags1 : 0x0 ,
LastSeenAt : time . Date ( 1 , time . January , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
Teams : [ ] int64 ( nil ) , Groups : [ ] string ( nil ) ,
OAuthToken : ( * oauth2 . Token ) ( nil ) , SessionToken : ( * usertoken . UserToken ) ( nil ) ,
ClientParams : authn . ClientParams { SyncUser : false ,
AllowSignUp : false , EnableUser : false , FetchSyncedUser : false ,
SyncTeams : false , SyncOrgRoles : false , CacheAuthProxyKey : "" ,
LookUpParams : login . UserLookupParams { UserID : ( * int64 ) ( nil ) ,
Email : ( * string ) ( nil ) , Login : ( * string ) ( nil ) } , SyncPermissions : true ,
FetchPermissionsParams : authn . FetchPermissionsParams { ActionsLookup : [ ] string ( nil ) , Roles : [ ] string { "fixed:folders:reader" } } } ,
Permissions : map [ int64 ] map [ string ] [ ] string ( nil ) , IDToken : "" } ,
wantErr : nil ,
} ,
{
name : "successful authentication as user" ,
payload : validPayload ,
idPayload : & validIDPayload ,
orgID : 1 ,
initTestEnv : func ( env * testEnv ) {
env . userSvc . ExpectedSignedInUser = & user . SignedInUser {
UserID : 2 ,
@ -149,50 +197,26 @@ func TestExtendedJWT_Authenticate(t *testing.T) {
Login : "johndoe" ,
}
} ,
want : & authn . Identity {
OrgID : 1 ,
OrgName : "" ,
OrgRoles : map [ int64 ] roletype . RoleType { 1 : roletype . RoleAdmin } ,
ID : "user:2" ,
Login : "johndoe" ,
Name : "John Doe" ,
Email : "johndoe@grafana.com" ,
IsGrafanaAdmin : boolPtr ( false ) ,
AuthenticatedBy : login . ExtendedJWTModule ,
AuthID : "" ,
IsDisabled : false ,
HelpFlags1 : 0 ,
Permissions : map [ int64 ] map [ string ] [ ] string {
1 : {
"dashboards:create" : {
"folders:uid:general" ,
} ,
"folders:read" : {
"folders:uid:general" ,
} ,
"datasources:explore" : nil ,
"datasources.insights:read" : [ ] string { } ,
} ,
} ,
ClientParams : authn . ClientParams {
SyncUser : false ,
AllowSignUp : false ,
FetchSyncedUser : false ,
EnableUser : false ,
SyncOrgRoles : false ,
SyncTeams : false ,
SyncPermissions : false ,
LookUpParams : login . UserLookupParams {
UserID : nil ,
Email : nil ,
Login : nil ,
} ,
} ,
} ,
wantErr : false ,
want : & authn . Identity { OrgID : 1 , OrgName : "" ,
OrgRoles : map [ int64 ] roletype . RoleType ( nil ) , ID : "user:2" ,
Login : "" , Name : "" , Email : "" ,
IsGrafanaAdmin : ( * bool ) ( nil ) , AuthenticatedBy : "extendedjwt" ,
AuthID : "access-policy:this-uid" , IsDisabled : false , HelpFlags1 : 0x0 ,
LastSeenAt : time . Date ( 1 , time . January , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
Teams : [ ] int64 ( nil ) , Groups : [ ] string ( nil ) ,
OAuthToken : ( * oauth2 . Token ) ( nil ) , SessionToken : ( * usertoken . UserToken ) ( nil ) ,
ClientParams : authn . ClientParams { SyncUser : false , AllowSignUp : false ,
EnableUser : false , FetchSyncedUser : true , SyncTeams : false ,
SyncOrgRoles : false , CacheAuthProxyKey : "" ,
LookUpParams : login . UserLookupParams { UserID : ( * int64 ) ( nil ) , Email : ( * string ) ( nil ) , Login : ( * string ) ( nil ) } ,
SyncPermissions : true ,
FetchPermissionsParams : authn . FetchPermissionsParams { ActionsLookup : [ ] string { "dashboards:create" ,
"folders:read" , "datasources:explore" , "datasources.insights:read" } ,
Roles : [ ] string ( nil ) } } , Permissions : map [ int64 ] map [ string ] [ ] string ( nil ) , IDToken : "" } ,
wantErr : nil ,
} ,
{
name : "should return error when the user cannot be parsed from the Subject claim " ,
name : "should return error when the subject is not an access-policy" ,
payload : ExtendedJWTClaims {
Claims : jwt . Claims {
Issuer : "http://localhost:3000" ,
@ -202,94 +226,40 @@ func TestExtendedJWT_Authenticate(t *testing.T) {
Expiry : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 3 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
IssuedAt : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 2 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
} ,
ClientID : "grafana" ,
Scopes : [ ] string { "profile" , "groups" } ,
Permissions : [ ] string { "fixed:folders:reader" } ,
} ,
orgID : 1 ,
want : nil ,
wantErr : true ,
} ,
{
name : "should return error when the OrgId is not the ID of the default org" ,
payload : ExtendedJWTClaims {
Claims : jwt . Claims {
Issuer : "http://localhost:3000" ,
Subject : "user:id:2" ,
Audience : jwt . Audience { "http://localhost:3000" } ,
ID : "1234567890" ,
Expiry : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 3 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
IssuedAt : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 2 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
} ,
ClientID : "grafana" ,
Scopes : [ ] string { "profile" , "groups" } ,
} ,
orgID : 0 ,
want : nil ,
wantErr : true ,
} ,
{
name : "should return error when the user cannot be found" ,
payload : ExtendedJWTClaims {
Claims : jwt . Claims {
Issuer : "http://localhost:3000" ,
Subject : "user:id:2" ,
Audience : jwt . Audience { "http://localhost:3000" } ,
ID : "1234567890" ,
Expiry : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 3 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
IssuedAt : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 2 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
} ,
ClientID : "grafana" ,
Scopes : [ ] string { "profile" , "groups" } ,
} ,
orgID : 1 ,
want : nil ,
initTestEnv : func ( env * testEnv ) {
env . userSvc . ExpectedError = user . ErrUserNotFound
} ,
wantErr : true ,
} ,
{
name : "should return error when entitlements claim is missing" ,
payload : ExtendedJWTClaims {
Claims : jwt . Claims {
Issuer : "http://localhost:3000" ,
Subject : "user:id:2" ,
Audience : jwt . Audience { "http://localhost:3000" } ,
ID : "1234567890" ,
Expiry : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 3 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
IssuedAt : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 2 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
} ,
ClientID : "grafana" ,
Scopes : [ ] string { "profile" , "groups" } ,
} ,
orgID : 1 ,
want : nil ,
wantErr : true ,
wantErr : errJWTInvalid . Errorf ( "Failed to parse sub: %s" , "invalid subject format" ) ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
env := setupTestCtx ( t , nil )
env := setupTestCtx ( nil )
if tc . initTestEnv != nil {
tc . initTestEnv ( env )
}
validHTTPReq := & http . Request {
Header : map [ string ] [ ] string {
"Authorizatio n" : { generateToken ( tc . payload , pk , jose . RS256 ) } ,
"X-Access-Token" : { generateToken ( tc . payload , pk , jose . RS256 , "at+jwt" ) } ,
} ,
}
mockTimeNow ( time . Date ( 2023 , 5 , 2 , 0 , 1 , 0 , 0 , time . UTC ) )
env . s . verifier = & mockVerifier { Claims : [ ] ExtendedJWTClaims { tc . payload } }
if tc . idPayload != nil {
env . s . verifier = & mockVerifier { Claims : [ ] ExtendedJWTClaims { tc . payload , * tc . idPayload } }
validHTTPReq . Header . Add ( extJWTAuthorizationHeaderName , generateToken ( * tc . idPayload , pk , jose . RS256 , "jwt" ) )
}
id , err := env . s . Authenticate ( context . Background ( ) , & authn . Request {
OrgID : tc . orgID ,
HTTPRequest : validHTTPReq ,
Resp : nil ,
} )
if tc . wantErr {
require . Error ( t , err )
if tc . wantErr != nil {
require . ErrorIs ( t , err , tc . wantErr )
} else {
require . NoError ( t , err )
assert . EqualValues ( t , tc . want , id , fmt . Sprintf ( "%+v" , id ) )
@ -304,6 +274,7 @@ func TestVerifyRFC9068TokenFailureScenarios(t *testing.T) {
name string
payload ExtendedJWTClaims
alg jose . SignatureAlgorithm
typ string
}
testCases := [ ] testCase {
@ -311,14 +282,13 @@ func TestVerifyRFC9068TokenFailureScenarios(t *testing.T) {
name : "missing iss" ,
payload : ExtendedJWTClaims {
Claims : jwt . Claims {
Subject : "user:id:2 " ,
Subject : "access-policy:this-uid " ,
Audience : jwt . Audience { "http://localhost:3000" } ,
ID : "1234567890" ,
Expiry : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 3 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
IssuedAt : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 2 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
} ,
ClientID : "grafana" ,
Scopes : [ ] string { "profile" , "groups" } ,
Scopes : [ ] string { "profile" , "groups" } ,
} ,
} ,
{
@ -326,13 +296,12 @@ func TestVerifyRFC9068TokenFailureScenarios(t *testing.T) {
payload : ExtendedJWTClaims {
Claims : jwt . Claims {
Issuer : "http://localhost:3000" ,
Subject : "user:id:2 " ,
Subject : "access-policy:this-uid " ,
Audience : jwt . Audience { "http://localhost:3000" } ,
ID : "1234567890" ,
IssuedAt : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 2 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
} ,
ClientID : "grafana" ,
Scopes : [ ] string { "profile" , "groups" } ,
Scopes : [ ] string { "profile" , "groups" } ,
} ,
} ,
{
@ -340,14 +309,13 @@ func TestVerifyRFC9068TokenFailureScenarios(t *testing.T) {
payload : ExtendedJWTClaims {
Claims : jwt . Claims {
Issuer : "http://localhost:3000" ,
Subject : "user:id:2 " ,
Subject : "access-policy:this-uid " ,
Audience : jwt . Audience { "http://localhost:3000" } ,
ID : "1234567890" ,
Expiry : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 2 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
IssuedAt : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 2 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
} ,
ClientID : "grafana" ,
Scopes : [ ] string { "profile" , "groups" } ,
Scopes : [ ] string { "profile" , "groups" } ,
} ,
} ,
{
@ -355,13 +323,12 @@ func TestVerifyRFC9068TokenFailureScenarios(t *testing.T) {
payload : ExtendedJWTClaims {
Claims : jwt . Claims {
Issuer : "http://localhost:3000" ,
Subject : "user:id:2 " ,
Subject : "access-policy:this-uid " ,
ID : "1234567890" ,
Expiry : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 3 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
IssuedAt : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 2 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
} ,
ClientID : "grafana" ,
Scopes : [ ] string { "profile" , "groups" } ,
Scopes : [ ] string { "profile" , "groups" } ,
} ,
} ,
{
@ -369,36 +336,35 @@ func TestVerifyRFC9068TokenFailureScenarios(t *testing.T) {
payload : ExtendedJWTClaims {
Claims : jwt . Claims {
Issuer : "http://localhost:3000" ,
Subject : "user:id:2 " ,
Subject : "access-policy:this-uid " ,
Audience : jwt . Audience { "http://some-other-host:3000" } ,
ID : "1234567890" ,
Expiry : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 3 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
IssuedAt : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 2 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
} ,
ClientID : "grafana" ,
Scopes : [ ] string { "profile" , "groups" } ,
Scopes : [ ] string { "profile" , "groups" } ,
} ,
} ,
{
name : "missing sub " ,
name : "wrong typ " ,
payload : ExtendedJWTClaims {
Claims : jwt . Claims {
Issuer : "http://localhost:3000" ,
Audience : jwt . Audience { "http://localhost:3000" } ,
Subject : "access-policy:this-uid" ,
Audience : jwt . Audience { "http://some-other-host:3000" } ,
ID : "1234567890" ,
Expiry : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 3 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
IssuedAt : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 2 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
} ,
ClientID : "grafana" ,
Scopes : [ ] string { "profile" , "groups" } ,
Scopes : [ ] string { "profile" , "groups" } ,
} ,
typ : "jwt" ,
} ,
{
name : "missing client_id " ,
name : "missing sub " ,
payload : ExtendedJWTClaims {
Claims : jwt . Claims {
Issuer : "http://localhost:3000" ,
Subject : "user:id:2" ,
Audience : jwt . Audience { "http://localhost:3000" } ,
ID : "1234567890" ,
Expiry : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 3 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
@ -412,13 +378,12 @@ func TestVerifyRFC9068TokenFailureScenarios(t *testing.T) {
payload : ExtendedJWTClaims {
Claims : jwt . Claims {
Issuer : "http://localhost:3000" ,
Subject : "user:id:2 " ,
Subject : "access-policy:this-uid " ,
Audience : jwt . Audience { "http://localhost:3000" } ,
ID : "1234567890" ,
Expiry : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 3 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
} ,
ClientID : "grafana" ,
Scopes : [ ] string { "profile" , "groups" } ,
Scopes : [ ] string { "profile" , "groups" } ,
} ,
} ,
{
@ -426,28 +391,13 @@ func TestVerifyRFC9068TokenFailureScenarios(t *testing.T) {
payload : ExtendedJWTClaims {
Claims : jwt . Claims {
Issuer : "http://localhost:3000" ,
Subject : "user:id:2 " ,
Subject : "access-policy:this-uid " ,
Audience : jwt . Audience { "http://localhost:3000" } ,
ID : "1234567890" ,
Expiry : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 3 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
IssuedAt : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 2 , 0 , 2 , 0 , 0 , time . UTC ) ) ,
} ,
ClientID : "grafana" ,
Scopes : [ ] string { "profile" , "groups" } ,
} ,
} ,
{
name : "missing jti" ,
payload : ExtendedJWTClaims {
Claims : jwt . Claims {
Issuer : "http://localhost:3000" ,
Subject : "user:id:2" ,
Audience : jwt . Audience { "http://localhost:3000" } ,
Expiry : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 3 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
IssuedAt : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 2 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
} ,
ClientID : "grafana" ,
Scopes : [ ] string { "profile" , "groups" } ,
Scopes : [ ] string { "profile" , "groups" } ,
} ,
} ,
{
@ -455,40 +405,40 @@ func TestVerifyRFC9068TokenFailureScenarios(t *testing.T) {
payload : ExtendedJWTClaims {
Claims : jwt . Claims {
Issuer : "http://localhost:3000" ,
Subject : "user:id:2 " ,
Subject : "access-policy:this-uid " ,
Audience : jwt . Audience { "http://localhost:3000" } ,
ID : "1234567890" ,
Expiry : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 3 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
IssuedAt : jwt . NewNumericDate ( time . Date ( 2023 , 5 , 2 , 0 , 0 , 0 , 0 , time . UTC ) ) ,
} ,
ClientID : "grafana" ,
Scopes : [ ] string { "profile" , "groups" } ,
Scopes : [ ] string { "profile" , "groups" } ,
} ,
alg : jose . RS384 ,
} ,
}
env := setupTestCtx ( t , nil )
mockTimeNow ( time . Date ( 2023 , 5 , 2 , 0 , 1 , 0 , 0 , time . UTC ) )
env := setupTestCtx ( nil )
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
if tc . alg == "" {
tc . alg = jose . RS256
}
tokenToTest := generateToken ( tc . payload , pk , tc . alg )
_ , err := env . s . verifyRFC9068Token ( context . Background ( ) , tokenToTest )
tokenToTest := generateToken ( tc . payload , pk , tc . alg , "at+jwt" )
_ , err := env . s . verifyRFC9068Token ( context . Background ( ) , tokenToTest , rfc9068ShortMediaType )
require . Error ( t , err )
} )
}
}
func setupTestCtx ( t * testing . T , cfg * setting . Cfg ) * testEnv {
func setupTestCtx ( cfg * setting . Cfg ) * testEnv {
if cfg == nil {
cfg = & setting . Cfg {
ExtendedJWTAuthEnabled : true ,
ExtendedJWTExpectIssuer : "http://localhost:3000" ,
ExtendedJWTExpectAudience : "http://localhost:3000" ,
ExtJWTAuth : setting . ExtJWTSettings {
Enabled : true ,
ExpectIssuer : "http://localhost:3000" ,
ExpectAudience : "http://localhost:3000" ,
} ,
}
}
@ -512,18 +462,13 @@ type testEnv struct {
s * ExtendedJWT
}
func generateToken ( payload ExtendedJWTClaims , signingKey any , alg jose . SignatureAlgorithm ) string {
func generateToken ( payload ExtendedJWTClaims , signingKey any , alg jose . SignatureAlgorithm , typ string ) string {
signer , _ := jose . NewSigner ( jose . SigningKey { Algorithm : alg , Key : signingKey } , & jose . SignerOptions {
ExtraHeaders : map [ jose . HeaderKey ] any {
jose . HeaderType : "at+jwt" ,
jose . HeaderType : typ ,
"kid" : "default" ,
} } )
result , _ := jwt . Signed ( signer ) . Claims ( payload ) . CompactSerialize ( )
return result
}
func mockTimeNow ( timeSeed time . Time ) {
timeNow = func ( ) time . Time {
return timeSeed
}
}