Add custom authorizer, update noop search
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
|
||||
iamv0 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
iamauthorizer "github.com/grafana/grafana/pkg/registry/apis/iam/authorizer"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/iam/legacy"
|
||||
@@ -40,6 +41,22 @@ func newIAMAuthorizer(
|
||||
return authorizer.DecisionAllow, "", nil
|
||||
})
|
||||
|
||||
serviceIdentityAuthorizer := authorizer.AuthorizerFunc(func(
|
||||
ctx context.Context, attr authorizer.Attributes,
|
||||
) (authorized authorizer.Decision, reason string, err error) {
|
||||
if identity.IsServiceIdentity(ctx) {
|
||||
// A Grafana sub-system should have full access. We trust them to make wise decisions.
|
||||
return authorizer.DecisionAllow, "", nil
|
||||
}
|
||||
|
||||
req, err := identity.GetRequester(ctx)
|
||||
if err == nil && req != nil && req.GetIsGrafanaAdmin() {
|
||||
return authorizer.DecisionAllow, "", nil
|
||||
}
|
||||
|
||||
return authorizer.DecisionDeny, "", nil
|
||||
})
|
||||
|
||||
// Identity specific resources
|
||||
legacyAuthorizer := gfauthorizer.NewResourceAuthorizer(legacyAccessClient)
|
||||
resourceAuthorizer["display"] = legacyAuthorizer
|
||||
@@ -58,7 +75,7 @@ func newIAMAuthorizer(
|
||||
resourceAuthorizer["searchUsers"] = serviceAuthorizer
|
||||
resourceAuthorizer["searchTeams"] = serviceAuthorizer
|
||||
// TODO: Implement fine-grained authorization for external group mapping search on the search level
|
||||
resourceAuthorizer["searchExternalGroupMappings"] = allowAuthorizer
|
||||
resourceAuthorizer["searchExternalGroupMappings"] = serviceIdentityAuthorizer
|
||||
|
||||
return &iamAuthorizer{resourceAuthorizer: resourceAuthorizer}
|
||||
}
|
||||
|
||||
@@ -97,8 +97,8 @@ func (r *TeamBindingAuthorizer) beforeWrite(ctx context.Context, obj runtime.Obj
|
||||
teamName := concreteObj.Spec.TeamRef.Name
|
||||
checkReq := types.CheckRequest{
|
||||
Namespace: authInfo.GetNamespace(),
|
||||
Group: iamv0.GROUP,
|
||||
Resource: iamv0.TeamResourceInfo.GetName(),
|
||||
Group: iamv0.TeamResourceInfo.GroupResource().Group,
|
||||
Resource: iamv0.TeamResourceInfo.GroupResource().Resource,
|
||||
Verb: utils.VerbSetPermissions,
|
||||
Name: teamName,
|
||||
}
|
||||
|
||||
@@ -28,11 +28,40 @@ func (n *NoopSearchREST) GetAPIRoutes(defs map[string]common.OpenAPIDefinition)
|
||||
{
|
||||
Path: "searchExternalGroupMappings",
|
||||
Spec: &spec3.PathProps{
|
||||
Get: &spec3.Operation{
|
||||
Post: &spec3.Operation{
|
||||
OperationProps: spec3.OperationProps{
|
||||
Description: "External Group Mapping search",
|
||||
Tags: []string{"Search"},
|
||||
OperationId: "searchExternalGroupMappings",
|
||||
RequestBody: &spec3.RequestBody{
|
||||
RequestBodyProps: spec3.RequestBodyProps{
|
||||
Content: map[string]*spec3.MediaType{
|
||||
"application/json": {
|
||||
MediaTypeProps: spec3.MediaTypeProps{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"externalGroups": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"string"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Parameters: []*spec3.Parameter{
|
||||
{
|
||||
ParameterProps: spec3.ParameterProps{
|
||||
@@ -44,15 +73,6 @@ func (n *NoopSearchREST) GetAPIRoutes(defs map[string]common.OpenAPIDefinition)
|
||||
Schema: spec.StringProperty(),
|
||||
},
|
||||
},
|
||||
{
|
||||
ParameterProps: spec3.ParameterProps{
|
||||
Name: "externalGroup",
|
||||
In: "query",
|
||||
Required: false,
|
||||
Description: "External group name",
|
||||
Schema: spec.StringProperty(),
|
||||
},
|
||||
},
|
||||
{
|
||||
ParameterProps: spec3.ParameterProps{
|
||||
Name: "teamName",
|
||||
|
||||
@@ -912,6 +912,139 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"/apis/iam.grafana.app/v0alpha1/namespaces/{namespace}/searchExternalGroupMappings": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Search"
|
||||
],
|
||||
"description": "External Group Mapping search",
|
||||
"operationId": "searchExternalGroupMappings",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "namespace",
|
||||
"in": "path",
|
||||
"description": "workspace",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"example": "default"
|
||||
},
|
||||
{
|
||||
"name": "teamName",
|
||||
"in": "query",
|
||||
"description": "Team name",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "limit",
|
||||
"in": "query",
|
||||
"description": "number of results to return",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"example": 30
|
||||
},
|
||||
{
|
||||
"name": "page",
|
||||
"in": "query",
|
||||
"description": "page number (starting from 1)",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"example": 1
|
||||
},
|
||||
{
|
||||
"name": "offset",
|
||||
"in": "query",
|
||||
"description": "number of results to skip",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"example": 0
|
||||
},
|
||||
{
|
||||
"name": "sort",
|
||||
"in": "query",
|
||||
"description": "sortable field",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"examples": {
|
||||
"": {
|
||||
"summary": "default sorting",
|
||||
"value": "externalGroup"
|
||||
},
|
||||
"-externalGroup": {
|
||||
"summary": "externalGroup descending",
|
||||
"value": "-externalGroup"
|
||||
},
|
||||
"externalGroup": {
|
||||
"summary": "externalGroup ascending",
|
||||
"value": "externalGroup"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"externalGroups": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"default": {
|
||||
"description": "Default OK response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"metadata",
|
||||
"items"
|
||||
],
|
||||
"properties": {
|
||||
"apiVersion": {
|
||||
"description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
||||
"type": "string"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"default": {}
|
||||
}
|
||||
},
|
||||
"kind": {
|
||||
"description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
"default": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/apis/iam.grafana.app/v0alpha1/namespaces/{namespace}/searchTeams": {
|
||||
"get": {
|
||||
"tags": [
|
||||
|
||||
Reference in New Issue
Block a user