Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions api/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3423,6 +3423,30 @@ func (c *Client) GetApps(ctx context.Context) ([]types.Application, error) {
return apps, nil
}

// ListApps returns a page of application resources.
//
// Note that application resources here refers to "dynamically-added"
// applications such as applications created by `tctl create`, or the CreateApp
// API. Applications defined in the `app_service.apps` section of the service
// YAML configuration are not collected in this API.
//
// For a page of registered applications that are served by an application
// service, use ListResources instead.
func (c *Client) ListApps(ctx context.Context, limit int, start string) ([]types.Application, string, error) {
resp, err := c.grpc.ListApps(ctx, &proto.ListAppsRequest{
Limit: int32(limit),
StartKey: start,
})
if err != nil {
return nil, "", trace.Wrap(err)
}
apps := make([]types.Application, 0, len(resp.Applications))
for _, app := range resp.Applications {
apps = append(apps, app)
}
return apps, resp.NextKey, nil
}

// DeleteApp deletes specified application resource.
func (c *Client) DeleteApp(ctx context.Context, name string) error {
_, err := c.grpc.DeleteApp(ctx, &types.ResourceRequest{Name: name})
Expand Down
2,672 changes: 1,571 additions & 1,101 deletions api/client/proto/authservice.pb.go

Large diffs are not rendered by default.

40 changes: 40 additions & 0 deletions api/client/proto/authservice_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 21 additions & 1 deletion api/proto/teleport/legacy/client/proto/authservice.proto
Original file line number Diff line number Diff line change
Expand Up @@ -1601,6 +1601,24 @@ message ReplaceRemoteLocksRequest {
repeated types.LockV2 Locks = 2;
}

// ListAppsRequest is a request for a page of registered applications.
message ListAppsRequest {
// Limit is the maximum amount of resources to retrieve.
int32 limit = 1;
// StartKey is used to start listing resources from a specific spot. It
// should be set to the previous NextKey value if using pagination, or
// left empty.
string start_key = 2;
}

// ListAppsResponse contains a page of registered applications.
message ListAppsResponse {
// Applictaions is a list of applications.
repeated types.AppV3 applications = 1;
// NextKey is the key for the next page of applications.
string next_key = 2;
}

// GetWindowsDesktopServicesResponse contains all registered Windows desktop services.
message GetWindowsDesktopServicesResponse {
// Services is a list of Windows desktop services.
Expand Down Expand Up @@ -1650,7 +1668,7 @@ message ListWindowsDesktopsRequest {
message ListWindowsDesktopsResponse {
// Desktops is a list of Windows desktop hosts.
repeated types.WindowsDesktopV3 desktops = 1;
// NextKey is the key for the next page of SAML IdP service providers.
// NextKey is the key for the next page of desktops.
string next_key = 2;
}

Expand Down Expand Up @@ -3470,6 +3488,8 @@ service AuthService {

// GetApps returns all registered applications.
rpc GetApps(google.protobuf.Empty) returns (types.AppV3List);
// ListApps returns a page of registered applications.
rpc ListApps(ListAppsRequest) returns (ListAppsResponse);
// GetApp returns an application by name.
rpc GetApp(types.ResourceRequest) returns (types.AppV3);
// CreateApp creates a new application resource.
Expand Down
4 changes: 2 additions & 2 deletions lib/auth/accesspoint/accesspoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ type Config struct {
AccessLists services.AccessLists
AccessMonitoringRules services.AccessMonitoringRules
AppSession services.AppSession
Apps services.Apps
Applications services.Applications
BotInstance services.BotInstance
ClusterConfig services.ClusterConfiguration
CrownJewels services.CrownJewels
Expand Down Expand Up @@ -181,7 +181,7 @@ func NewCache(cfg Config) (*cache.Cache, error) {
AccessLists: cfg.AccessLists,
AccessMonitoringRules: cfg.AccessMonitoringRules,
AppSession: cfg.AppSession,
Apps: cfg.Apps,
Apps: cfg.Applications,
ClusterConfig: cfg.ClusterConfig,
AutoUpdateService: cfg.AutoUpdateService,
CrownJewels: cfg.CrownJewels,
Expand Down
4 changes: 2 additions & 2 deletions lib/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ func NewServer(cfg *InitConfig, opts ...ServerOption) (*Server, error) {
ClusterConfigurationInternal: cfg.ClusterConfiguration,
AutoUpdateService: cfg.AutoUpdateService,
Restrictions: cfg.Restrictions,
Apps: cfg.Apps,
Applications: cfg.Apps,
Kubernetes: cfg.Kubernetes,
Databases: cfg.Databases,
DatabaseServices: cfg.DatabaseServices,
Expand Down Expand Up @@ -736,7 +736,7 @@ type Services struct {
services.DynamicAccessExt
services.ClusterConfigurationInternal
services.Restrictions
services.Apps
services.Applications
services.Kubernetes
services.Databases
services.DatabaseServices
Expand Down
59 changes: 59 additions & 0 deletions lib/auth/auth_with_roles.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"cmp"
"context"
"fmt"
"io"
"maps"
"net/url"
"os"
Expand Down Expand Up @@ -6406,6 +6407,64 @@ func (a *ServerWithRoles) GetApps(ctx context.Context) (result []types.Applicati
return result, nil
}

// ListApps returns a page of application resources.
func (a *ServerWithRoles) ListApps(ctx context.Context, limit int, startKey string) ([]types.Application, string, error) {
if err := a.action(apidefaults.Namespace, types.KindApp, types.VerbList, types.VerbRead); err != nil {
return nil, "", trace.Wrap(err)
}

if limit <= 0 || limit > apidefaults.DefaultChunkSize {
limit = apidefaults.DefaultChunkSize
}

var nextKey string
var count int
var done bool
results, err := stream.Collect(
stream.FilterMap(
stream.PageFunc(func() ([]types.Application, error) {
if done {
return nil, io.EOF
}
apps, next, err := a.authServer.ListApps(ctx, limit, startKey)
if err != nil {
return nil, trace.Wrap(err)
}

startKey = next
if next == "" {
done = true
}
return apps, nil
}),
func(app types.Application) (types.Application, bool) {
// Checking done here could cause loss of applications
// if there is only one page.
if nextKey != "" {
return nil, false
}

if err := a.checkAccessToApp(app); err != nil {
return nil, false
}

if count >= limit {
done = true
nextKey = app.GetName()
return nil, false
}

count++
return app, true
}),
)
if err != nil {
return nil, "", trace.Wrap(err)
}

return results, nextKey, nil
}

// DeleteApp removes the specified application resource.
func (a *ServerWithRoles) DeleteApp(ctx context.Context, name string) error {
if err := a.action(apidefaults.Namespace, types.KindApp, types.VerbDelete); err != nil {
Expand Down
37 changes: 37 additions & 0 deletions lib/auth/auth_with_roles_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3465,13 +3465,27 @@ func TestApps(t *testing.T) {
cmpopts.IgnoreFields(types.Metadata{}, "Revision"),
))

out, next, err := devClt.ListApps(ctx, 0, "")
require.NoError(t, err)
require.Empty(t, next)
require.Empty(t, cmp.Diff([]types.Application{devApp}, out,
cmpopts.IgnoreFields(types.Metadata{}, "Revision"),
))

// Admin should see both.
apps, err = adminClt.GetApps(ctx)
require.NoError(t, err)
require.Empty(t, cmp.Diff([]types.Application{adminApp, devApp}, apps,
cmpopts.IgnoreFields(types.Metadata{}, "Revision"),
))

out, next, err = adminClt.ListApps(ctx, 0, "")
require.NoError(t, err)
require.Empty(t, next)
require.Empty(t, cmp.Diff([]types.Application{adminApp, devApp}, out,
cmpopts.IgnoreFields(types.Metadata{}, "Revision"),
))

// Dev shouldn't be able to delete dev app...
err = devClt.DeleteApp(ctx, adminApp.GetName())
require.True(t, trace.IsAccessDenied(err))
Expand All @@ -3491,18 +3505,41 @@ func TestApps(t *testing.T) {
// Dev should only be able to delete dev app.
err = devClt.DeleteAllApps(ctx)
require.NoError(t, err)

apps, err = devClt.GetApps(ctx)
require.NoError(t, err)
require.Empty(t, apps)

out, next, err = devClt.ListApps(ctx, 0, "")
require.NoError(t, err)
require.Empty(t, out)
require.Empty(t, next)

apps, err = adminClt.GetApps(ctx)
require.NoError(t, err)
require.Empty(t, cmp.Diff([]types.Application{adminApp}, apps,
cmpopts.IgnoreFields(types.Metadata{}, "Revision"),
))

out, next, err = adminClt.ListApps(ctx, 0, "")
require.NoError(t, err)
require.Empty(t, next)
require.Empty(t, cmp.Diff([]types.Application{adminApp}, out,
cmpopts.IgnoreFields(types.Metadata{}, "Revision"),
))

// Admin should be able to delete all.
err = adminClt.DeleteAllApps(ctx)
require.NoError(t, err)

apps, err = adminClt.GetApps(ctx)
require.NoError(t, err)
require.Empty(t, apps)

out, next, err = adminClt.ListApps(ctx, 0, "")
require.NoError(t, err)
require.Empty(t, out)
require.Empty(t, next)
}

// TestReplaceRemoteLocksRBAC verifies that only a remote proxy may replace the
Expand Down
13 changes: 13 additions & 0 deletions lib/auth/authclient/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,9 @@ type ReadProxyAccessPoint interface {
// GetApps returns all application resources.
GetApps(ctx context.Context) ([]types.Application, error)

// ListApps returns a page of application resources.
ListApps(ctx context.Context, limit int, startKey string) ([]types.Application, string, error)

// GetApp returns the specified application resource.
GetApp(ctx context.Context, name string) (types.Application, error)

Expand Down Expand Up @@ -570,6 +573,9 @@ type ReadAppsAccessPoint interface {
// GetApps returns all application resources.
GetApps(ctx context.Context) ([]types.Application, error)

// ListApps returns a page of application resources.
ListApps(ctx context.Context, limit int, startKey string) ([]types.Application, string, error)

// GetApp returns the specified application resource.
GetApp(ctx context.Context, name string) (types.Application, error)
}
Expand Down Expand Up @@ -760,6 +766,10 @@ type ReadDiscoveryAccessPoint interface {

// GetApps returns all application resources.
GetApps(context.Context) ([]types.Application, error)

// ListApps returns a page of application resources.
ListApps(ctx context.Context, limit int, startKey string) ([]types.Application, string, error)

// GetApp returns the specified application resource.
GetApp(ctx context.Context, name string) (types.Application, error)

Expand Down Expand Up @@ -1055,6 +1065,9 @@ type Cache interface {
// GetApps returns all application resources.
GetApps(ctx context.Context) ([]types.Application, error)

// ListApps returns a page of application resources.
ListApps(ctx context.Context, limit int, startKey string) ([]types.Application, string, error)

// GetApp returns the specified application resource.
GetApp(ctx context.Context, name string) (types.Application, error)

Expand Down
2 changes: 1 addition & 1 deletion lib/auth/authclient/clt.go
Original file line number Diff line number Diff line change
Expand Up @@ -1596,7 +1596,7 @@ type ClientI interface {
services.DynamicAccess
services.DynamicAccessOracle
services.Restrictions
services.Apps
services.Applications
services.Databases
services.DatabaseServices
services.Kubernetes
Expand Down
Loading
Loading