From 18c1697e11402deef419f2ecd23529c9789232f1 Mon Sep 17 00:00:00 2001 From: Juan Antonio Osorio Date: Tue, 30 Jan 2024 10:50:01 +0200 Subject: [PATCH] Bootstrap Permissions API in minder server and implement roles list This sets up the boilerplate to start using the Permissions API in minder. It also sets up the first API call, which is merely listing the available roles. --- internal/authz/authz.go | 2 +- internal/authz/authz_test.go | 2 +- internal/authz/interface.go | 16 +++++---- internal/controlplane/handlers_authz.go | 38 ++++++++++++++++++++++ internal/controlplane/register_handlers.go | 8 +++++ internal/controlplane/server.go | 27 ++++++++------- 6 files changed, 73 insertions(+), 20 deletions(-) diff --git a/internal/authz/authz.go b/internal/authz/authz.go index 53f4c3f42d..8f4d1dddc0 100644 --- a/internal/authz/authz.go +++ b/internal/authz/authz.go @@ -311,7 +311,7 @@ func (a *ClientWrapper) doDelete(ctx context.Context, user string, role string, // DeleteUser removes all tuples for the given user func (a *ClientWrapper) DeleteUser(ctx context.Context, user string) error { - for _, role := range AllRoles { + for role := range AllRoles { listresp, err := a.cli.ListObjects(ctx).Body(fgaclient.ClientListObjectsRequest{ Type: "project", Relation: role.String(), diff --git a/internal/authz/authz_test.go b/internal/authz/authz_test.go index c1f455bb35..f1f72ec0ae 100644 --- a/internal/authz/authz_test.go +++ b/internal/authz/authz_test.go @@ -54,7 +54,7 @@ func TestAllRolesExistInFGAModel(t *testing.T) { t.Logf("relations: %v", projectTypeDef.Relations) - for _, r := range authz.AllRoles { + for r := range authz.AllRoles { assert.Contains(t, *projectTypeDef.Relations, r.String(), "role %s not found in authz model", r) } } diff --git a/internal/authz/interface.go b/internal/authz/interface.go index 572ec8f7a3..1ee3e4a40d 100644 --- a/internal/authz/interface.go +++ b/internal/authz/interface.go @@ -44,12 +44,16 @@ const ( var ( // AllRoles is a list of all roles - AllRoles = []Role{ - AuthzRoleAdmin, - AuthzRoleEditor, - AuthzRoleViewer, - AuthzRolePolicyWriter, - AuthzRolePermissionsManager, + AllRoles = map[Role]string{ + AuthzRoleAdmin: "The admin role allows the user to perform all actions on the project and " + + "sub-projects.", + AuthzRoleEditor: "The editor role allows for more write and read actions on the project and " + + "sub-projects except for project administration.", + AuthzRoleViewer: "The viewer role allows for read actions on the project and sub-projects.", + AuthzRolePolicyWriter: "The policy_writer role allows for writing policies (rule types and " + + "profiles) on the project and sub-projects. This is handy for CI jobs.", + AuthzRolePermissionsManager: "The permissions_manager role allows for managing permissions " + + "on the project and sub-projects.", } ) diff --git a/internal/controlplane/handlers_authz.go b/internal/controlplane/handlers_authz.go index 475305645c..a0b73fa283 100644 --- a/internal/controlplane/handlers_authz.go +++ b/internal/controlplane/handlers_authz.go @@ -28,6 +28,7 @@ import ( "google.golang.org/grpc/status" "github.com/stacklok/minder/internal/auth" + "github.com/stacklok/minder/internal/authz" "github.com/stacklok/minder/internal/db" "github.com/stacklok/minder/internal/engine" "github.com/stacklok/minder/internal/logger" @@ -236,3 +237,40 @@ func requiresProjectAuthorization(opts *minder.RpcOptions) bool { return !opts.Anonymous && opts.GetAuthScope() != minder.ObjectOwner_OBJECT_OWNER_USER } + +// Permissions API +// ensure interface implementation +var _ minder.PermissionsServiceServer = (*Server)(nil) + +// ListRoles returns the list of available roles for the minder instance +func (*Server) ListRoles(_ context.Context, _ *minder.ListRolesRequest) (*minder.ListRolesResponse, error) { + resp := minder.ListRolesResponse{ + Roles: make([]*minder.Role, 0, len(authz.AllRoles)), + } + for role, desc := range authz.AllRoles { + resp.Roles = append(resp.Roles, &minder.Role{ + Name: role.String(), + Description: desc, + }) + } + + return &resp, nil +} + +// ListRoleAssignments returns the list of role assignments for the given project +func (*Server) ListRoleAssignments( + context.Context, + *minder.ListRoleAssignmentsRequest, +) (*minder.ListRoleAssignmentsResponse, error) { + return nil, nil +} + +// AssignRole assigns a role to a user on a project +func (*Server) AssignRole(context.Context, *minder.AssignRoleRequest) (*minder.AssignRoleResponse, error) { + return nil, nil +} + +// RemoveRole removes a role from a user on a project +func (*Server) RemoveRole(context.Context, *minder.RemoveRoleRequest) (*minder.RemoveRoleResponse, error) { + return nil, nil +} diff --git a/internal/controlplane/register_handlers.go b/internal/controlplane/register_handlers.go index 8437c2376c..52a9b068cb 100644 --- a/internal/controlplane/register_handlers.go +++ b/internal/controlplane/register_handlers.go @@ -56,6 +56,11 @@ func RegisterGatewayHTTPHandlers(ctx context.Context, gwmux *runtime.ServeMux, g if err := pb.RegisterArtifactServiceHandlerFromEndpoint(ctx, gwmux, grpcAddress, opts); err != nil { log.Fatal().Err(err).Msg("failed to register gateway") } + + // Register the Permissions service + if err := pb.RegisterPermissionsServiceHandlerFromEndpoint(ctx, gwmux, grpcAddress, opts); err != nil { + log.Fatal().Err(err).Msg("failed to register gateway") + } } // RegisterGRPCServices registers the GRPC services @@ -77,4 +82,7 @@ func RegisterGRPCServices(s *Server) { // Register the Artifact service pb.RegisterArtifactServiceServer(s.grpcServer, s) + + // Register the Permissions service + pb.RegisterPermissionsServiceServer(s.grpcServer, s) } diff --git a/internal/controlplane/server.go b/internal/controlplane/server.go index 0371308ac7..558c4880c0 100644 --- a/internal/controlplane/server.go +++ b/internal/controlplane/server.go @@ -66,24 +66,27 @@ var ( // Server represents the controlplane server type Server struct { - store db.Store - cfg *serverconfig.Config - evt *events.Eventer - mt *metrics - provMt provtelemetry.ProviderMetrics - grpcServer *grpc.Server - vldtr auth.JwtValidator + store db.Store + cfg *serverconfig.Config + evt *events.Eventer + mt *metrics + provMt provtelemetry.ProviderMetrics + grpcServer *grpc.Server + vldtr auth.JwtValidator + OAuth2 *oauth2.Config + ClientID string + ClientSecret string + authzClient authz.Client + cryptoEngine *crypto.Engine + + // Implementations for service registration pb.UnimplementedHealthServiceServer pb.UnimplementedOAuthServiceServer pb.UnimplementedUserServiceServer pb.UnimplementedRepositoryServiceServer pb.UnimplementedProfileServiceServer pb.UnimplementedArtifactServiceServer - OAuth2 *oauth2.Config - ClientID string - ClientSecret string - authzClient authz.Client - cryptoEngine *crypto.Engine + pb.UnimplementedPermissionsServiceServer } // ServerOption is a function that modifies a server