Skip to content

Commit

Permalink
Initial implementation of user management
Browse files Browse the repository at this point in the history
Signed-off-by: Radoslav Dimitrov <[email protected]>
  • Loading branch information
rdimitrov committed Jun 18, 2024
1 parent 54c62db commit 6b4b815
Show file tree
Hide file tree
Showing 22 changed files with 1,924 additions and 988 deletions.
9 changes: 7 additions & 2 deletions .mk/identity.mk
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,10 @@ endif

password-login:
@echo "Setting up password login..."
@$(CONTAINER) exec -it keycloak_container /opt/keycloak/bin/kcadm.sh create users -r stacklok -s username=testuser -s enabled=true
@$(CONTAINER) exec -it keycloak_container /opt/keycloak/bin/kcadm.sh set-password -r stacklok --username testuser --new-password tester
@$(CONTAINER) exec -it keycloak_container /opt/keycloak/bin/kcadm.sh create users -r stacklok -s username=testuser -s enabled=true -s [email protected]
@$(CONTAINER) exec -it keycloak_container /opt/keycloak/bin/kcadm.sh set-password -r stacklok --username testuser --new-password tester

password-login-2:
@echo "Setting up password login..."
@$(CONTAINER) exec -it keycloak_container /opt/keycloak/bin/kcadm.sh create users -r stacklok -s username=testuser2 -s enabled=true -s [email protected]
@$(CONTAINER) exec -it keycloak_container /opt/keycloak/bin/kcadm.sh set-password -r stacklok --username testuser2 --new-password tester
2 changes: 1 addition & 1 deletion cmd/cli/app/auth/invite/invite_accept.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ var inviteAcceptCmd = &cobra.Command{
Args: cobra.ExactArgs(1),
}

// inviteAcceptCommand is the whoami subcommand
// inviteAcceptCommand is the invite accept subcommand
func inviteAcceptCommand(ctx context.Context, cmd *cobra.Command, args []string, conn *grpc.ClientConn) error {
client := minderv1.NewUserServiceClient(conn)
code := args[0]
Expand Down
2 changes: 1 addition & 1 deletion cmd/cli/app/auth/invite/invite_decline.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ var inviteDeclineCmd = &cobra.Command{
Args: cobra.ExactArgs(1),
}

// inviteAcceptCommand is the whoami subcommand
// inviteDeclineCommand is the invite decline subcommand
func inviteDeclineCommand(ctx context.Context, cmd *cobra.Command, args []string, conn *grpc.ClientConn) error {
client := minderv1.NewUserServiceClient(conn)
code := args[0]
Expand Down
90 changes: 90 additions & 0 deletions cmd/cli/app/auth/invite/invite_get.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//
// Copyright 2023 Stacklok, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package invite provides the auth invite command for the minder CLI.
package invite

import (
"context"
"fmt"
"strings"
"time"

"github.com/spf13/cobra"
"github.com/spf13/viper"
"google.golang.org/grpc"

"github.com/stacklok/minder/cmd/cli/app"
"github.com/stacklok/minder/internal/util"
"github.com/stacklok/minder/internal/util/cli"
"github.com/stacklok/minder/internal/util/cli/table"
"github.com/stacklok/minder/internal/util/cli/table/layouts"
minderv1 "github.com/stacklok/minder/pkg/api/protobuf/go/minder/v1"
)

// inviteGetCmd represents the list command
var inviteGetCmd = &cobra.Command{
Hidden: true, // TODO: This hides the command, remove it once it's implemented
Use: "get",
Short: "Get info about pending invitations",
Long: `Get shows additional information about a pending invitation`,
RunE: cli.GRPCClientWrapRunE(inviteGetCommand),
Args: cobra.ExactArgs(1),
}

// inviteGetCommand is the invite get subcommand
func inviteGetCommand(ctx context.Context, cmd *cobra.Command, args []string, conn *grpc.ClientConn) error {
client := minderv1.NewInviteServiceClient(conn)

// No longer print usage on returned error, since we've parsed our inputs
// See https://github.com/spf13/cobra/issues/340#issuecomment-374617413
cmd.SilenceUsage = true
format := viper.GetString("output")

res, err := client.GetInviteDetails(ctx, &minderv1.GetInviteDetailsRequest{
Code: args[0],
})
if err != nil {
return cli.MessageAndError("Error getting info for invitation", err)
}

switch format {
case app.JSON:
out, err := util.GetJsonFromProto(res)
if err != nil {
return cli.MessageAndError("Error getting json from proto", err)
}
cmd.Println(out)
case app.YAML:
out, err := util.GetYamlFromProto(res)
if err != nil {
return cli.MessageAndError("Error getting yaml from proto", err)
}
cmd.Println(out)
case app.Table:
t := table.New(table.Simple, layouts.Default, []string{"Sponsor", "Project", "Expires"})
t.AddRow(res.SponsorDisplay, res.ProjectDisplay, res.ExpiresAt.AsTime().Format(time.RFC3339))
t.Render()
default:
return fmt.Errorf("unsupported output format: %s", format)
}
return nil
}

func init() {
inviteCmd.AddCommand(inviteGetCmd)
inviteGetCmd.Flags().StringP("output", "o", app.Table,
fmt.Sprintf("Output format (one of %s)", strings.Join(app.SupportedOutputFormats(), ",")))
}
6 changes: 4 additions & 2 deletions cmd/cli/app/auth/invite/invite_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ func inviteListCommand(ctx context.Context, cmd *cobra.Command, _ []string, conn
// No longer print usage on returned error, since we've parsed our inputs
// See https://github.com/spf13/cobra/issues/340#issuecomment-374617413
cmd.SilenceUsage = true

format := viper.GetString("output")

res, err := client.ListInvitations(ctx, &minderv1.ListInvitationsRequest{})
Expand All @@ -72,6 +71,10 @@ func inviteListCommand(ctx context.Context, cmd *cobra.Command, _ []string, conn
}
cmd.Println(out)
case app.Table:
if len(res.Invitations) == 0 {
cmd.Println("No pending invitations")
return nil
}
t := table.New(table.Simple, layouts.Default, []string{"Sponsor", "Project", "Role", "Expires", "Code"})
for _, v := range res.Invitations {
t.AddRow(v.SponsorDisplay, v.Project, v.Role, v.ExpiresAt.AsTime().Format(time.RFC3339), v.Code)
Expand All @@ -85,7 +88,6 @@ func inviteListCommand(ctx context.Context, cmd *cobra.Command, _ []string, conn

func init() {
inviteCmd.AddCommand(inviteListCmd)

inviteListCmd.Flags().StringP("output", "o", app.Table,
fmt.Sprintf("Output format (one of %s)", strings.Join(app.SupportedOutputFormats(), ",")))
}
35 changes: 24 additions & 11 deletions cmd/cli/app/project/role/role_deny.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,37 +42,50 @@ func DenyCommand(ctx context.Context, cmd *cobra.Command, _ []string, conn *grpc
sub := viper.GetString("sub")
r := viper.GetString("role")
project := viper.GetString("project")
email := viper.GetString("email")

// No longer print usage on returned error, since we've parsed our inputs
// See https://github.com/spf13/cobra/issues/340#issuecomment-374617413
cmd.SilenceUsage = true

roleAssignment := &minderv1.RoleAssignment{
Role: r,
Subject: sub,
}
failMsg := "Error denying role"
successMsg := "Denied role successfully."
// Only send an email if one is provided
if email != "" {
roleAssignment = &minderv1.RoleAssignment{
Role: r,
Email: email,
}
failMsg = "Error deleting an invite"
successMsg = "Invite deleted successfully."
}

_, err := client.RemoveRole(ctx, &minderv1.RemoveRoleRequest{
Context: &minderv1.Context{
Project: &project,
},
RoleAssignment: &minderv1.RoleAssignment{
Role: r,
Subject: sub,
},
RoleAssignment: roleAssignment,
})
if err != nil {
return cli.MessageAndError("Error denying role", err)
return cli.MessageAndError(failMsg, err)
}

cmd.Println("Denied role successfully.")
cmd.Println(successMsg)
return nil
}

func init() {
RoleCmd.AddCommand(denyCmd)

denyCmd.Flags().StringP("sub", "s", "", "subject to grant access to")
denyCmd.Flags().StringP("role", "r", "", "the role to grant")
if err := denyCmd.MarkFlagRequired("sub"); err != nil {
denyCmd.Print("Error marking `sub` flag as required.")
os.Exit(1)
}
denyCmd.Flags().StringP("sub", "s", "", "subject to grant access to")
denyCmd.Flags().StringP("email", "e", "", "email to send invitation to")
denyCmd.MarkFlagsOneRequired("sub", "email")
denyCmd.MarkFlagsMutuallyExclusive("sub", "email")
if err := denyCmd.MarkFlagRequired("role"); err != nil {
denyCmd.Print("Error marking `role` flag as required.")
os.Exit(1)
Expand Down
39 changes: 28 additions & 11 deletions cmd/cli/app/project/role/role_grant.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,25 +42,43 @@ func GrantCommand(ctx context.Context, cmd *cobra.Command, _ []string, conn *grp
sub := viper.GetString("sub")
r := viper.GetString("role")
project := viper.GetString("project")
email := viper.GetString("email")

// No longer print usage on returned error, since we've parsed our inputs
// See https://github.com/spf13/cobra/issues/340#issuecomment-374617413
cmd.SilenceUsage = true

_, err := client.AssignRole(ctx, &minderv1.AssignRoleRequest{
roleAssignment := &minderv1.RoleAssignment{
Role: r,
Subject: sub,
}
failMsg := "Error granting role"
successMsg := "Granted role successfully."
// Only send an email if one is provided
if email != "" {
roleAssignment = &minderv1.RoleAssignment{
Role: r,
Email: email,
}
failMsg = "Error creating an invite"
successMsg = "Invite created successfully."
}

ret, err := client.AssignRole(ctx, &minderv1.AssignRoleRequest{
Context: &minderv1.Context{
Project: &project,
},
RoleAssignment: &minderv1.RoleAssignment{
Role: r,
Subject: sub,
},
RoleAssignment: roleAssignment,
})
if err != nil {
return cli.MessageAndError("Error granting role", err)
return cli.MessageAndError(failMsg, err)
}

cmd.Println("Granted role successfully.")
cmd.Println(successMsg)

if ret.Invitation != nil && ret.Invitation.Code != "" {
cmd.Printf("You can accept it by running: \n\nminder auth invite accept %s\n", ret.Invitation.Code)
}
return nil
}

Expand All @@ -69,10 +87,9 @@ func init() {

grantCmd.Flags().StringP("sub", "s", "", "subject to grant access to")
grantCmd.Flags().StringP("role", "r", "", "the role to grant")
if err := grantCmd.MarkFlagRequired("sub"); err != nil {
grantCmd.Print("Error marking `sub` flag as required.")
os.Exit(1)
}
grantCmd.Flags().StringP("email", "e", "", "email to send invitation to")
grantCmd.MarkFlagsOneRequired("sub", "email")
grantCmd.MarkFlagsMutuallyExclusive("sub", "email")
if err := grantCmd.MarkFlagRequired("role"); err != nil {
grantCmd.Print("Error marking `role` flag as required.")
os.Exit(1)
Expand Down
Loading

0 comments on commit 6b4b815

Please sign in to comment.