Skip to content

Commit

Permalink
CR
Browse files Browse the repository at this point in the history
  • Loading branch information
rudream committed Jun 26, 2024
1 parent a6624ed commit 2bf04aa
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 44 deletions.
24 changes: 18 additions & 6 deletions lib/auth/notifications/notificationsv1/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,10 @@ func (s *Service) CreateGlobalNotification(ctx context.Context, req *notificatio

// CreateUserNotification creates a user-specific notification.
func (s *Service) CreateUserNotification(ctx context.Context, req *notificationsv1.CreateUserNotificationRequest) (*notificationsv1.Notification, error) {
if req.Username == "" {
return nil, trace.BadParameter("missing username")
}

authCtx, err := s.authorizer.Authorize(ctx)
if err != nil {
return nil, trace.Wrap(err)
Expand Down Expand Up @@ -532,6 +536,10 @@ func (s *Service) DeleteGlobalNotification(ctx context.Context, req *notificatio
return nil, trace.Wrap(err)
}

if err := authCtx.AuthorizeAdminActionAllowReusedMFA(); err != nil {
return nil, trace.Wrap(err)
}

if err := authCtx.CheckAccessToKind(types.KindNotification, types.VerbDelete); err != nil {
return nil, trace.Wrap(err)
}
Expand All @@ -547,6 +555,10 @@ func (s *Service) DeleteUserNotification(ctx context.Context, req *notifications
return nil, trace.Wrap(err)
}

if err := authCtx.AuthorizeAdminActionAllowReusedMFA(); err != nil {
return nil, trace.Wrap(err)
}

if err := authCtx.CheckAccessToKind(types.KindNotification, types.VerbDelete); err != nil {
return nil, trace.Wrap(err)
}
Expand All @@ -557,23 +569,23 @@ func (s *Service) DeleteUserNotification(ctx context.Context, req *notifications

// ListAllUserCreatedNotificationsForUser returns a paginated list of all user-created user-specific notifications for a user. This should only be used by admins.
func (s *Service) ListAllUserCreatedNotificationsForUser(ctx context.Context, req *notificationsv1.ListAllUserCreatedNotificationsForUserRequest) (*notificationsv1.ListNotificationsResponse, error) {
if req.Username == "" {
return nil, trace.BadParameter("missing username")
}

authCtx, err := s.authorizer.Authorize(ctx)
if err != nil {
return nil, trace.Wrap(err)
}

if !authz.HasBuiltinRole(*authCtx, string(types.RoleAdmin)) {
return nil, trace.AccessDenied("only users with the admin role can list notifications for another user")
return nil, trace.AccessDenied("only RoleAdmin can list notifications for a specific user")
}

if err := authCtx.CheckAccessToKind(types.KindNotification, types.VerbList); err != nil {
return nil, trace.Wrap(err)
}

if req.Username == "" {
return nil, trace.BadParameter("missing username")
}

stream := stream.FilterMap(
s.userNotificationCache.StreamUserNotifications(ctx, req.Username, req.PageToken),
func(n *notificationsv1.Notification) (*notificationsv1.Notification, bool) {
Expand Down Expand Up @@ -613,7 +625,7 @@ func (s *Service) ListAllUserCreatedGlobalNotifications(ctx context.Context, req
}

if !authz.HasBuiltinRole(*authCtx, string(types.RoleAdmin)) {
return nil, trace.AccessDenied("only users with the admin role can list all global notifications")
return nil, trace.AccessDenied("only RoleAdmin can list all global notifications")
}

stream := stream.FilterMap(
Expand Down
2 changes: 1 addition & 1 deletion lib/web/ui/labels.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func makeLabels(labelMaps ...map[string]string) []Label {
return labels
}

// makeLabelsIncludingInternalis a function that transforms map[string]string arguments passed to it to sorted slice of Labels, including Teleport internal labels.
// makeLabelsIncludingInternalis transforms map[string]string arguments passed to it to sorted slice of Labels, including Teleport internal labels.
func makeLabelsIncludingInternal(labelMaps ...map[string]string) []Label {
length := 0
for _, labelMap := range labelMaps {
Expand Down
7 changes: 0 additions & 7 deletions tool/tctl/common/cmds.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,6 @@ func Commands() []CLICommand {
&accessmonitoring.Command{},
&plugin.PluginsCommand{},
&NotificationCommand{},
}
}

// OSSCommands returns the oss variants of commands that use different variants
// for oss and ent.
func OSSCommands() []CLICommand {
return []CLICommand{
&configure.SSOConfigureCommand{},
&tester.SSOTestCommand{},
&fido2Command{},
Expand Down
54 changes: 25 additions & 29 deletions tool/tctl/common/notification_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"fmt"
"io"
"os"
"strings"
"time"

"github.com/alecthomas/kingpin/v2"
Expand All @@ -49,7 +48,7 @@ type NotificationCommand struct {

format string
user string
roles string
roles []string
requireAllRoles bool
warning bool

Expand All @@ -66,7 +65,7 @@ func (n *NotificationCommand) Initialize(app *kingpin.Application, _ *servicecfg

n.create = notif.Command("create", "Create a cluster notification.").Alias("add")
n.create.Flag("user", "Target a specific user.").StringVar(&n.user)
n.create.Flag("roles", "Target a specific set of roles. By default, this will target all users with any of the provided roles, use --require-all-roles to exclusively target users with all of them.").StringVar(&n.roles)
n.create.Flag("roles", "Target a specific set of roles. By default, this will target all users with any of the provided roles, use --require-all-roles to exclusively target users with all of them.").StringsVar(&n.roles)
n.create.Flag("require-all-roles", "Set whether this notification should target users who have all of the provided roles.").BoolVar(&n.requireAllRoles)
n.create.Flag("title", "Set the notification's title.").Short('t').Required().StringVar(&n.title)
n.create.Flag("content", "Set the notification's content.").Required().StringVar(&n.content)
Expand Down Expand Up @@ -95,7 +94,7 @@ func (n *NotificationCommand) TryRun(ctx context.Context, cmd string, client *au
case n.ls.FullCommand():
err = n.List(ctx, nc)
case n.rm.FullCommand():
err = n.Remove(ctx, nc)
err = n.Remove(ctx, client)
default:
return false, nil
}
Expand Down Expand Up @@ -127,7 +126,7 @@ func (n *NotificationCommand) Create(ctx context.Context, client *authclient.Cli
nc := client.NotificationServiceClient()

if n.user != "" {
if n.roles != "" || n.requireAllRoles {
if len(n.roles) != 0 || n.requireAllRoles {
return trace.BadParameter("roles cannot be configured for a notification which targets a specific user")
}

Expand All @@ -147,20 +146,18 @@ func (n *NotificationCommand) Create(ctx context.Context, client *authclient.Cli
return trail.FromGRPC(err)
}

fmt.Printf("\n\ncreated notification: \n%v\n", created)

fmt.Fprintf(n.stdout, "Created notification %s for user %s\n", created.GetMetadata().GetName(), n.user)
return nil
}

if n.roles != "" {
if len(n.roles) != 0 {
created, err := nc.CreateGlobalNotification(ctx, &notificationspb.CreateGlobalNotificationRequest{
GlobalNotification: &notificationspb.GlobalNotification{
Kind: types.KindGlobalNotification,
Spec: &notificationspb.GlobalNotificationSpec{
Matcher: &notificationspb.GlobalNotificationSpec_ByRoles{
ByRoles: &notificationspb.ByRoles{
Roles: n.splitRoles(),
Roles: n.roles,
},
},
MatchAllConditions: n.requireAllRoles,
Expand Down Expand Up @@ -208,7 +205,6 @@ func (n *NotificationCommand) Create(ctx context.Context, client *authclient.Cli
},
},
})

if err != nil {
return trail.FromGRPC(err)
}
Expand Down Expand Up @@ -251,11 +247,11 @@ func (n *NotificationCommand) List(ctx context.Context, client notificationspb.N
}
}

displayNotifications(n.format, result)
displayNotifications(n.format, result, n.stdout)
return nil
}

func displayNotifications(format string, notifications []*notificationspb.Notification) {
func displayNotifications(format string, notifications []*notificationspb.Notification, w io.Writer) {
switch format {
case teleport.Text:
var rows [][]string
Expand All @@ -268,41 +264,41 @@ func displayNotifications(format string, notifications []*notificationspb.Notifi
})
}
table := asciitable.MakeTableWithTruncatedColumn([]string{"ID", "Created", "Expires", "Title"}, rows, "Title")
fmt.Println(table.AsBuffer().String())
fmt.Fprint(w, table.AsBuffer().String())
case teleport.JSON:
utils.WriteJSONArray(os.Stdout, notifications)
utils.WriteJSONArray(w, notifications)
case teleport.YAML:
utils.WriteYAML(os.Stdout, notifications)
utils.WriteYAML(w, notifications)
default:
// Do nothing, kingpin validates the --format flag before we ever get here.
}
}

// Remove removes a notification.
func (n *NotificationCommand) Remove(ctx context.Context, client notificationspb.NotificationServiceClient) error {
func (n *NotificationCommand) Remove(ctx context.Context, client *authclient.Client) error {
var err error

// Prompt for admin action MFA re-auth.
mfaResponse, err := mfa.PerformAdminActionMFACeremony(ctx, client.PerformMFACeremony, true /*allowReuse*/)
if err == nil {
ctx = mfa.ContextWithMFAResponse(ctx, mfaResponse)
} else if !errors.Is(err, &mfa.ErrMFANotRequired) && !errors.Is(err, &mfa.ErrMFANotSupported) {
return trace.Wrap(err)
}

nc := client.NotificationServiceClient()

switch {
case n.user != "":
_, err = client.DeleteUserNotification(ctx, &notificationspb.DeleteUserNotificationRequest{
_, err = nc.DeleteUserNotification(ctx, &notificationspb.DeleteUserNotificationRequest{
Username: n.user,
NotificationId: n.title,
})
default:
_, err = client.DeleteGlobalNotification(ctx, &notificationspb.DeleteGlobalNotificationRequest{
_, err = nc.DeleteGlobalNotification(ctx, &notificationspb.DeleteGlobalNotificationRequest{
NotificationId: n.title,
})
}

return trail.FromGRPC(err)
}

func (n *NotificationCommand) splitRoles() []string {
var roles []string
for _, s := range strings.Split(n.roles, ",") {
if s == "" {
continue
}
roles = append(roles, s)
}
return roles
}
2 changes: 1 addition & 1 deletion tool/tctl/common/notification_command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func TestNotificationCommmandCRUD(t *testing.T) {
// Test creating a global notification for users with the test-1 role.
buf, err = runNotificationsCommand(t, clt, []string{"create", "--roles", "test-1", "--title", "test-1 role test notification", "--content", "This is a test notification."})
require.NoError(t, err)
require.Contains(t, buf.String(), "for users with one or more of the following roles: test-1")
require.Contains(t, buf.String(), "for users with one or more of the following roles: [test-1]")
globalNotificationId := strings.Split(buf.String(), " ")[2]

// List notifications for auditor and verify output.
Expand Down

0 comments on commit 2bf04aa

Please sign in to comment.