mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
JWT Authentication: Add support for specifying groups in auth.jwt for teamsync (#82175)
* merge JSON search logic * document public methods * improve test coverage * use separate JWT setting struct * correct use of cfg.JWTAuth * add group tests * fix DynMap typing * add settings to default ini * add groups option to devenv path * fix test * lint * revert jwt-proxy change * remove redundant check * fix parallel test
This commit is contained in:
@@ -131,7 +131,7 @@ func ProvideService(
|
||||
}
|
||||
}
|
||||
|
||||
if s.cfg.JWTAuthEnabled {
|
||||
if s.cfg.JWTAuth.Enabled {
|
||||
s.RegisterClient(clients.ProvideJWT(jwtService, cfg))
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ func (s *Service) getUsageStats(ctx context.Context) (map[string]any, error) {
|
||||
authTypes["ldap"] = s.cfg.LDAPAuthEnabled
|
||||
authTypes["auth_proxy"] = s.cfg.AuthProxyEnabled
|
||||
authTypes["anonymous"] = s.cfg.AnonymousEnabled
|
||||
authTypes["jwt"] = s.cfg.JWTAuthEnabled
|
||||
authTypes["jwt"] = s.cfg.JWTAuth.Enabled
|
||||
authTypes["grafana_password"] = !s.cfg.DisableLogin
|
||||
authTypes["login_form"] = !s.cfg.DisableLoginForm
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ func TestService_getUsageStats(t *testing.T) {
|
||||
svc.cfg.DisableLogin = false
|
||||
svc.cfg.BasicAuthEnabled = true
|
||||
svc.cfg.AuthProxyEnabled = true
|
||||
svc.cfg.JWTAuthEnabled = true
|
||||
svc.cfg.JWTAuth.Enabled = true
|
||||
svc.cfg.LDAPAuthEnabled = true
|
||||
svc.cfg.EditorsCanAdmin = true
|
||||
svc.cfg.ViewersCanEdit = true
|
||||
|
||||
@@ -2,13 +2,9 @@ package clients
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/jmespath/go-jmespath"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/auth"
|
||||
authJWT "github.com/grafana/grafana/pkg/services/auth/jwt"
|
||||
@@ -16,6 +12,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/login"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
"github.com/grafana/grafana/pkg/util/errutil"
|
||||
)
|
||||
|
||||
@@ -73,15 +70,16 @@ func (s *JWT) Authenticate(ctx context.Context, r *authn.Request) (*authn.Identi
|
||||
SyncUser: true,
|
||||
FetchSyncedUser: true,
|
||||
SyncPermissions: true,
|
||||
SyncOrgRoles: !s.cfg.JWTAuthSkipOrgRoleSync,
|
||||
AllowSignUp: s.cfg.JWTAuthAutoSignUp,
|
||||
SyncOrgRoles: !s.cfg.JWTAuth.SkipOrgRoleSync,
|
||||
AllowSignUp: s.cfg.JWTAuth.AutoSignUp,
|
||||
SyncTeams: s.cfg.JWTAuth.GroupsAttributePath != "",
|
||||
}}
|
||||
|
||||
if key := s.cfg.JWTAuthUsernameClaim; key != "" {
|
||||
if key := s.cfg.JWTAuth.UsernameClaim; key != "" {
|
||||
id.Login, _ = claims[key].(string)
|
||||
id.ClientParams.LookUpParams.Login = &id.Login
|
||||
}
|
||||
if key := s.cfg.JWTAuthEmailClaim; key != "" {
|
||||
if key := s.cfg.JWTAuth.EmailClaim; key != "" {
|
||||
id.Email, _ = claims[key].(string)
|
||||
id.ClientParams.LookUpParams.Email = &id.Email
|
||||
}
|
||||
@@ -91,16 +89,16 @@ func (s *JWT) Authenticate(ctx context.Context, r *authn.Request) (*authn.Identi
|
||||
}
|
||||
|
||||
orgRoles, isGrafanaAdmin, err := getRoles(s.cfg, func() (org.RoleType, *bool, error) {
|
||||
if s.cfg.JWTAuthSkipOrgRoleSync {
|
||||
if s.cfg.JWTAuth.SkipOrgRoleSync {
|
||||
return "", nil, nil
|
||||
}
|
||||
|
||||
role, grafanaAdmin := s.extractRoleAndAdmin(claims)
|
||||
if s.cfg.JWTAuthRoleAttributeStrict && !role.IsValid() {
|
||||
if s.cfg.JWTAuth.RoleAttributeStrict && !role.IsValid() {
|
||||
return "", nil, errJWTInvalidRole.Errorf("invalid role claim in JWT: %s", role)
|
||||
}
|
||||
|
||||
if !s.cfg.JWTAuthAllowAssignGrafanaAdmin {
|
||||
if !s.cfg.JWTAuth.AllowAssignGrafanaAdmin {
|
||||
return role, nil, nil
|
||||
}
|
||||
|
||||
@@ -114,6 +112,11 @@ func (s *JWT) Authenticate(ctx context.Context, r *authn.Request) (*authn.Identi
|
||||
id.OrgRoles = orgRoles
|
||||
id.IsGrafanaAdmin = isGrafanaAdmin
|
||||
|
||||
id.Groups, err = s.extractGroups(claims)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if id.Login == "" && id.Email == "" {
|
||||
s.log.FromContext(ctx).Debug("Failed to get an authentication claim from JWT",
|
||||
"login", id.Login, "email", id.Email)
|
||||
@@ -126,7 +129,7 @@ func (s *JWT) Authenticate(ctx context.Context, r *authn.Request) (*authn.Identi
|
||||
// remove sensitive query param
|
||||
// avoid JWT URL login passing auth_token in URL
|
||||
func (s *JWT) stripSensitiveParam(httpRequest *http.Request) {
|
||||
if s.cfg.JWTAuthURLLogin {
|
||||
if s.cfg.JWTAuth.URLLogin {
|
||||
params := httpRequest.URL.Query()
|
||||
if params.Has(authQueryParamName) {
|
||||
params.Del(authQueryParamName)
|
||||
@@ -137,8 +140,8 @@ func (s *JWT) stripSensitiveParam(httpRequest *http.Request) {
|
||||
|
||||
// retrieveToken retrieves the JWT token from the request.
|
||||
func (s *JWT) retrieveToken(httpRequest *http.Request) string {
|
||||
jwtToken := httpRequest.Header.Get(s.cfg.JWTAuthHeaderName)
|
||||
if jwtToken == "" && s.cfg.JWTAuthURLLogin {
|
||||
jwtToken := httpRequest.Header.Get(s.cfg.JWTAuth.HeaderName)
|
||||
if jwtToken == "" && s.cfg.JWTAuth.URLLogin {
|
||||
jwtToken = httpRequest.URL.Query().Get("auth_token")
|
||||
}
|
||||
// Strip the 'Bearer' prefix if it exists.
|
||||
@@ -146,7 +149,7 @@ func (s *JWT) retrieveToken(httpRequest *http.Request) string {
|
||||
}
|
||||
|
||||
func (s *JWT) Test(ctx context.Context, r *authn.Request) bool {
|
||||
if !s.cfg.JWTAuthEnabled || s.cfg.JWTAuthHeaderName == "" {
|
||||
if !s.cfg.JWTAuth.Enabled || s.cfg.JWTAuth.HeaderName == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -171,11 +174,11 @@ func (s *JWT) Priority() uint {
|
||||
const roleGrafanaAdmin = "GrafanaAdmin"
|
||||
|
||||
func (s *JWT) extractRoleAndAdmin(claims map[string]any) (org.RoleType, bool) {
|
||||
if s.cfg.JWTAuthRoleAttributePath == "" {
|
||||
if s.cfg.JWTAuth.RoleAttributePath == "" {
|
||||
return "", false
|
||||
}
|
||||
|
||||
role, err := searchClaimsForStringAttr(s.cfg.JWTAuthRoleAttributePath, claims)
|
||||
role, err := util.SearchJSONForStringAttr(s.cfg.JWTAuth.RoleAttributePath, claims)
|
||||
if err != nil || role == "" {
|
||||
return "", false
|
||||
}
|
||||
@@ -186,33 +189,10 @@ func (s *JWT) extractRoleAndAdmin(claims map[string]any) (org.RoleType, bool) {
|
||||
return org.RoleType(role), false
|
||||
}
|
||||
|
||||
func searchClaimsForStringAttr(attributePath string, claims map[string]any) (string, error) {
|
||||
val, err := searchClaimsForAttr(attributePath, claims)
|
||||
if err != nil {
|
||||
return "", err
|
||||
func (s *JWT) extractGroups(claims map[string]any) ([]string, error) {
|
||||
if s.cfg.JWTAuth.GroupsAttributePath == "" {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
strVal, ok := val.(string)
|
||||
if ok {
|
||||
return strVal, nil
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func searchClaimsForAttr(attributePath string, claims map[string]any) (any, error) {
|
||||
if attributePath == "" {
|
||||
return "", errors.New("no attribute path specified")
|
||||
}
|
||||
|
||||
if len(claims) == 0 {
|
||||
return "", errors.New("empty claims provided")
|
||||
}
|
||||
|
||||
val, err := jmespath.Search(attributePath, claims)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to search claims with provided path: %q: %w", attributePath, err)
|
||||
}
|
||||
|
||||
return val, nil
|
||||
return util.SearchJSONForStringSliceAttr(s.cfg.JWTAuth.GroupsAttributePath, claims)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
"github.com/grafana/grafana/pkg/services/login"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
|
||||
func stringPtr(s string) *string {
|
||||
@@ -22,72 +23,153 @@ func stringPtr(s string) *string {
|
||||
}
|
||||
|
||||
func TestAuthenticateJWT(t *testing.T) {
|
||||
jwtService := &jwt.FakeJWTService{
|
||||
VerifyProvider: func(context.Context, string) (jwt.JWTClaims, error) {
|
||||
return jwt.JWTClaims{
|
||||
"sub": "1234567890",
|
||||
"email": "eai.doe@cor.po",
|
||||
"preferred_username": "eai-doe",
|
||||
"name": "Eai Doe",
|
||||
"roles": "Admin",
|
||||
}, nil
|
||||
},
|
||||
}
|
||||
t.Parallel()
|
||||
|
||||
jwtHeaderName := "X-Forwarded-User"
|
||||
wantID := &authn.Identity{
|
||||
OrgID: 0,
|
||||
OrgName: "",
|
||||
OrgRoles: map[int64]roletype.RoleType{1: roletype.RoleAdmin},
|
||||
ID: "",
|
||||
Login: "eai-doe",
|
||||
Name: "Eai Doe",
|
||||
Email: "eai.doe@cor.po",
|
||||
IsGrafanaAdmin: boolPtr(false),
|
||||
AuthenticatedBy: login.JWTModule,
|
||||
AuthID: "1234567890",
|
||||
IsDisabled: false,
|
||||
HelpFlags1: 0,
|
||||
ClientParams: authn.ClientParams{
|
||||
SyncUser: true,
|
||||
AllowSignUp: true,
|
||||
FetchSyncedUser: true,
|
||||
SyncOrgRoles: true,
|
||||
SyncPermissions: true,
|
||||
LookUpParams: login.UserLookupParams{
|
||||
UserID: nil,
|
||||
Email: stringPtr("eai.doe@cor.po"),
|
||||
Login: stringPtr("eai-doe"),
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
wantID *authn.Identity
|
||||
verifyProvider func(context.Context, string) (jwt.JWTClaims, error)
|
||||
cfg *setting.Cfg
|
||||
}{
|
||||
{
|
||||
name: "Valid Use case with group path",
|
||||
wantID: &authn.Identity{
|
||||
OrgID: 0,
|
||||
OrgName: "",
|
||||
OrgRoles: map[int64]roletype.RoleType{1: roletype.RoleAdmin},
|
||||
Groups: []string{"foo", "bar"},
|
||||
ID: "",
|
||||
Login: "eai-doe",
|
||||
Name: "Eai Doe",
|
||||
Email: "eai.doe@cor.po",
|
||||
IsGrafanaAdmin: boolPtr(false),
|
||||
AuthenticatedBy: login.JWTModule,
|
||||
AuthID: "1234567890",
|
||||
IsDisabled: false,
|
||||
HelpFlags1: 0,
|
||||
ClientParams: authn.ClientParams{
|
||||
SyncUser: true,
|
||||
AllowSignUp: true,
|
||||
FetchSyncedUser: true,
|
||||
SyncOrgRoles: true,
|
||||
SyncPermissions: true,
|
||||
SyncTeams: true,
|
||||
LookUpParams: login.UserLookupParams{
|
||||
UserID: nil,
|
||||
Email: stringPtr("eai.doe@cor.po"),
|
||||
Login: stringPtr("eai-doe"),
|
||||
},
|
||||
},
|
||||
},
|
||||
verifyProvider: func(context.Context, string) (jwt.JWTClaims, error) {
|
||||
return jwt.JWTClaims{
|
||||
"sub": "1234567890",
|
||||
"email": "eai.doe@cor.po",
|
||||
"preferred_username": "eai-doe",
|
||||
"name": "Eai Doe",
|
||||
"roles": "Admin",
|
||||
"groups": []string{"foo", "bar"},
|
||||
}, nil
|
||||
},
|
||||
cfg: &setting.Cfg{
|
||||
JWTAuth: setting.AuthJWTSettings{
|
||||
Enabled: true,
|
||||
HeaderName: jwtHeaderName,
|
||||
EmailClaim: "email",
|
||||
UsernameClaim: "preferred_username",
|
||||
AutoSignUp: true,
|
||||
AllowAssignGrafanaAdmin: true,
|
||||
RoleAttributeStrict: true,
|
||||
RoleAttributePath: "roles",
|
||||
GroupsAttributePath: "groups[]",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Valid Use case without group path",
|
||||
wantID: &authn.Identity{
|
||||
OrgID: 0,
|
||||
OrgName: "",
|
||||
OrgRoles: map[int64]roletype.RoleType{1: roletype.RoleAdmin},
|
||||
ID: "",
|
||||
Login: "eai-doe",
|
||||
Groups: []string{},
|
||||
Name: "Eai Doe",
|
||||
Email: "eai.doe@cor.po",
|
||||
IsGrafanaAdmin: boolPtr(false),
|
||||
AuthenticatedBy: login.JWTModule,
|
||||
AuthID: "1234567890",
|
||||
IsDisabled: false,
|
||||
HelpFlags1: 0,
|
||||
ClientParams: authn.ClientParams{
|
||||
SyncUser: true,
|
||||
AllowSignUp: true,
|
||||
FetchSyncedUser: true,
|
||||
SyncOrgRoles: true,
|
||||
SyncPermissions: true,
|
||||
SyncTeams: false,
|
||||
LookUpParams: login.UserLookupParams{
|
||||
UserID: nil,
|
||||
Email: stringPtr("eai.doe@cor.po"),
|
||||
Login: stringPtr("eai-doe"),
|
||||
},
|
||||
},
|
||||
},
|
||||
verifyProvider: func(context.Context, string) (jwt.JWTClaims, error) {
|
||||
return jwt.JWTClaims{
|
||||
"sub": "1234567890",
|
||||
"email": "eai.doe@cor.po",
|
||||
"preferred_username": "eai-doe",
|
||||
"name": "Eai Doe",
|
||||
"roles": "Admin",
|
||||
"groups": []string{"foo", "bar"},
|
||||
}, nil
|
||||
},
|
||||
cfg: &setting.Cfg{
|
||||
JWTAuth: setting.AuthJWTSettings{
|
||||
Enabled: true,
|
||||
HeaderName: jwtHeaderName,
|
||||
EmailClaim: "email",
|
||||
UsernameClaim: "preferred_username",
|
||||
AutoSignUp: true,
|
||||
AllowAssignGrafanaAdmin: true,
|
||||
RoleAttributeStrict: true,
|
||||
RoleAttributePath: "roles",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
cfg := &setting.Cfg{
|
||||
JWTAuthEnabled: true,
|
||||
JWTAuthHeaderName: jwtHeaderName,
|
||||
JWTAuthEmailClaim: "email",
|
||||
JWTAuthUsernameClaim: "preferred_username",
|
||||
JWTAuthAutoSignUp: true,
|
||||
JWTAuthAllowAssignGrafanaAdmin: true,
|
||||
JWTAuthRoleAttributeStrict: true,
|
||||
JWTAuthRoleAttributePath: "roles",
|
||||
}
|
||||
jwtClient := ProvideJWT(jwtService, cfg)
|
||||
validHTTPReq := &http.Request{
|
||||
Header: map[string][]string{
|
||||
jwtHeaderName: {"sample-token"}},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
jwtService := &jwt.FakeJWTService{
|
||||
VerifyProvider: tc.verifyProvider,
|
||||
}
|
||||
|
||||
id, err := jwtClient.Authenticate(context.Background(), &authn.Request{
|
||||
OrgID: 1,
|
||||
HTTPRequest: validHTTPReq,
|
||||
Resp: nil,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
jwtClient := ProvideJWT(jwtService, tc.cfg)
|
||||
validHTTPReq := &http.Request{
|
||||
Header: map[string][]string{
|
||||
jwtHeaderName: {"sample-token"}},
|
||||
}
|
||||
|
||||
assert.EqualValues(t, wantID, id, fmt.Sprintf("%+v", id))
|
||||
id, err := jwtClient.Authenticate(context.Background(), &authn.Request{
|
||||
OrgID: 1,
|
||||
HTTPRequest: validHTTPReq,
|
||||
Resp: nil,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.EqualValues(t, tc.wantID, id, fmt.Sprintf("%+v", id))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestJWTClaimConfig(t *testing.T) {
|
||||
t.Parallel()
|
||||
jwtService := &jwt.FakeJWTService{
|
||||
VerifyProvider: func(context.Context, string) (jwt.JWTClaims, error) {
|
||||
return jwt.JWTClaims{
|
||||
@@ -102,30 +184,19 @@ func TestJWTClaimConfig(t *testing.T) {
|
||||
|
||||
jwtHeaderName := "X-Forwarded-User"
|
||||
|
||||
cfg := &setting.Cfg{
|
||||
JWTAuthEnabled: true,
|
||||
JWTAuthHeaderName: jwtHeaderName,
|
||||
JWTAuthAutoSignUp: true,
|
||||
JWTAuthAllowAssignGrafanaAdmin: true,
|
||||
JWTAuthRoleAttributeStrict: true,
|
||||
JWTAuthRoleAttributePath: "roles",
|
||||
}
|
||||
|
||||
// #nosec G101 -- This is a dummy/test token
|
||||
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.XbPfbIHMI6arZ3Y922BhjWgQzWXcXNrz0ogtVhfEd2o"
|
||||
|
||||
type Dictionary map[string]any
|
||||
|
||||
type testCase struct {
|
||||
desc string
|
||||
claimsConfigurations []Dictionary
|
||||
claimsConfigurations []util.DynMap
|
||||
valid bool
|
||||
}
|
||||
|
||||
testCases := []testCase{
|
||||
{
|
||||
desc: "JWT configuration with email and username claims",
|
||||
claimsConfigurations: []Dictionary{
|
||||
claimsConfigurations: []util.DynMap{
|
||||
{
|
||||
"JWTAuthEmailClaim": true,
|
||||
"JWTAuthUsernameClaim": true,
|
||||
@@ -135,7 +206,7 @@ func TestJWTClaimConfig(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "JWT configuration with email claim",
|
||||
claimsConfigurations: []Dictionary{
|
||||
claimsConfigurations: []util.DynMap{
|
||||
{
|
||||
"JWTAuthEmailClaim": true,
|
||||
"JWTAuthUsernameClaim": false,
|
||||
@@ -145,7 +216,7 @@ func TestJWTClaimConfig(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "JWT configuration with username claim",
|
||||
claimsConfigurations: []Dictionary{
|
||||
claimsConfigurations: []util.DynMap{
|
||||
{
|
||||
"JWTAuthEmailClaim": false,
|
||||
"JWTAuthUsernameClaim": true,
|
||||
@@ -155,7 +226,7 @@ func TestJWTClaimConfig(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "JWT configuration without email and username claims",
|
||||
claimsConfigurations: []Dictionary{
|
||||
claimsConfigurations: []util.DynMap{
|
||||
{
|
||||
"JWTAuthEmailClaim": false,
|
||||
"JWTAuthUsernameClaim": false,
|
||||
@@ -166,39 +237,53 @@ func TestJWTClaimConfig(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
cfg := &setting.Cfg{
|
||||
JWTAuth: setting.AuthJWTSettings{
|
||||
Enabled: true,
|
||||
HeaderName: jwtHeaderName,
|
||||
AutoSignUp: true,
|
||||
AllowAssignGrafanaAdmin: true,
|
||||
RoleAttributeStrict: true,
|
||||
RoleAttributePath: "roles",
|
||||
},
|
||||
}
|
||||
for _, claims := range tc.claimsConfigurations {
|
||||
cfg.JWTAuthEmailClaim = ""
|
||||
cfg.JWTAuthUsernameClaim = ""
|
||||
cfg.JWTAuth.EmailClaim = ""
|
||||
cfg.JWTAuth.UsernameClaim = ""
|
||||
|
||||
if claims["JWTAuthEmailClaim"] == true {
|
||||
cfg.JWTAuthEmailClaim = "email"
|
||||
cfg.JWTAuth.EmailClaim = "email"
|
||||
}
|
||||
if claims["JWTAuthUsernameClaim"] == true {
|
||||
cfg.JWTAuthUsernameClaim = "preferred_username"
|
||||
cfg.JWTAuth.UsernameClaim = "preferred_username"
|
||||
}
|
||||
}
|
||||
|
||||
httpReq := &http.Request{
|
||||
URL: &url.URL{RawQuery: "auth_token=" + token},
|
||||
Header: map[string][]string{
|
||||
jwtHeaderName: {token}},
|
||||
}
|
||||
jwtClient := ProvideJWT(jwtService, cfg)
|
||||
_, err := jwtClient.Authenticate(context.Background(), &authn.Request{
|
||||
OrgID: 1,
|
||||
HTTPRequest: httpReq,
|
||||
Resp: nil,
|
||||
})
|
||||
if tc.valid {
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
require.Error(t, err)
|
||||
}
|
||||
})
|
||||
httpReq := &http.Request{
|
||||
URL: &url.URL{RawQuery: "auth_token=" + token},
|
||||
Header: map[string][]string{
|
||||
jwtHeaderName: {token}},
|
||||
}
|
||||
jwtClient := ProvideJWT(jwtService, cfg)
|
||||
_, err := jwtClient.Authenticate(context.Background(), &authn.Request{
|
||||
OrgID: 1,
|
||||
HTTPRequest: httpReq,
|
||||
Resp: nil,
|
||||
})
|
||||
if tc.valid {
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
require.Error(t, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestJWTTest(t *testing.T) {
|
||||
t.Parallel()
|
||||
jwtService := &jwt.FakeJWTService{}
|
||||
jwtHeaderName := "X-Forwarded-User"
|
||||
// #nosec G101 -- This is dummy/test token
|
||||
@@ -280,14 +365,18 @@ func TestJWTTest(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
cfg := &setting.Cfg{
|
||||
JWTAuthEnabled: true,
|
||||
JWTAuthURLLogin: tc.urlLogin,
|
||||
JWTAuthHeaderName: tc.cfgHeaderName,
|
||||
JWTAuthAutoSignUp: true,
|
||||
JWTAuthAllowAssignGrafanaAdmin: true,
|
||||
JWTAuthRoleAttributeStrict: true,
|
||||
JWTAuth: setting.AuthJWTSettings{
|
||||
Enabled: true,
|
||||
URLLogin: tc.urlLogin,
|
||||
HeaderName: tc.cfgHeaderName,
|
||||
AutoSignUp: true,
|
||||
AllowAssignGrafanaAdmin: true,
|
||||
RoleAttributeStrict: true,
|
||||
},
|
||||
}
|
||||
jwtClient := ProvideJWT(jwtService, cfg)
|
||||
httpReq := &http.Request{
|
||||
@@ -308,6 +397,7 @@ func TestJWTTest(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestJWTStripParam(t *testing.T) {
|
||||
t.Parallel()
|
||||
jwtService := &jwt.FakeJWTService{
|
||||
VerifyProvider: func(context.Context, string) (jwt.JWTClaims, error) {
|
||||
return jwt.JWTClaims{
|
||||
@@ -323,15 +413,17 @@ func TestJWTStripParam(t *testing.T) {
|
||||
jwtHeaderName := "X-Forwarded-User"
|
||||
|
||||
cfg := &setting.Cfg{
|
||||
JWTAuthEnabled: true,
|
||||
JWTAuthHeaderName: jwtHeaderName,
|
||||
JWTAuthAutoSignUp: true,
|
||||
JWTAuthAllowAssignGrafanaAdmin: true,
|
||||
JWTAuthURLLogin: true,
|
||||
JWTAuthRoleAttributeStrict: false,
|
||||
JWTAuthRoleAttributePath: "roles",
|
||||
JWTAuthEmailClaim: "email",
|
||||
JWTAuthUsernameClaim: "preferred_username",
|
||||
JWTAuth: setting.AuthJWTSettings{
|
||||
Enabled: true,
|
||||
HeaderName: jwtHeaderName,
|
||||
AutoSignUp: true,
|
||||
AllowAssignGrafanaAdmin: true,
|
||||
URLLogin: true,
|
||||
RoleAttributeStrict: false,
|
||||
RoleAttributePath: "roles",
|
||||
EmailClaim: "email",
|
||||
UsernameClaim: "preferred_username",
|
||||
},
|
||||
}
|
||||
|
||||
// #nosec G101 -- This is a dummy/test token
|
||||
|
||||
Reference in New Issue
Block a user