Skip to content

Commit

Permalink
feat(iamctl): add list-roles
Browse files Browse the repository at this point in the history
Listing all the predefined roles.
  • Loading branch information
odsod committed May 18, 2021
1 parent 9b91c2d commit 15d9b83
Show file tree
Hide file tree
Showing 10 changed files with 972 additions and 717 deletions.
58 changes: 32 additions & 26 deletions cmd/iamctl/internal/examplecmd/exampleservercmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,41 +9,44 @@ import (
"cloud.google.com/go/spanner"
"go.einride.tech/iam/iamauthz"
"go.einride.tech/iam/iamexample"
"go.einride.tech/iam/iamexample/iamexampledata"
"go.einride.tech/iam/iammember"
"go.einride.tech/iam/iammember/iamgooglemember"
"go.einride.tech/iam/iammixin"
"go.einride.tech/iam/iamregistry"
"go.einride.tech/iam/iamspanner"
iamexamplev1 "go.einride.tech/iam/proto/gen/einride/iam/example/v1"
"google.golang.org/genproto/googleapis/iam/admin/v1"
"google.golang.org/genproto/googleapis/iam/v1"
"google.golang.org/grpc"
)

func newServer(spannerClient *spanner.Client) (iamexamplev1.FreightServiceServer, error) {
roles, err := iamregistry.NewRoles(iamexampledata.PredefinedRoles())
iamDescriptor, err := iamexamplev1.NewFreightServiceIAMDescriptor()
if err != nil {
return nil, err
}
roles, err := iamregistry.NewRoles(iamDescriptor.PredefinedRoles)
if err != nil {
return nil, err
}
memberResolver := iammember.ChainResolvers(
// Resolve members from the example members header.
iamexample.NewIAMMemberHeaderResolver(),
// Resolve members from the authorization header.
iamgooglemember.ResolveAuthorizationHeader(googleUserInfoMemberResolver{}),
// Resolve members from the Cloud Endpoint UserInfo header.
iamgooglemember.ResolveUserInfoHeader(
iamgooglemember.GoogleCloudEndpointUserInfoHeader,
googleUserInfoMemberResolver{},
),
// Resolve members from the API Gateway UserInfo header.
iamgooglemember.ResolveUserInfoHeader(
iamgooglemember.GoogleCloudAPIGatewayUserInfoHeader,
googleUserInfoMemberResolver{},
),
)
iamServer, err := iamspanner.NewIAMServer(
spannerClient,
roles,
iammember.ChainResolvers(
// Resolve members from the example members header.
iamexample.NewIAMMemberHeaderResolver(),
// Resolve members from the authorization header.
iamgooglemember.ResolveAuthorizationHeader(googleUserInfoMemberResolver{}),
// Resolve members from the Cloud Endpoint UserInfo header.
iamgooglemember.ResolveUserInfoHeader(
iamgooglemember.GoogleCloudEndpointUserInfoHeader,
googleUserInfoMemberResolver{},
),
// Resolve members from the API Gateway UserInfo header.
iamgooglemember.ResolveUserInfoHeader(
iamgooglemember.GoogleCloudAPIGatewayUserInfoHeader,
googleUserInfoMemberResolver{},
),
),
memberResolver,
iamspanner.ServerConfig{
ErrorHook: func(ctx context.Context, err error) {
log.Println(err)
Expand All @@ -62,9 +65,15 @@ func newServer(spannerClient *spanner.Client) (iamexamplev1.FreightServiceServer
},
},
}
authorization, err := iamexamplev1.NewFreightServiceAuthorization(freightServer, iamServer, memberResolver)
if err != nil {
return nil, err
}
freightServerAuthorization := &iamexample.Authorization{
Next: freightServer,
IAMServer: iamServer,
FreightServiceAuthorization: authorization,
Next: freightServer,
IAMServer: iamServer,
IAMDescriptor: iamDescriptor,
}
return freightServerAuthorization, nil
}
Expand All @@ -89,10 +98,7 @@ func runServer(ctx context.Context, server iamexamplev1.FreightServiceServer, ad
),
grpc.StreamInterceptor(iamauthz.RequireStreamAuthorization),
)
iam.RegisterIAMPolicyServer(grpcServer, server)
if adminServer, ok := server.(admin.IAMServer); ok {
admin.RegisterIAMServer(grpcServer, adminServer)
}
iammixin.Register(grpcServer, server)
iamexamplev1.RegisterFreightServiceServer(grpcServer, server)
go func() {
<-ctx.Done()
Expand Down
1 change: 1 addition & 0 deletions cmd/iamctl/internal/rootcmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func init() {
Command.AddCommand(setIAMPolicyCommand)
Command.AddCommand(addIAMPolicyBindingCommand)
Command.AddCommand(removeIAMPolicyBindingCommand)
Command.AddCommand(listRolesCommand)
_ = connection.AddToFlagSet(Command.PersistentFlags())
Command.SetHelpCommand(&cobra.Command{
Use: "hidden-help",
Expand Down
77 changes: 77 additions & 0 deletions cmd/iamctl/internal/rootcmd/listroles.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package rootcmd

import (
"context"
"fmt"

"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.einride.tech/iam/cmd/iamctl/internal/connection"
"google.golang.org/genproto/googleapis/iam/admin/v1"
"google.golang.org/protobuf/encoding/protojson"
)

var listRolesCommand = &cobra.Command{
Use: "list-roles",
Short: "List IAM roles",
RunE: func(cmd *cobra.Command, args []string) error {
viperCfg := viper.New()
if err := viperCfg.BindPFlags(cmd.Flags()); err != nil {
return err
}
if err := viperCfg.BindPFlags(cmd.PersistentFlags()); err != nil {
return err
}
var flags listRolesFlags
if err := viperCfg.Unmarshal(&flags); err != nil {
return err
}
conn, err := flags.Connect(cmd.Context())
if err != nil {
return err
}
defer func() {
_ = conn.Close()
}()
client := admin.NewIAMClient(conn)
return runListRolesCommand(cmd.Context(), client, &flags)
},
}

type listRolesFlags struct {
connection.Flags `mapstructure:",squash"`
Full bool `mapstructure:"full"`
}

func init() {
listRolesCommand.Flags().Bool("full", false, "list full roles")
}

func runListRolesCommand(
ctx context.Context,
client admin.IAMClient,
flags *listRolesFlags,
) error {
var nextPageToken string
var view admin.RoleView
if flags.Full {
view = admin.RoleView_FULL
}
for {
response, err := client.ListRoles(ctx, &admin.ListRolesRequest{
PageToken: nextPageToken,
View: view,
})
if err != nil {
return err
}
for _, role := range response.Roles {
fmt.Println(protojson.Format(role))
}
nextPageToken = response.NextPageToken
if nextPageToken == "" {
break
}
}
return nil
}
9 changes: 9 additions & 0 deletions iamexample/server_iam.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package iamexample
import (
"context"

"google.golang.org/genproto/googleapis/iam/admin/v1"
"google.golang.org/genproto/googleapis/iam/v1"
)

Expand All @@ -29,3 +30,11 @@ func (s *Server) TestIamPermissions(
) (*iam.TestIamPermissionsResponse, error) {
return s.IAM.TestIamPermissions(ctx, request)
}

// ListRoles implements admin.IAMServer.
func (s *Server) ListRoles(
ctx context.Context,
request *admin.ListRolesRequest,
) (*admin.ListRolesResponse, error) {
return s.IAM.ListRoles(ctx, request)
}
2 changes: 2 additions & 0 deletions iammixin/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Package iammixin provides utilities for registering gRPC servers with IAM mixins.
package iammixin
59 changes: 59 additions & 0 deletions iammixin/register.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package iammixin

import (
"context"

"google.golang.org/genproto/googleapis/iam/admin/v1"
"google.golang.org/genproto/googleapis/iam/v1"
"google.golang.org/grpc"
)

// Server is an interface for servers that implement the essential IAM mixins.
type Server interface {
iam.IAMPolicyServer
ListRoles(context.Context, *admin.ListRolesRequest) (*admin.ListRolesResponse, error)
}

// Register the IAM mixin server with the provided gRPC server.
func Register(server *grpc.Server, serverImpl Server) {
iam.RegisterIAMPolicyServer(server, serverImpl)
admin.RegisterIAMServer(server, &adminAdapter{server: serverImpl})
}

// adminAdapter provides unimplemented methods for the non-essential IAM admin mixins.
type adminAdapter struct {
admin.UnimplementedIAMServer
server Server
}

// ListRoles implements admin.IAMServer.
func (a *adminAdapter) ListRoles(
ctx context.Context,
request *admin.ListRolesRequest,
) (*admin.ListRolesResponse, error) {
return a.server.ListRoles(ctx, request)
}

// SetIamPolicy implements admin.IAMServer.
func (a *adminAdapter) SetIamPolicy(
ctx context.Context,
request *iam.SetIamPolicyRequest,
) (*iam.Policy, error) {
return a.server.SetIamPolicy(ctx, request)
}

// GetIamPolicy implements admin.IAMServer.
func (a *adminAdapter) GetIamPolicy(
ctx context.Context,
request *iam.GetIamPolicyRequest,
) (*iam.Policy, error) {
return a.server.GetIamPolicy(ctx, request)
}

// TestIamPermissions implements admin.IAMServer.
func (a *adminAdapter) TestIamPermissions(
ctx context.Context,
request *iam.TestIamPermissionsRequest,
) (*iam.TestIamPermissionsResponse, error) {
return a.server.TestIamPermissions(ctx, request)
}
Loading

0 comments on commit 15d9b83

Please sign in to comment.