mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Auth: Add support for escaping colon characters in org_mapping (#89951)
* Split org_mapping correctly if it contains multiple colons * Improve tests * Use backslash as an escape character for colons * Cleanup, address feedback * Change test to use double quotes as an example
This commit is contained in:
parent
7a78ad3893
commit
4f06568f8a
@ -3,6 +3,7 @@ package connectors
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@ -11,7 +12,12 @@ import (
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
const mapperMatchAllOrgID = -1
|
||||
const (
|
||||
mapperMatchAllOrgID = -1
|
||||
escapeStr = `\`
|
||||
)
|
||||
|
||||
var separatorRegexp = regexp.MustCompile(":")
|
||||
|
||||
// OrgRoleMapper maps external orgs/groups to Grafana orgs and basic roles.
|
||||
type OrgRoleMapper struct {
|
||||
@ -132,7 +138,7 @@ func (m *OrgRoleMapper) ParseOrgMappingSettings(ctx context.Context, mappings []
|
||||
res := map[string]map[int64]org.RoleType{}
|
||||
|
||||
for _, v := range mappings {
|
||||
kv := strings.Split(v, ":")
|
||||
kv := splitOrgMapping(v)
|
||||
if !isValidOrgMappingFormat(kv) {
|
||||
m.logger.Error("Skipping org mapping due to invalid format.", "mapping", fmt.Sprintf("%v", v))
|
||||
if roleStrict {
|
||||
@ -203,6 +209,29 @@ func (m *OrgRoleMapper) getAllOrgs() (map[int64]bool, error) {
|
||||
return allOrgIDs, nil
|
||||
}
|
||||
|
||||
func splitOrgMapping(mapping string) []string {
|
||||
result := make([]string, 0, 3)
|
||||
matches := separatorRegexp.FindAllStringIndex(mapping, -1)
|
||||
from := 0
|
||||
|
||||
for _, match := range matches {
|
||||
// match[0] is the start, match[1] is the end of the match
|
||||
start, end := match[0], match[1]
|
||||
// Check if the match is not preceded by two backslashes
|
||||
if start == 0 || mapping[start-1:start] != escapeStr {
|
||||
result = append(result, strings.ReplaceAll(mapping[from:end-1], escapeStr, ""))
|
||||
from = end
|
||||
}
|
||||
}
|
||||
|
||||
result = append(result, mapping[from:])
|
||||
if len(result) > 3 {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func getRoleForInternalOrgMapping(kv []string) org.RoleType {
|
||||
if len(kv) > 2 && org.RoleType(kv[2]).IsValid() {
|
||||
return org.RoleType(kv[2])
|
||||
|
@ -268,6 +268,29 @@ func TestOrgRoleMapper_ParseOrgMappingSettings(t *testing.T) {
|
||||
strictRoleMapping: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "should return correct mapping when the first part contains multiple colons",
|
||||
rawMapping: []string{"Groups\\:IT\\:ops:1:Viewer"},
|
||||
roleStrict: false,
|
||||
expected: &MappingConfiguration{
|
||||
orgMapping: map[string]map[int64]org.RoleType{"Groups:IT:ops": {1: org.RoleViewer}},
|
||||
strictRoleMapping: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "should return correct mapping when the org name contains multiple colons",
|
||||
rawMapping: []string{`Group1:Org\:1:Viewer`},
|
||||
roleStrict: false,
|
||||
setupMock: func(orgService *orgtest.MockService) {
|
||||
orgService.On("GetByName", mock.Anything, mock.MatchedBy(func(query *org.GetOrgByNameQuery) bool {
|
||||
return query.Name == "Org:1"
|
||||
})).Return(&org.Org{ID: 1}, nil)
|
||||
},
|
||||
expected: &MappingConfiguration{
|
||||
orgMapping: map[string]map[int64]org.RoleType{"Group1": {1: org.RoleViewer}},
|
||||
strictRoleMapping: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "should return empty mapping when org mapping is nil",
|
||||
rawMapping: nil,
|
||||
@ -277,8 +300,8 @@ func TestOrgRoleMapper_ParseOrgMappingSettings(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "should return empty mapping when the org mapping format is invalid and strict role mapping is enabled",
|
||||
rawMapping: []string{"External:Org1:First:Organization:Editor"},
|
||||
name: "should return empty mapping when one of the org mappings are not in the correct format and strict role mapping is enabled",
|
||||
rawMapping: []string{"Second:Group:1:SuperEditor", "Second:1:Viewer"},
|
||||
roleStrict: true,
|
||||
expected: &MappingConfiguration{
|
||||
orgMapping: map[string]map[int64]org.RoleType{},
|
||||
@ -286,11 +309,11 @@ func TestOrgRoleMapper_ParseOrgMappingSettings(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "should return only the valid mappings from the raw mappings when strict role mapping is disabled",
|
||||
rawMapping: []string{"External:Org1:First:Organization:Editor", "Second:1:Editor"},
|
||||
name: "should skip org mapping when one of the org mappings are not in the correct format and strict role mapping is enabled",
|
||||
rawMapping: []string{"Second:Group:1:SuperEditor", "Second:1:Admin"},
|
||||
roleStrict: false,
|
||||
expected: &MappingConfiguration{
|
||||
orgMapping: map[string]map[int64]org.RoleType{"Second": {1: org.RoleEditor}},
|
||||
orgMapping: map[string]map[int64]org.RoleType{"Second": {1: org.RoleAdmin}},
|
||||
strictRoleMapping: false,
|
||||
},
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user