mirror of
https://github.com/kubeshark/kubeshark.git
synced 2025-09-27 21:38:06 +00:00
182 lines
5.4 KiB
Go
182 lines
5.4 KiB
Go
package providers
|
|
|
|
/*
|
|
This provider abstracts keto role management down to what we need for mizu
|
|
|
|
Keto, in the configuration we use it, is basically a tuple database. Each tuple consists of 4 strings (namespace, object, relation, subjectID) - for example ("workspaces", "sock-shop-workspace", "viewer", "ramiberman")
|
|
|
|
namespace - used to organize tuples into groups - we currently use "system" for defining admins and "workspaces" for defining workspace permissions
|
|
objects - represents something one can have permissions to (files, mizu workspaces etc)
|
|
relation - represents the permission (viewer, editor, owner etc) - we currently use only viewer and admin
|
|
subject - represents the user or group that has the permission - we currently use usernames
|
|
|
|
more on keto here: https://www.ory.sh/keto/docs/
|
|
*/
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/up9inc/mizu/agent/pkg/utils"
|
|
|
|
ketoClient "github.com/ory/keto-client-go/client"
|
|
ketoRead "github.com/ory/keto-client-go/client/read"
|
|
ketoWrite "github.com/ory/keto-client-go/client/write"
|
|
ketoModels "github.com/ory/keto-client-go/models"
|
|
)
|
|
|
|
const (
|
|
ketoHost = "localhost"
|
|
ketoReadPort = 4466
|
|
ketoWritePort = 4467
|
|
)
|
|
|
|
var (
|
|
readClient = getKetoClient(fmt.Sprintf("%s:%d", ketoHost, ketoReadPort))
|
|
writeClient = getKetoClient(fmt.Sprintf("%s:%d", ketoHost, ketoWritePort))
|
|
systemRoleNamespace = "system"
|
|
workspacesRoleNamespace = "workspaces"
|
|
|
|
systemObject = "system"
|
|
|
|
AdminRole = "admin"
|
|
ViewerRole = "viewer"
|
|
)
|
|
|
|
func GetUserSystemRoles(username string) ([]string, error) {
|
|
return getObjectRelationsForSubjectID(systemRoleNamespace, systemObject, username)
|
|
}
|
|
|
|
func CheckIfUserHasSystemRole(username string, role string) (bool, error) {
|
|
systemRoles, err := GetUserSystemRoles(username)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
for _, systemRole := range systemRoles {
|
|
if systemRole == role {
|
|
return true, nil
|
|
}
|
|
}
|
|
|
|
return false, nil
|
|
}
|
|
|
|
func GetUserWorkspaceRole(username string, workspace string) ([]string, error) {
|
|
return getObjectRelationsForSubjectID(workspacesRoleNamespace, workspace, username)
|
|
}
|
|
|
|
func SetUserWorkspaceRole(username string, workspace string, role string) error {
|
|
return createObjectRelationForSubjectID(workspacesRoleNamespace, workspace, username, role)
|
|
}
|
|
|
|
func SetUserSystemRole(username string, role string) error {
|
|
return createObjectRelationForSubjectID(systemRoleNamespace, systemObject, username, role)
|
|
}
|
|
|
|
func DeleteAllUserWorkspaceRoles(username string) error {
|
|
return deleteAllNamespacedRelationsForSubjectID(workspacesRoleNamespace, username)
|
|
}
|
|
|
|
func createObjectRelationForSubjectID(namespace string, object string, subjectID string, relation string) error {
|
|
tuple := ketoModels.RelationQuery{
|
|
Namespace: &namespace,
|
|
Object: object,
|
|
Relation: relation,
|
|
SubjectID: subjectID,
|
|
}
|
|
|
|
_, err := writeClient.Write.CreateRelationTuple(ketoWrite.
|
|
NewCreateRelationTupleParams().
|
|
WithPayload(&tuple))
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func getObjectRelationsForSubjectID(namespace string, object string, subjectID string) ([]string, error) {
|
|
relationTuples, err := queryRelationTuples(&namespace, &object, &subjectID, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
relations := make([]string, 0)
|
|
|
|
for _, clientRelation := range relationTuples {
|
|
relations = append(relations, *clientRelation.Relation)
|
|
}
|
|
|
|
return utils.UniqueStringSlice(relations), nil
|
|
}
|
|
|
|
func deleteAllNamespacedRelationsForSubjectID(namespace string, subjectID string) error {
|
|
relationTuples, err := queryRelationTuples(&namespace, nil, &subjectID, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, clientRelation := range relationTuples {
|
|
_, err := writeClient.Write.DeleteRelationTuple(ketoWrite.
|
|
NewDeleteRelationTupleParams().
|
|
WithNamespace(*clientRelation.Namespace).
|
|
WithObject(*clientRelation.Object).
|
|
WithRelation(*clientRelation.Relation).
|
|
WithSubjectID(&clientRelation.SubjectID))
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func queryRelationTuples(namespace *string, object *string, subjectID *string, role *string) ([]*ketoModels.InternalRelationTuple, error) {
|
|
relationTuplesQuery := ketoRead.NewGetRelationTuplesParams()
|
|
if namespace != nil {
|
|
relationTuplesQuery = relationTuplesQuery.WithNamespace(*namespace)
|
|
}
|
|
if object != nil {
|
|
relationTuplesQuery = relationTuplesQuery.WithObject(object)
|
|
}
|
|
if subjectID != nil {
|
|
relationTuplesQuery = relationTuplesQuery.WithSubjectID(subjectID)
|
|
}
|
|
if role != nil {
|
|
relationTuplesQuery = relationTuplesQuery.WithRelation(role)
|
|
}
|
|
|
|
return recursiveKetoPagingTraverse(relationTuplesQuery, make([]*ketoModels.InternalRelationTuple, 0), "")
|
|
}
|
|
|
|
func recursiveKetoPagingTraverse(queryParams *ketoRead.GetRelationTuplesParams, tuples []*ketoModels.InternalRelationTuple, pagingToken string) ([]*ketoModels.InternalRelationTuple, error) {
|
|
params := queryParams
|
|
if pagingToken != "" {
|
|
params = queryParams.WithPageToken(&pagingToken)
|
|
}
|
|
|
|
clientRelationsResponse, err := readClient.Read.GetRelationTuples(params)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
tuples = append(tuples, clientRelationsResponse.Payload.RelationTuples...)
|
|
|
|
if clientRelationsResponse.Payload.NextPageToken != "" {
|
|
return recursiveKetoPagingTraverse(queryParams, tuples, clientRelationsResponse.Payload.NextPageToken)
|
|
}
|
|
|
|
return tuples, nil
|
|
}
|
|
|
|
func getKetoClient(url string) *ketoClient.OryKeto {
|
|
return ketoClient.NewHTTPClientWithConfig(nil,
|
|
ketoClient.
|
|
DefaultTransportConfig().
|
|
WithSchemes([]string{"http"}).
|
|
WithHost(url))
|
|
}
|