mirror of
https://github.com/grafana/grafana.git
synced 2024-11-21 16:38:03 -06:00
OAuth: Add optional strict parsing of role_attribute_path (#28021)
* OAuth: Add strict role mapping By default the user is assigned the role Viewer if role_attribute_path doesn't return a role, which is not always desirable. This commit adds a strict mode, which deny the user access if a role isn't returned. Fix #26626 * Update docs/sources/auth/generic-oauth.md Co-authored-by: Emil Tullstedt <emil.tullstedt@grafana.com> * Update docs/sources/auth/generic-oauth.md * Update .gitignore file with WAN * Removed WAN from .gitignore Co-authored-by: Emil Tullstedt <emil.tullstedt@grafana.com> Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> Co-authored-by: achatterjee-grafana <aparajita.chatterjee@grafana.com>
This commit is contained in:
parent
68f38aa49b
commit
4fc0d42470
@ -458,6 +458,7 @@ api_url = https://<tenant-id>.okta.com/oauth2/v1/userinfo
|
||||
allowed_domains =
|
||||
allowed_groups =
|
||||
role_attribute_path =
|
||||
role_attribute_strict = false
|
||||
|
||||
#################################### Generic OAuth #######################
|
||||
[auth.generic_oauth]
|
||||
@ -472,6 +473,7 @@ email_attribute_path =
|
||||
login_attribute_path =
|
||||
name_attribute_path =
|
||||
role_attribute_path =
|
||||
role_attribute_strict = false
|
||||
id_token_attribute_name =
|
||||
auth_url =
|
||||
token_url =
|
||||
|
@ -449,6 +449,7 @@
|
||||
;allowed_domains =
|
||||
;allowed_groups =
|
||||
;role_attribute_path =
|
||||
;role_attribute_strict = false
|
||||
|
||||
#################################### Generic OAuth ##########################
|
||||
[auth.generic_oauth]
|
||||
@ -470,6 +471,7 @@
|
||||
;team_ids =
|
||||
;allowed_organizations =
|
||||
;role_attribute_path =
|
||||
;role_attribute_strict = false
|
||||
;tls_skip_verify_insecure = false
|
||||
;tls_client_cert =
|
||||
;tls_client_key =
|
||||
|
@ -194,6 +194,8 @@ To ease configuration of a proper JMESPath expression, you can test/evaluate exp
|
||||
|
||||
### Role mapping
|
||||
|
||||
If the`role_attribute_path` property does not return a role, then the user is assigned the `Viewer` role by default. You can disable the role assignment by setting `role_attribute_strict = true`. It denies user access if no role or an invalid role is returned.
|
||||
|
||||
**Basic example:**
|
||||
|
||||
In the following example user will get `Editor` as role when authenticating. The value of the property `role` will be the resulting role if the role is a proper Grafana role, i.e. `Viewer`, `Editor` or `Admin`.
|
||||
|
@ -26,6 +26,7 @@ type SocialGenericOAuth struct {
|
||||
loginAttributePath string
|
||||
nameAttributePath string
|
||||
roleAttributePath string
|
||||
roleAttributeStrict bool
|
||||
idTokenAttributeName string
|
||||
teamIds []int
|
||||
}
|
||||
@ -166,6 +167,10 @@ func (s *SocialGenericOAuth) UserInfo(client *http.Client, token *oauth2.Token)
|
||||
userInfo.Login = userInfo.Email
|
||||
}
|
||||
|
||||
if s.roleAttributeStrict && !models.RoleType(userInfo.Role).IsValid() {
|
||||
return nil, errors.New("invalid role")
|
||||
}
|
||||
|
||||
if !s.IsTeamMember(client) {
|
||||
return nil, errors.New("user not a member of one of the required teams")
|
||||
}
|
||||
|
@ -14,9 +14,10 @@ import (
|
||||
|
||||
type SocialOkta struct {
|
||||
*SocialBase
|
||||
apiUrl string
|
||||
allowedGroups []string
|
||||
roleAttributePath string
|
||||
apiUrl string
|
||||
allowedGroups []string
|
||||
roleAttributePath string
|
||||
roleAttributeStrict bool
|
||||
}
|
||||
|
||||
type OktaUserInfoJson struct {
|
||||
@ -81,6 +82,9 @@ func (s *SocialOkta) UserInfo(client *http.Client, token *oauth2.Token) (*BasicU
|
||||
if err != nil {
|
||||
s.log.Error("Failed to extract role", "error", err)
|
||||
}
|
||||
if s.roleAttributeStrict && !models.RoleType(role).IsValid() {
|
||||
return nil, errors.New("invalid role")
|
||||
}
|
||||
|
||||
groups := s.GetGroups(&data)
|
||||
if !s.IsGroupMember(groups) {
|
||||
|
@ -86,24 +86,25 @@ func NewOAuthService() {
|
||||
for _, name := range allOauthes {
|
||||
sec := setting.Raw.Section("auth." + name)
|
||||
info := &setting.OAuthInfo{
|
||||
ClientId: sec.Key("client_id").String(),
|
||||
ClientSecret: sec.Key("client_secret").String(),
|
||||
Scopes: util.SplitString(sec.Key("scopes").String()),
|
||||
AuthUrl: sec.Key("auth_url").String(),
|
||||
TokenUrl: sec.Key("token_url").String(),
|
||||
ApiUrl: sec.Key("api_url").String(),
|
||||
Enabled: sec.Key("enabled").MustBool(),
|
||||
EmailAttributeName: sec.Key("email_attribute_name").String(),
|
||||
EmailAttributePath: sec.Key("email_attribute_path").String(),
|
||||
RoleAttributePath: sec.Key("role_attribute_path").String(),
|
||||
AllowedDomains: util.SplitString(sec.Key("allowed_domains").String()),
|
||||
HostedDomain: sec.Key("hosted_domain").String(),
|
||||
AllowSignup: sec.Key("allow_sign_up").MustBool(),
|
||||
Name: sec.Key("name").MustString(name),
|
||||
TlsClientCert: sec.Key("tls_client_cert").String(),
|
||||
TlsClientKey: sec.Key("tls_client_key").String(),
|
||||
TlsClientCa: sec.Key("tls_client_ca").String(),
|
||||
TlsSkipVerify: sec.Key("tls_skip_verify_insecure").MustBool(),
|
||||
ClientId: sec.Key("client_id").String(),
|
||||
ClientSecret: sec.Key("client_secret").String(),
|
||||
Scopes: util.SplitString(sec.Key("scopes").String()),
|
||||
AuthUrl: sec.Key("auth_url").String(),
|
||||
TokenUrl: sec.Key("token_url").String(),
|
||||
ApiUrl: sec.Key("api_url").String(),
|
||||
Enabled: sec.Key("enabled").MustBool(),
|
||||
EmailAttributeName: sec.Key("email_attribute_name").String(),
|
||||
EmailAttributePath: sec.Key("email_attribute_path").String(),
|
||||
RoleAttributePath: sec.Key("role_attribute_path").String(),
|
||||
RoleAttributeStrict: sec.Key("role_attribute_strict").MustBool(),
|
||||
AllowedDomains: util.SplitString(sec.Key("allowed_domains").String()),
|
||||
HostedDomain: sec.Key("hosted_domain").String(),
|
||||
AllowSignup: sec.Key("allow_sign_up").MustBool(),
|
||||
Name: sec.Key("name").MustString(name),
|
||||
TlsClientCert: sec.Key("tls_client_cert").String(),
|
||||
TlsClientKey: sec.Key("tls_client_key").String(),
|
||||
TlsClientCa: sec.Key("tls_client_ca").String(),
|
||||
TlsSkipVerify: sec.Key("tls_skip_verify_insecure").MustBool(),
|
||||
}
|
||||
|
||||
if !info.Enabled {
|
||||
@ -167,10 +168,11 @@ func NewOAuthService() {
|
||||
// Okta
|
||||
if name == "okta" {
|
||||
SocialMap["okta"] = &SocialOkta{
|
||||
SocialBase: newSocialBase(name, &config, info),
|
||||
apiUrl: info.ApiUrl,
|
||||
allowedGroups: util.SplitString(sec.Key("allowed_groups").String()),
|
||||
roleAttributePath: info.RoleAttributePath,
|
||||
SocialBase: newSocialBase(name, &config, info),
|
||||
apiUrl: info.ApiUrl,
|
||||
allowedGroups: util.SplitString(sec.Key("allowed_groups").String()),
|
||||
roleAttributePath: info.RoleAttributePath,
|
||||
roleAttributeStrict: info.RoleAttributeStrict,
|
||||
}
|
||||
}
|
||||
|
||||
@ -183,6 +185,7 @@ func NewOAuthService() {
|
||||
emailAttributePath: info.EmailAttributePath,
|
||||
nameAttributePath: sec.Key("name_attribute_path").String(),
|
||||
roleAttributePath: info.RoleAttributePath,
|
||||
roleAttributeStrict: info.RoleAttributeStrict,
|
||||
loginAttributePath: sec.Key("login_attribute_path").String(),
|
||||
idTokenAttributeName: sec.Key("id_token_attribute_name").String(),
|
||||
teamIds: sec.Key("team_ids").Ints(","),
|
||||
|
@ -8,6 +8,7 @@ type OAuthInfo struct {
|
||||
EmailAttributeName string
|
||||
EmailAttributePath string
|
||||
RoleAttributePath string
|
||||
RoleAttributeStrict bool
|
||||
AllowedDomains []string
|
||||
HostedDomain string
|
||||
ApiUrl string
|
||||
|
Loading…
Reference in New Issue
Block a user