-
Notifications
You must be signed in to change notification settings - Fork 432
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add rbac middleware system (#6103)
- Loading branch information
Showing
29 changed files
with
1,556 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package rbac | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
"github.com/go-gorp/gorp" | ||
"github.com/rockbears/log" | ||
|
||
"github.com/ovh/cds/engine/api/database/gorpmapping" | ||
"github.com/ovh/cds/engine/gorpmapper" | ||
"github.com/ovh/cds/sdk" | ||
) | ||
|
||
func LoadRbacByName(ctx context.Context, db gorp.SqlExecutor, name string, opts ...LoadOptionFunc) (sdk.RBAC, error) { | ||
query := `SELECT * FROM rbac WHERE name = $1` | ||
return get(ctx, db, gorpmapping.NewQuery(query).Args(name), opts...) | ||
} | ||
|
||
// Insert a RBAC permission in database | ||
func Insert(ctx context.Context, db gorpmapper.SqlExecutorWithTx, rb *sdk.RBAC) error { | ||
if err := sdk.IsValidRbac(rb); err != nil { | ||
return err | ||
} | ||
if rb.UUID == "" { | ||
rb.UUID = sdk.UUID() | ||
} | ||
if rb.Created.IsZero() { | ||
rb.Created = time.Now() | ||
} | ||
rb.LastModified = time.Now() | ||
dbRb := rbac{RBAC: *rb} | ||
if err := gorpmapping.InsertAndSign(ctx, db, &dbRb); err != nil { | ||
return err | ||
} | ||
|
||
for i := range rb.Globals { | ||
dbRbGlobal := rbacGlobal{ | ||
RbacUUID: dbRb.UUID, | ||
RBACGlobal: rb.Globals[i], | ||
} | ||
if err := insertRbacGlobal(ctx, db, &dbRbGlobal); err != nil { | ||
return err | ||
} | ||
} | ||
for i := range rb.Projects { | ||
dbRbProject := rbacProject{ | ||
RbacUUID: dbRb.UUID, | ||
RBACProject: rb.Projects[i], | ||
} | ||
if err := insertRbacProject(ctx, db, &dbRbProject); err != nil { | ||
return err | ||
} | ||
} | ||
*rb = dbRb.RBAC | ||
return nil | ||
} | ||
|
||
func Update(ctx context.Context, db gorpmapper.SqlExecutorWithTx, rb *sdk.RBAC) error { | ||
if err := Delete(ctx, db, *rb); err != nil { | ||
return err | ||
} | ||
return Insert(ctx, db, rb) | ||
} | ||
|
||
func Delete(_ context.Context, db gorpmapper.SqlExecutorWithTx, rb sdk.RBAC) error { | ||
dbRb := rbac{RBAC: rb} | ||
if err := gorpmapping.Delete(db, &dbRb); err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func get(ctx context.Context, db gorp.SqlExecutor, q gorpmapping.Query, opts ...LoadOptionFunc) (sdk.RBAC, error) { | ||
var r sdk.RBAC | ||
var rbacDB rbac | ||
found, err := gorpmapping.Get(ctx, db, q, &rbacDB) | ||
if err != nil { | ||
return r, err | ||
} | ||
if !found { | ||
return r, sdk.WithStack(sdk.ErrNotFound) | ||
} | ||
|
||
isValid, err := gorpmapping.CheckSignature(rbacDB, rbacDB.Signature) | ||
if err != nil { | ||
return r, sdk.WrapError(err, "error when checking signature for rbac %s", rbacDB.UUID) | ||
} | ||
if !isValid { | ||
log.Error(ctx, "rbac.get> rbac %s (%s) data corrupted", rbacDB.Name, rbacDB.UUID) | ||
return r, sdk.WithStack(sdk.ErrNotFound) | ||
} | ||
for _, f := range opts { | ||
if err := f(ctx, db, &rbacDB); err != nil { | ||
return r, err | ||
} | ||
} | ||
r = rbacDB.RBAC | ||
return r, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
package rbac | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/go-gorp/gorp" | ||
"github.com/rockbears/log" | ||
|
||
"github.com/ovh/cds/engine/api/database/gorpmapping" | ||
"github.com/ovh/cds/engine/gorpmapper" | ||
"github.com/ovh/cds/sdk" | ||
) | ||
|
||
func insertRbacGlobal(ctx context.Context, db gorpmapper.SqlExecutorWithTx, rg *rbacGlobal) error { | ||
if err := gorpmapping.InsertAndSign(ctx, db, rg); err != nil { | ||
return err | ||
} | ||
|
||
for _, userID := range rg.RBACUsersIDs { | ||
if err := insertRbacGlobalUser(ctx, db, rg.ID, userID); err != nil { | ||
return err | ||
} | ||
} | ||
for _, groupID := range rg.RBACGroupsIDs { | ||
if err := insertRbacGlobalGroup(ctx, db, rg.ID, groupID); err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func insertRbacGlobalUser(ctx context.Context, db gorpmapper.SqlExecutorWithTx, rbacGlobalID int64, userID string) error { | ||
rgu := rbacGlobalUser{ | ||
RbacGlobalID: rbacGlobalID, | ||
RbacGlobalUserID: userID, | ||
} | ||
if err := gorpmapping.InsertAndSign(ctx, db, &rgu); err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func insertRbacGlobalGroup(ctx context.Context, db gorpmapper.SqlExecutorWithTx, rbacGlobalID int64, groupID int64) error { | ||
rgu := rbacGlobalGroup{ | ||
RbacGlobalID: rbacGlobalID, | ||
RbacGlobalGroupID: groupID, | ||
} | ||
if err := gorpmapping.InsertAndSign(ctx, db, &rgu); err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func getAllRBACGlobalUsers(ctx context.Context, db gorp.SqlExecutor, rbacGlobal *rbacGlobal) error { | ||
q := gorpmapping.NewQuery("SELECT * FROM rbac_global_users WHERE rbac_global_id = $1").Args(rbacGlobal.ID) | ||
var rbacUserIDS []rbacGlobalUser | ||
if err := gorpmapping.GetAll(ctx, db, q, &rbacUserIDS); err != nil { | ||
return err | ||
} | ||
rbacGlobal.RBACGlobal.RBACUsersIDs = make([]string, 0, len(rbacUserIDS)) | ||
for _, rbacUsers := range rbacUserIDS { | ||
isValid, err := gorpmapping.CheckSignature(rbacUsers, rbacUsers.Signature) | ||
if err != nil { | ||
return sdk.WrapError(err, "error when checking signature for rbac_global_users %d", rbacUsers.ID) | ||
} | ||
if !isValid { | ||
log.Error(ctx, "rbac.getAllRBACGlobalUsers> rbac_global_users %d data corrupted", rbacUsers.ID) | ||
continue | ||
} | ||
rbacGlobal.RBACGlobal.RBACUsersIDs = append(rbacGlobal.RBACGlobal.RBACUsersIDs, rbacUsers.RbacGlobalUserID) | ||
} | ||
return nil | ||
} | ||
|
||
func getAllRBACGlobalGroups(ctx context.Context, db gorp.SqlExecutor, rbacGlobal *rbacGlobal) error { | ||
q := gorpmapping.NewQuery("SELECT * FROM rbac_global_groups WHERE rbac_global_id = $1").Args(rbacGlobal.ID) | ||
var rbacGroupIDs []rbacGlobalGroup | ||
if err := gorpmapping.GetAll(ctx, db, q, &rbacGroupIDs); err != nil { | ||
return err | ||
} | ||
rbacGlobal.RBACGlobal.RBACGroupsIDs = make([]int64, 0, len(rbacGroupIDs)) | ||
for _, rbacGroups := range rbacGroupIDs { | ||
isValid, err := gorpmapping.CheckSignature(rbacGroups, rbacGroups.Signature) | ||
if err != nil { | ||
return sdk.WrapError(err, "error when checking signature for rbac_global_groups %d", rbacGroups.ID) | ||
} | ||
if !isValid { | ||
log.Error(ctx, "rbac.getAllRBACGlobalGroups> rbac_global_groups %d data corrupted", rbacGroups.ID) | ||
continue | ||
} | ||
rbacGlobal.RBACGlobal.RBACGroupsIDs = append(rbacGlobal.RBACGlobal.RBACGroupsIDs, rbacGroups.RbacGlobalGroupID) | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package rbac | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/go-gorp/gorp" | ||
"github.com/lib/pq" | ||
"github.com/rockbears/log" | ||
|
||
"github.com/ovh/cds/engine/api/database/gorpmapping" | ||
"github.com/ovh/cds/engine/gorpmapper" | ||
"github.com/ovh/cds/sdk" | ||
) | ||
|
||
func insertRbacProject(ctx context.Context, db gorpmapper.SqlExecutorWithTx, dbRP *rbacProject) error { | ||
if err := gorpmapping.InsertAndSign(ctx, db, dbRP); err != nil { | ||
return err | ||
} | ||
|
||
for _, rbProjectID := range dbRP.RBACProjectsIDs { | ||
if err := insertRbacProjectIdentifiers(ctx, db, dbRP.ID, rbProjectID); err != nil { | ||
return err | ||
} | ||
} | ||
for _, rbUserID := range dbRP.RBACUsersIDs { | ||
if err := insertRbacProjectUser(ctx, db, dbRP.ID, rbUserID); err != nil { | ||
return err | ||
} | ||
} | ||
for _, rbGroupID := range dbRP.RBACGroupsIDs { | ||
if err := insertRbacProjectGroup(ctx, db, dbRP.ID, rbGroupID); err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func insertRbacProjectIdentifiers(ctx context.Context, db gorpmapper.SqlExecutorWithTx, rbacParentID int64, projectID int64) error { | ||
identifier := rbacProjectIdentifiers{ | ||
RbacProjectID: rbacParentID, | ||
ProjectID: projectID, | ||
} | ||
if err := gorpmapping.InsertAndSign(ctx, db, &identifier); err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func insertRbacProjectUser(ctx context.Context, db gorpmapper.SqlExecutorWithTx, rbacProjectID int64, userID string) error { | ||
rgu := rbacProjectUser{ | ||
RbacProjectID: rbacProjectID, | ||
RbacProjectUserID: userID, | ||
} | ||
if err := gorpmapping.InsertAndSign(ctx, db, &rgu); err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func insertRbacProjectGroup(ctx context.Context, db gorpmapper.SqlExecutorWithTx, rbacProjectID int64, groupID int64) error { | ||
rgu := rbacProjectGroup{ | ||
RbacProjectID: rbacProjectID, | ||
RbacProjectGroupID: groupID, | ||
} | ||
if err := gorpmapping.InsertAndSign(ctx, db, &rgu); err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func getAllRbacProjects(ctx context.Context, db gorp.SqlExecutor, q gorpmapping.Query) ([]rbacProject, error) { | ||
var rbacProjects []rbacProject | ||
if err := gorpmapping.GetAll(ctx, db, q, &rbacProjects); err != nil { | ||
return nil, err | ||
} | ||
|
||
projectsFiltered := make([]rbacProject, 0, len(rbacProjects)) | ||
for _, projectDatas := range rbacProjects { | ||
isValid, err := gorpmapping.CheckSignature(projectDatas, projectDatas.Signature) | ||
if err != nil { | ||
return nil, sdk.WrapError(err, "error when checking signature for rbac_project %d", projectDatas.ID) | ||
} | ||
if !isValid { | ||
log.Error(ctx, "rbac.getAllRbacProjects> rbac_project %d data corrupted", projectDatas.ID) | ||
continue | ||
} | ||
projectsFiltered = append(projectsFiltered, projectDatas) | ||
} | ||
return projectsFiltered, nil | ||
} | ||
|
||
func loadRbacProjectsByRoleAndIDs(ctx context.Context, db gorp.SqlExecutor, role string, rbacProjectIDs []int64) ([]rbacProject, error) { | ||
q := gorpmapping.NewQuery(`SELECT * from rbac_project WHERE role = $1 AND id = ANY($2)`).Args(role, pq.Int64Array(rbacProjectIDs)) | ||
return getAllRbacProjects(ctx, db, q) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package rbac | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/go-gorp/gorp" | ||
"github.com/lib/pq" | ||
"github.com/rockbears/log" | ||
|
||
"github.com/ovh/cds/engine/api/database/gorpmapping" | ||
"github.com/ovh/cds/engine/api/group" | ||
"github.com/ovh/cds/sdk" | ||
) | ||
|
||
func loadRbacProjectGroupsByUserID(ctx context.Context, db gorp.SqlExecutor, userID string) ([]rbacProjectGroup, error) { | ||
groups, err := group.LoadAllByUserID(ctx, db, userID) | ||
if err != nil { | ||
return nil, err | ||
} | ||
groupIDs := make([]int64, 0, len(groups)) | ||
for _, g := range groups { | ||
groupIDs = append(groupIDs, g.ID) | ||
} | ||
return loadRbacProjectGroupsByGroupIDs(ctx, db, groupIDs) | ||
} | ||
|
||
func loadRbacProjectGroupsByGroupIDs(ctx context.Context, db gorp.SqlExecutor, groupIDs []int64) ([]rbacProjectGroup, error) { | ||
q := gorpmapping.NewQuery("SELECT * FROM rbac_project_groups WHERE group_id = ANY ($1)").Args(pq.Int64Array(groupIDs)) | ||
return getAllRBACProjectGroups(ctx, db, q) | ||
} | ||
|
||
func loadRBACProjectGroups(ctx context.Context, db gorp.SqlExecutor, rbacProject *rbacProject) error { | ||
q := gorpmapping.NewQuery("SELECT * FROM rbac_project_groups WHERE rbac_project_id = $1").Args(rbacProject.ID) | ||
rbacProjectGroups, err := getAllRBACProjectGroups(ctx, db, q) | ||
if err != nil { | ||
return err | ||
} | ||
rbacProject.RBACProject.RBACGroupsIDs = make([]int64, 0, len(rbacProjectGroups)) | ||
for _, g := range rbacProjectGroups { | ||
rbacProject.RBACProject.RBACGroupsIDs = append(rbacProject.RBACProject.RBACGroupsIDs, g.RbacProjectGroupID) | ||
} | ||
return nil | ||
} | ||
|
||
func getAllRBACProjectGroups(ctx context.Context, db gorp.SqlExecutor, q gorpmapping.Query) ([]rbacProjectGroup, error) { | ||
var rbacGroupIDs []rbacProjectGroup | ||
if err := gorpmapping.GetAll(ctx, db, q, &rbacGroupIDs); err != nil { | ||
return nil, err | ||
} | ||
|
||
groupsFiltered := make([]rbacProjectGroup, 0, len(rbacGroupIDs)) | ||
for _, rbacGroups := range rbacGroupIDs { | ||
isValid, err := gorpmapping.CheckSignature(rbacGroups, rbacGroups.Signature) | ||
if err != nil { | ||
return nil, sdk.WrapError(err, "error when checking signature for rbac_project_groups %d", rbacGroups.ID) | ||
} | ||
if !isValid { | ||
log.Error(ctx, "rbac.getAllRBACProjectGroups> rbac_project_groups %d data corrupted", rbacGroups.ID) | ||
continue | ||
} | ||
groupsFiltered = append(groupsFiltered, rbacGroups) | ||
} | ||
return groupsFiltered, nil | ||
} |
Oops, something went wrong.