Oc Auth x Hydra x LDAP : draft of claims enrich for traefik + draft of forwarding
This commit is contained in:
360
infrastructure/perms_connectors/keto_connector.go
Normal file
360
infrastructure/perms_connectors/keto_connector.go
Normal file
@@ -0,0 +1,360 @@
|
||||
package perms_connectors
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"oc-auth/conf"
|
||||
"oc-auth/infrastructure/utils"
|
||||
|
||||
oclib "cloud.o-forge.io/core/oc-lib"
|
||||
"cloud.o-forge.io/core/oc-lib/tools"
|
||||
)
|
||||
|
||||
type KetoConnector struct{}
|
||||
|
||||
func (k KetoConnector) namespace() string {
|
||||
return "open-cloud"
|
||||
}
|
||||
|
||||
func (k KetoConnector) scope() string {
|
||||
return "oc-auth"
|
||||
}
|
||||
|
||||
func (f KetoConnector) permToQuery(perm Permission, permDependancies *Permission) string {
|
||||
n := "?namespace=" + perm.Namespace()
|
||||
if perm.Object != "" {
|
||||
n += "&object=" + perm.Object
|
||||
}
|
||||
if perm.Subject != "" {
|
||||
n += "&subject_id=" + perm.Subject
|
||||
}
|
||||
if perm.Relation != "" {
|
||||
n += "&relation=" + perm.Relation
|
||||
}
|
||||
if permDependancies != nil {
|
||||
n += "&subject_set.namespace=" + perm.Namespace()
|
||||
if permDependancies.Object != "" {
|
||||
n += "&subject_set.object=" + permDependancies.Object
|
||||
}
|
||||
if permDependancies.Subject != "" {
|
||||
n += "&subject_set.subject_id=" + permDependancies.Subject
|
||||
}
|
||||
if permDependancies.Relation != "" {
|
||||
n += "&subject_set.relation=" + permDependancies.Relation
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (k KetoConnector) Status() tools.State {
|
||||
caller := tools.NewHTTPCaller(map[tools.DataType]map[tools.METHOD]string{})
|
||||
var responseBody map[string]interface{}
|
||||
host := conf.GetConfig().PermissionConnectorHost
|
||||
port := fmt.Sprintf("%v", conf.GetConfig().PermissionConnectorPort)
|
||||
resp, err := caller.CallGet("http://"+host+":"+port, "/health/ready")
|
||||
if err != nil {
|
||||
return tools.DEAD
|
||||
}
|
||||
err = json.Unmarshal(resp, &responseBody)
|
||||
if err != nil || responseBody["status"] != "ok" {
|
||||
return tools.DEAD
|
||||
}
|
||||
return tools.ALIVE
|
||||
}
|
||||
|
||||
func (k KetoConnector) CheckPermission(perm Permission, permDependancies *Permission, internal bool) bool {
|
||||
if (perm.Object == k.scope() || perm.Subject == k.scope()) && !internal {
|
||||
log := oclib.GetLogger()
|
||||
log.Error().Msg("Permission denied : Ask illegal permission")
|
||||
return false
|
||||
}
|
||||
caller := tools.NewHTTPCaller(map[tools.DataType]map[tools.METHOD]string{})
|
||||
var responseBody map[string]interface{}
|
||||
host := conf.GetConfig().PermissionConnectorHost
|
||||
port := fmt.Sprintf("%v", conf.GetConfig().PermissionConnectorPort)
|
||||
resp, err := caller.CallGet("http://"+host+":"+port, "/relation-tuples/check"+k.permToQuery(perm, permDependancies))
|
||||
if err != nil {
|
||||
log := oclib.GetLogger()
|
||||
log.Error().Msg(err.Error())
|
||||
return false
|
||||
}
|
||||
err = json.Unmarshal(resp, &responseBody)
|
||||
if err != nil || responseBody["allowed"] == nil {
|
||||
return false
|
||||
}
|
||||
return responseBody["allowed"].(bool)
|
||||
}
|
||||
|
||||
func (k KetoConnector) DeleteRole(roleID string) (string, int, error) {
|
||||
k.deleteRelationShip("", "", roleID, nil)
|
||||
_, code, err := k.deleteRelationShip(roleID, "", k.scope(), nil)
|
||||
if err != nil {
|
||||
return "", code, err
|
||||
}
|
||||
return roleID, 200, nil
|
||||
}
|
||||
|
||||
func (k KetoConnector) DeletePermission(permID string, relation string, internal bool) (string, int, error) {
|
||||
meth, err := utils.ExtractMethod(relation, internal)
|
||||
if err != nil {
|
||||
for _, method := range []tools.METHOD{tools.GET, tools.PUT, tools.POST, tools.DELETE} {
|
||||
k.DeletePermission("", method.String(), internal)
|
||||
}
|
||||
return "", 200, err
|
||||
}
|
||||
k.deleteRelationShip("", "", permID, nil)
|
||||
_, code, err := k.deleteRelationShip(permID, "permits"+meth.String(), k.scope(), nil)
|
||||
if err != nil {
|
||||
return "", code, err
|
||||
}
|
||||
return permID, 200, nil
|
||||
}
|
||||
|
||||
func (k KetoConnector) CreateRole(roleID string) (string, int, error) {
|
||||
p, code, err := k.createRelationShip(roleID, "is", k.scope(), nil)
|
||||
if err != nil {
|
||||
return "", code, err
|
||||
}
|
||||
return p.Object, 200, nil
|
||||
}
|
||||
|
||||
func (k KetoConnector) CreatePermission(permID string, relation string, internal bool) (string, int, error) {
|
||||
meth, err := utils.ExtractMethod(relation, internal)
|
||||
if err != nil {
|
||||
return "", 422, err
|
||||
}
|
||||
p, code, err := k.createRelationShip(permID, "permits"+meth.String(), k.scope(), nil)
|
||||
if err != nil {
|
||||
return "", code, err
|
||||
}
|
||||
return p.Object, 200, nil
|
||||
}
|
||||
|
||||
func (k KetoConnector) GetRole(roleID string) ([]string, error) {
|
||||
arr := []string{}
|
||||
roles, err := k.get(roleID, "is", k.scope())
|
||||
if err != nil {
|
||||
return arr, err
|
||||
}
|
||||
for _, role := range roles {
|
||||
arr = append(arr, role.Object)
|
||||
}
|
||||
return arr, nil
|
||||
}
|
||||
|
||||
func (k KetoConnector) GetRoleByUser(userID string) ([]string, error) {
|
||||
arr := []string{}
|
||||
roles, err := k.get("", "is", userID)
|
||||
if err != nil {
|
||||
return arr, err
|
||||
}
|
||||
for _, role := range roles {
|
||||
arr = append(arr, role.Object)
|
||||
}
|
||||
return arr, nil
|
||||
}
|
||||
|
||||
func (k KetoConnector) GetPermission(permID string, relation string) ([]Permission, error) {
|
||||
meth, err := utils.ExtractMethod(relation, true)
|
||||
if err != nil {
|
||||
p := []Permission{}
|
||||
for _, method := range []tools.METHOD{tools.GET, tools.PUT, tools.POST, tools.DELETE} {
|
||||
fmt.Println("blblbl", permID, "permits"+method.String(), k.scope())
|
||||
perms, err := k.get(permID, "permits"+method.String(), k.scope())
|
||||
fmt.Println("blblbl2", perms, err)
|
||||
if err == nil && len(perms) > 0 {
|
||||
p = append(p, perms...)
|
||||
}
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
return k.get(permID, "permits"+meth.String(), k.scope())
|
||||
}
|
||||
|
||||
func (k KetoConnector) GetPermissionByRole(roleID string) ([]Permission, error) {
|
||||
return k.get("", "", roleID)
|
||||
}
|
||||
func (k KetoConnector) GetPermissionByUser(userID string) ([]Permission, error) {
|
||||
roles, err := k.get("", "is", userID)
|
||||
perms := []Permission{}
|
||||
if err != nil {
|
||||
return perms, err
|
||||
}
|
||||
for _, role := range roles {
|
||||
p, err := k.get(role.Object, "", k.scope())
|
||||
if err != nil {
|
||||
log := oclib.GetLogger()
|
||||
log.Error().Msg(err.Error())
|
||||
continue
|
||||
}
|
||||
perms = append(perms, p...)
|
||||
}
|
||||
return perms, nil
|
||||
}
|
||||
|
||||
func (k KetoConnector) get(object string, relation string, subject string) ([]Permission, error) {
|
||||
t := []Permission{}
|
||||
caller := tools.NewHTTPCaller(map[tools.DataType]map[tools.METHOD]string{})
|
||||
host := conf.GetConfig().PermissionConnectorHost
|
||||
port := fmt.Sprintf("%v", conf.GetConfig().PermissionConnectorPort)
|
||||
resp, err := caller.CallGet("http://"+host+":"+port, "/relation-tuples"+k.permToQuery(
|
||||
Permission{Object: object, Relation: relation, Subject: subject}, nil))
|
||||
if err != nil {
|
||||
return t, err
|
||||
}
|
||||
var data map[string]interface{}
|
||||
err = json.Unmarshal(resp, &data)
|
||||
if err != nil {
|
||||
return t, err
|
||||
}
|
||||
if data["relation_tuples"] != nil {
|
||||
for _, v := range data["relation_tuples"].([]interface{}) {
|
||||
t = append(t, Permission{
|
||||
Relation: v.(map[string]interface{})["relation"].(string),
|
||||
Subject: v.(map[string]interface{})["subject_id"].(string),
|
||||
Object: v.(map[string]interface{})["object"].(string),
|
||||
})
|
||||
}
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func (k KetoConnector) BindRole(userID string, roleID string) (string, int, error) {
|
||||
_, code, err := k.createRelationShip(roleID, "member", userID, nil)
|
||||
if err != nil {
|
||||
return roleID, code, err
|
||||
}
|
||||
return roleID, 200, nil
|
||||
}
|
||||
|
||||
func (k KetoConnector) BindPermission(roleID string, permID string, relation string) (*Permission, int, error) {
|
||||
meth, err := utils.ExtractMethod(relation, false)
|
||||
if err != nil {
|
||||
return nil, 422, err
|
||||
}
|
||||
perms, err := k.GetPermission(permID, meth.String())
|
||||
if err != nil || len(perms) != 1 {
|
||||
if len(perms) == 0 {
|
||||
return nil, 404, errors.New("Permission not found")
|
||||
} else if len(perms) > 1 {
|
||||
return nil, 409, errors.New("Multiple permission found")
|
||||
}
|
||||
}
|
||||
_, code, err := k.createRelationShip(roleID, perms[0].Relation, permID, nil)
|
||||
if err != nil {
|
||||
return nil, code, err
|
||||
}
|
||||
return &Permission{
|
||||
Object: roleID,
|
||||
Relation: perms[0].Relation,
|
||||
Subject: permID,
|
||||
}, 200, nil
|
||||
}
|
||||
|
||||
func (k KetoConnector) UnBindRole(userID string, roleID string) (string, int, error) {
|
||||
_, code, err := k.deleteRelationShip(roleID, "member", userID, nil)
|
||||
if err != nil {
|
||||
return roleID, code, err
|
||||
}
|
||||
return roleID, 200, nil
|
||||
}
|
||||
|
||||
func (k KetoConnector) UnBindPermission(roleID string, permID string, relation string) (*Permission, int, error) {
|
||||
meth, err := utils.ExtractMethod(relation, false)
|
||||
if err != nil {
|
||||
return nil, 422, err
|
||||
}
|
||||
perms, err := k.GetPermission(permID, meth.String())
|
||||
if err != nil || len(perms) != 1 {
|
||||
if len(perms) == 0 {
|
||||
return nil, 404, errors.New("Permission not found")
|
||||
} else if len(perms) > 1 {
|
||||
return nil, 409, errors.New("Multiple permission found")
|
||||
}
|
||||
}
|
||||
_, code, err := k.deleteRelationShip(roleID, perms[0].Relation, permID, nil)
|
||||
if err != nil {
|
||||
return nil, code, err
|
||||
}
|
||||
return &Permission{
|
||||
Object: roleID,
|
||||
Relation: perms[0].Relation,
|
||||
Subject: permID,
|
||||
}, 200, nil
|
||||
}
|
||||
func (k KetoConnector) createRelationShip(object string, relation string, subject string, subPerm *Permission) (*Permission, int, error) {
|
||||
exist, err := k.get(object, relation, subject)
|
||||
if err == nil && len(exist) > 0 {
|
||||
return nil, 409, errors.New("Relation already exist")
|
||||
}
|
||||
caller := tools.NewHTTPCaller(map[tools.DataType]map[tools.METHOD]string{})
|
||||
body := map[string]interface{}{"namespace": k.namespace(), "object": object, "relation": relation, "subject_id": subject}
|
||||
|
||||
if subPerm != nil {
|
||||
s, code, err := k.createRelationShip(subPerm.Object, subPerm.Relation, subPerm.Subject, nil)
|
||||
if err != nil {
|
||||
return nil, code, err
|
||||
}
|
||||
body["subject_set"] = map[string]interface{}{"namespace": s.Namespace(), "object": s.Object, "relation": s.Relation, "subject_id": s.Subject}
|
||||
}
|
||||
host := conf.GetConfig().PermissionConnectorHost
|
||||
port := fmt.Sprintf("%v", conf.GetConfig().PermissionConnectorAdminPort)
|
||||
b, err := caller.CallPut("http://"+host+":"+port, "/relation-tuples", body)
|
||||
if err != nil {
|
||||
log := oclib.GetLogger()
|
||||
log.Error().Msg(err.Error())
|
||||
return nil, 500, err
|
||||
}
|
||||
var data map[string]interface{}
|
||||
err = json.Unmarshal(b, &data)
|
||||
if err != nil {
|
||||
log := oclib.GetLogger()
|
||||
log.Error().Msg(err.Error())
|
||||
return nil, 500, err
|
||||
}
|
||||
perm := &Permission{
|
||||
Object: data["object"].(string),
|
||||
Relation: data["relation"].(string),
|
||||
Subject: data["subject_id"].(string),
|
||||
}
|
||||
if data["subject_set"] != nil {
|
||||
sub := data["subject_set"].(map[string]interface{})
|
||||
perm.SubPermission = &Permission{
|
||||
Object: sub["object"].(string),
|
||||
Relation: sub["relation"].(string),
|
||||
Subject: sub["subject_id"].(string),
|
||||
}
|
||||
}
|
||||
return perm, 200, nil
|
||||
}
|
||||
|
||||
func (k KetoConnector) deleteRelationShip(object string, relation string, subject string, subPerm *Permission) (*Permission, int, error) {
|
||||
exist, err := k.get(object, relation, subject)
|
||||
if err == nil && len(exist) == 0 {
|
||||
return nil, 409, errors.New("Relation does not exist")
|
||||
}
|
||||
caller := tools.NewHTTPCaller(map[tools.DataType]map[tools.METHOD]string{})
|
||||
n := k.permToQuery(Permission{Object: object, Relation: relation, Subject: subject}, subPerm)
|
||||
host := conf.GetConfig().PermissionConnectorHost
|
||||
port := fmt.Sprintf("%v", conf.GetConfig().PermissionConnectorAdminPort)
|
||||
fmt.Println(host, port, n)
|
||||
b, err := caller.CallDelete("http://"+host+":"+port, "/relation-tuples"+n)
|
||||
fmt.Println(b, err)
|
||||
if err != nil {
|
||||
log := oclib.GetLogger()
|
||||
log.Error().Msg(err.Error())
|
||||
return nil, 500, err
|
||||
}
|
||||
var data map[string]interface{}
|
||||
err = json.Unmarshal(b, &data)
|
||||
if err == nil && data["code"].(int) > 300 {
|
||||
return nil, data["code"].(int), errors.New("Error while deleting relation")
|
||||
}
|
||||
return &Permission{
|
||||
Object: object,
|
||||
Relation: relation,
|
||||
Subject: subject,
|
||||
SubPermission: subPerm,
|
||||
}, 200, nil
|
||||
}
|
||||
52
infrastructure/perms_connectors/perms_connector.go
Normal file
52
infrastructure/perms_connectors/perms_connector.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package perms_connectors
|
||||
|
||||
import (
|
||||
"oc-auth/conf"
|
||||
|
||||
"cloud.o-forge.io/core/oc-lib/tools"
|
||||
)
|
||||
|
||||
type Permission struct {
|
||||
Object string `json:"object,omitempty"`
|
||||
Relation string `json:"relation,omitempty"`
|
||||
Subject string `json:"subject,omitempty"`
|
||||
SubPermission *Permission `json:"sub_perm,omitempty"`
|
||||
}
|
||||
|
||||
func (p Permission) Namespace() string {
|
||||
return "open-cloud"
|
||||
}
|
||||
|
||||
func (k Permission) Scope() string {
|
||||
return "oc-auth"
|
||||
}
|
||||
|
||||
type PermConnector interface {
|
||||
Status() tools.State
|
||||
CheckPermission(perm Permission, permDependancies *Permission, internal bool) bool
|
||||
BindRole(userID string, roleID string) (string, int, error)
|
||||
BindPermission(roleID string, permID string, relation string) (*Permission, int, error)
|
||||
|
||||
UnBindRole(userID string, roleID string) (string, int, error)
|
||||
UnBindPermission(roleID string, permID string, relation string) (*Permission, int, error)
|
||||
|
||||
CreateRole(roleID string) (string, int, error)
|
||||
CreatePermission(permID string, relation string, internal bool) (string, int, error)
|
||||
DeleteRole(roleID string) (string, int, error)
|
||||
DeletePermission(permID string, relation string, internal bool) (string, int, error)
|
||||
|
||||
GetRoleByUser(userID string) ([]string, error)
|
||||
GetPermissionByRole(roleID string) ([]Permission, error)
|
||||
GetPermissionByUser(userID string) ([]Permission, error)
|
||||
|
||||
GetRole(roleID string) ([]string, error)
|
||||
GetPermission(permID string, relation string) ([]Permission, error)
|
||||
}
|
||||
|
||||
var c = map[string]PermConnector{
|
||||
"keto": KetoConnector{},
|
||||
}
|
||||
|
||||
func GetPermissionConnector() PermConnector {
|
||||
return c[conf.GetConfig().PermissionConnectorHost]
|
||||
}
|
||||
Reference in New Issue
Block a user