github.com/gravitational/teleport/api@v0.0.0-20240507183017-3110591cbafc/client/client.go (about)

     1  /*
     2  Copyright 2020-2022 Gravitational, Inc.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package client
    18  
    19  import (
    20  	"cmp"
    21  	"compress/gzip"
    22  	"context"
    23  	"crypto/tls"
    24  	"errors"
    25  	"fmt"
    26  	"io"
    27  	"log/slog"
    28  	"net"
    29  	"slices"
    30  	"sync"
    31  	"sync/atomic"
    32  	"time"
    33  
    34  	"github.com/coreos/go-semver/semver"
    35  	"github.com/gravitational/trace"
    36  	"github.com/jonboulle/clockwork"
    37  	"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
    38  	"golang.org/x/crypto/ssh"
    39  	"google.golang.org/grpc"
    40  	"google.golang.org/grpc/connectivity"
    41  	"google.golang.org/grpc/credentials"
    42  	ggzip "google.golang.org/grpc/encoding/gzip"
    43  	"google.golang.org/grpc/keepalive"
    44  	gmetadata "google.golang.org/grpc/metadata"
    45  	"google.golang.org/protobuf/types/known/durationpb"
    46  	"google.golang.org/protobuf/types/known/emptypb"
    47  	"google.golang.org/protobuf/types/known/timestamppb"
    48  
    49  	"github.com/gravitational/teleport/api/breaker"
    50  	"github.com/gravitational/teleport/api/client/accesslist"
    51  	"github.com/gravitational/teleport/api/client/accessmonitoringrules"
    52  	"github.com/gravitational/teleport/api/client/crownjewel"
    53  	crownjewelapi "github.com/gravitational/teleport/api/client/crownjewel"
    54  	"github.com/gravitational/teleport/api/client/discoveryconfig"
    55  	"github.com/gravitational/teleport/api/client/externalauditstorage"
    56  	kubewaitingcontainerclient "github.com/gravitational/teleport/api/client/kubewaitingcontainer"
    57  	"github.com/gravitational/teleport/api/client/okta"
    58  	"github.com/gravitational/teleport/api/client/proto"
    59  	"github.com/gravitational/teleport/api/client/scim"
    60  	"github.com/gravitational/teleport/api/client/secreport"
    61  	"github.com/gravitational/teleport/api/client/userloginstate"
    62  	"github.com/gravitational/teleport/api/constants"
    63  	"github.com/gravitational/teleport/api/defaults"
    64  	"github.com/gravitational/teleport/api/gen/proto/go/assist/v1"
    65  	accesslistv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/accesslist/v1"
    66  	accessmonitoringrulev1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/accessmonitoringrules/v1"
    67  	auditlogpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/auditlog/v1"
    68  	clusterconfigpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/clusterconfig/v1"
    69  	crownjewelv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/crownjewel/v1"
    70  	dbobjectv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/dbobject/v1"
    71  	dbobjectimportrulev1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/dbobjectimportrule/v1"
    72  	devicepb "github.com/gravitational/teleport/api/gen/proto/go/teleport/devicetrust/v1"
    73  	discoveryconfigv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/discoveryconfig/v1"
    74  	externalauditstoragev1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/externalauditstorage/v1"
    75  	integrationpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/integration/v1"
    76  	kubeproto "github.com/gravitational/teleport/api/gen/proto/go/teleport/kube/v1"
    77  	kubewaitingcontainerpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/kubewaitingcontainer/v1"
    78  	loginrulepb "github.com/gravitational/teleport/api/gen/proto/go/teleport/loginrule/v1"
    79  	machineidv1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/machineid/v1"
    80  	oktapb "github.com/gravitational/teleport/api/gen/proto/go/teleport/okta/v1"
    81  	pluginspb "github.com/gravitational/teleport/api/gen/proto/go/teleport/plugins/v1"
    82  	presencepb "github.com/gravitational/teleport/api/gen/proto/go/teleport/presence/v1"
    83  	resourceusagepb "github.com/gravitational/teleport/api/gen/proto/go/teleport/resourceusage/v1"
    84  	samlidppb "github.com/gravitational/teleport/api/gen/proto/go/teleport/samlidp/v1"
    85  	secreportsv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/secreports/v1"
    86  	trustpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/trust/v1"
    87  	userloginstatev1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/userloginstate/v1"
    88  	userspb "github.com/gravitational/teleport/api/gen/proto/go/teleport/users/v1"
    89  	userpreferencespb "github.com/gravitational/teleport/api/gen/proto/go/userpreferences/v1"
    90  	"github.com/gravitational/teleport/api/internalutils/stream"
    91  	"github.com/gravitational/teleport/api/metadata"
    92  	"github.com/gravitational/teleport/api/mfa"
    93  	"github.com/gravitational/teleport/api/observability/tracing"
    94  	"github.com/gravitational/teleport/api/types"
    95  	"github.com/gravitational/teleport/api/types/events"
    96  	"github.com/gravitational/teleport/api/types/wrappers"
    97  	"github.com/gravitational/teleport/api/utils"
    98  	"github.com/gravitational/teleport/api/utils/grpc/interceptors"
    99  )
   100  
   101  func init() {
   102  	// gzip is used for gRPC auditStream compression. SetLevel changes the
   103  	// compression level, must be called in initialization, and is not thread safe.
   104  	if err := ggzip.SetLevel(gzip.BestSpeed); err != nil {
   105  		panic(err)
   106  	}
   107  }
   108  
   109  // AuthServiceClient keeps the interfaces implemented by the auth service.
   110  type AuthServiceClient struct {
   111  	proto.AuthServiceClient
   112  	assist.AssistServiceClient
   113  	auditlogpb.AuditLogServiceClient
   114  	userpreferencespb.UserPreferencesServiceClient
   115  }
   116  
   117  // Client is a gRPC Client that connects to a Teleport Auth server either
   118  // locally or over ssh through a Teleport web proxy or tunnel proxy.
   119  //
   120  // This client can be used to cover a variety of Teleport use cases,
   121  // such as programmatically handling access requests, integrating
   122  // with external tools, or dynamically configuring Teleport.
   123  type Client struct {
   124  	// c contains configuration values for the client.
   125  	c Config
   126  	// tlsConfig is the *tls.Config for a successfully connected client.
   127  	tlsConfig *tls.Config
   128  	// dialer is the ContextDialer for a successfully connected client.
   129  	dialer ContextDialer
   130  	// conn is a grpc connection to the auth server.
   131  	conn *grpc.ClientConn
   132  	// grpc is the gRPC client specification for the auth server.
   133  	grpc AuthServiceClient
   134  	// JoinServiceClient is a client for the JoinService, which runs on both the
   135  	// auth and proxy.
   136  	*JoinServiceClient
   137  	// closedFlag is set to indicate that the connection is closed.
   138  	// It's a pointer to allow the Client struct to be copied.
   139  	closedFlag *int32
   140  }
   141  
   142  // New creates a new Client with an open connection to a Teleport server.
   143  //
   144  // New will try to open a connection with all combinations of addresses and credentials.
   145  // The first successful connection to a server will be used, or an aggregated error will
   146  // be returned if all combinations fail.
   147  //
   148  // cfg.Credentials must be non-empty. One of cfg.Addrs and cfg.Dialer must be non-empty,
   149  // unless LoadProfile is used to fetch Credentials and load a web proxy dialer.
   150  //
   151  // See the example below for usage.
   152  func New(ctx context.Context, cfg Config) (*Client, error) {
   153  	if err := cfg.CheckAndSetDefaults(); err != nil {
   154  		return nil, trace.Wrap(err)
   155  	}
   156  
   157  	// If cfg.DialInBackground is true, only a single connection is attempted.
   158  	// This option is primarily meant for internal use where the client has
   159  	// direct access to server values that guarantee a successful connection.
   160  	if cfg.DialInBackground {
   161  		return connectInBackground(ctx, cfg)
   162  	}
   163  
   164  	return connect(ctx, cfg)
   165  }
   166  
   167  // NewTracingClient creates a new tracing.Client that will forward spans to the
   168  // connected Teleport server. See New for details on how the connection it
   169  // established.
   170  func NewTracingClient(ctx context.Context, cfg Config) (*tracing.Client, error) {
   171  	clt, err := New(ctx, cfg)
   172  	if err != nil {
   173  		return nil, trace.Wrap(err)
   174  	}
   175  
   176  	return tracing.NewClient(clt.GetConnection()), nil
   177  }
   178  
   179  // NewOktaClient creates a new Okta client for managing Okta resources.
   180  func NewOktaClient(ctx context.Context, cfg Config) (*okta.Client, error) {
   181  	clt, err := New(ctx, cfg)
   182  	if err != nil {
   183  		return nil, trace.Wrap(err)
   184  	}
   185  	return okta.NewClient(oktapb.NewOktaServiceClient(clt.GetConnection())), nil
   186  }
   187  
   188  // newClient constructs a new client.
   189  func newClient(cfg Config, dialer ContextDialer, tlsConfig *tls.Config) *Client {
   190  	return &Client{
   191  		c:          cfg,
   192  		dialer:     dialer,
   193  		tlsConfig:  ConfigureALPN(tlsConfig, cfg.ALPNSNIAuthDialClusterName),
   194  		closedFlag: new(int32),
   195  	}
   196  }
   197  
   198  // connectInBackground connects the client to the server in the background.
   199  //
   200  // The client will use the first credentials and the given dialer.
   201  //
   202  // If no dialer is given, the first address will be used. If no
   203  // ALPNSNIAuthDialClusterName is given, this address must be an auth server
   204  // address.
   205  //
   206  // If ALPNSNIAuthDialClusterName is given, the address is expected to be a web
   207  // proxy address and the client will connect auth through the web proxy server
   208  // using TLS Routing.
   209  func connectInBackground(ctx context.Context, cfg Config) (*Client, error) {
   210  	tlsConfig, err := cfg.Credentials[0].TLSConfig()
   211  	if err != nil {
   212  		return nil, trace.Wrap(err)
   213  	}
   214  	if cfg.Dialer != nil {
   215  		return dialerConnect(ctx, connectParams{
   216  			cfg:       cfg,
   217  			tlsConfig: tlsConfig,
   218  			dialer:    cfg.Dialer,
   219  		})
   220  	} else if len(cfg.Addrs) != 0 {
   221  		return authConnect(ctx, connectParams{
   222  			cfg:       cfg,
   223  			tlsConfig: tlsConfig,
   224  			addr:      cfg.Addrs[0],
   225  		})
   226  	}
   227  	return nil, trace.BadParameter("must provide Dialer or Addrs in config")
   228  }
   229  
   230  // connect connects the client to the server using the Credentials and
   231  // Dialer/Addresses provided in the client's config. Multiple goroutines are started
   232  // to make dial attempts with different combinations of dialers and credentials. The
   233  // first client to successfully connect is used to populate the client's connection
   234  // attributes. If none successfully connect, an aggregated error is returned.
   235  func connect(ctx context.Context, cfg Config) (*Client, error) {
   236  	ctx, cancel := context.WithCancel(ctx)
   237  	defer cancel()
   238  	var wg sync.WaitGroup
   239  
   240  	// sendError is used to send errors to errChan with context.
   241  	errChan := make(chan error)
   242  	sendError := func(err error) {
   243  		errChan <- trace.Wrap(err)
   244  	}
   245  
   246  	// syncConnect is used to concurrently create multiple clients
   247  	// with the different combination of connection parameters.
   248  	// The first successful client to be sent to cltChan will be returned.
   249  	cltChan := make(chan *Client)
   250  	syncConnect := func(ctx context.Context, connect connectFunc, params connectParams) {
   251  		wg.Add(1)
   252  		go func() {
   253  			defer wg.Done()
   254  			clt, err := connect(ctx, params)
   255  			if err != nil {
   256  				sendError(trace.Wrap(err))
   257  				return
   258  			}
   259  			select {
   260  			case cltChan <- clt:
   261  			case <-ctx.Done():
   262  				clt.Close()
   263  			}
   264  		}()
   265  	}
   266  
   267  	wg.Add(1)
   268  	go func() {
   269  		defer wg.Done()
   270  
   271  		// Connect with provided credentials.
   272  		for _, creds := range cfg.Credentials {
   273  			tlsConfig, err := creds.TLSConfig()
   274  			if err != nil {
   275  				sendError(trace.Wrap(err))
   276  				continue
   277  			}
   278  
   279  			sshConfig, err := creds.SSHClientConfig()
   280  			if err != nil && !trace.IsNotImplemented(err) {
   281  				sendError(trace.Wrap(err))
   282  				continue
   283  			}
   284  
   285  			// Connect with dialer provided in config.
   286  			if cfg.Dialer != nil {
   287  				syncConnect(ctx, dialerConnect, connectParams{
   288  					cfg:       cfg,
   289  					tlsConfig: tlsConfig,
   290  				})
   291  			}
   292  
   293  			addrs := cfg.Addrs
   294  			if len(addrs) == 0 {
   295  				// If there's no explicitly specified address, fall back to
   296  				// an address provided by the credential, if it provides one.
   297  				credAddrSource, ok := creds.(CredentialsWithDefaultAddrs)
   298  				if ok {
   299  					addrs, err = credAddrSource.DefaultAddrs()
   300  					if err != nil {
   301  						sendError(trace.Wrap(err))
   302  						continue
   303  					}
   304  					slog.DebugContext(ctx, "No addresses were configured explicitly, falling back to addresses specified by credential. Consider explicitly configuring an address.", "address", addrs)
   305  				}
   306  			}
   307  
   308  			// Attempt to connect to each address as Auth, Proxy, Tunnel and TLS Routing.
   309  			for _, addr := range addrs {
   310  				syncConnect(ctx, authConnect, connectParams{
   311  					cfg:       cfg,
   312  					tlsConfig: tlsConfig,
   313  					addr:      addr,
   314  				})
   315  				if sshConfig != nil {
   316  					for _, cf := range []connectFunc{proxyConnect, tunnelConnect, tlsRoutingConnect, tlsRoutingWithConnUpgradeConnect} {
   317  						syncConnect(ctx, cf, connectParams{
   318  							cfg:       cfg,
   319  							tlsConfig: tlsConfig,
   320  							sshConfig: sshConfig,
   321  							addr:      addr,
   322  						})
   323  					}
   324  				}
   325  			}
   326  		}
   327  	}()
   328  
   329  	// Start goroutine to wait for wait group.
   330  	go func() {
   331  		wg.Wait()
   332  		// Close errChan to return errors.
   333  		close(errChan)
   334  	}()
   335  
   336  	var errs []error
   337  Outer:
   338  	for {
   339  		select {
   340  		// Use the first client to successfully connect in syncConnect.
   341  		case clt := <-cltChan:
   342  			go func() {
   343  				for range errChan {
   344  				}
   345  			}()
   346  			return clt, nil
   347  		case err, ok := <-errChan:
   348  			if !ok {
   349  				break Outer
   350  			}
   351  			// Add a new line to make errs human readable.
   352  			errs = append(errs, trace.Wrap(err, ""))
   353  		}
   354  	}
   355  
   356  	// errChan is closed, return errors.
   357  	if len(errs) == 0 {
   358  		if len(cfg.Addrs) == 0 && cfg.Dialer == nil {
   359  			// Some credentials don't require these fields. If no errors propagate, then they need to provide these fields.
   360  			return nil, trace.BadParameter("no connection methods found, try providing Dialer or Addrs in config")
   361  		}
   362  		// This case should never be reached with config validation and above case.
   363  		return nil, trace.Errorf("no connection methods found")
   364  	}
   365  	if ctx.Err() != nil {
   366  		errs = append(errs, trace.Wrap(ctx.Err()))
   367  	}
   368  	return nil, trace.Wrap(trace.NewAggregate(errs...), "all connection methods failed")
   369  }
   370  
   371  type (
   372  	connectFunc   func(ctx context.Context, params connectParams) (*Client, error)
   373  	connectParams struct {
   374  		cfg       Config
   375  		addr      string
   376  		tlsConfig *tls.Config
   377  		dialer    ContextDialer
   378  		sshConfig *ssh.ClientConfig
   379  	}
   380  )
   381  
   382  // authConnect connects to the Teleport Auth Server directly or through Proxy.
   383  func authConnect(ctx context.Context, params connectParams) (*Client, error) {
   384  	dialer := NewDialer(ctx, params.cfg.KeepAlivePeriod, params.cfg.DialTimeout,
   385  		WithInsecureSkipVerify(params.cfg.InsecureAddressDiscovery),
   386  		WithALPNConnUpgrade(params.cfg.ALPNConnUpgradeRequired),
   387  		WithALPNConnUpgradePing(true), // Use Ping protocol for long-lived connections.
   388  		WithPROXYHeaderGetter(params.cfg.PROXYHeaderGetter),
   389  	)
   390  
   391  	clt := newClient(params.cfg, dialer, params.tlsConfig)
   392  	if err := clt.dialGRPC(ctx, params.addr); err != nil {
   393  		return nil, trace.Wrap(err, "failed to connect to addr %v as an auth server", params.addr)
   394  	}
   395  	return clt, nil
   396  }
   397  
   398  // tunnelConnect connects to the Teleport Auth Server through the proxy's reverse tunnel.
   399  func tunnelConnect(ctx context.Context, params connectParams) (*Client, error) {
   400  	if params.sshConfig == nil {
   401  		return nil, trace.BadParameter("must provide ssh client config")
   402  	}
   403  	dialer := newTunnelDialer(*params.sshConfig, params.cfg.KeepAlivePeriod, params.cfg.DialTimeout, WithInsecureSkipVerify(params.cfg.InsecureAddressDiscovery))
   404  	clt := newClient(params.cfg, dialer, params.tlsConfig)
   405  	if err := clt.dialGRPC(ctx, params.addr); err != nil {
   406  		return nil, trace.Wrap(err, "failed to connect to addr %v as a reverse tunnel proxy", params.addr)
   407  	}
   408  	return clt, nil
   409  }
   410  
   411  // proxyConnect connects to the Teleport Auth Server through the proxy.
   412  // takes a specific addr parameter to allow the proxy address to be modified
   413  // when using special credentials.
   414  func proxyConnect(ctx context.Context, params connectParams) (*Client, error) {
   415  	if params.sshConfig == nil {
   416  		return nil, trace.BadParameter("must provide ssh client config")
   417  	}
   418  
   419  	dialer := NewProxyDialer(
   420  		*params.sshConfig,
   421  		params.cfg.KeepAlivePeriod,
   422  		params.cfg.DialTimeout,
   423  		params.addr,
   424  		params.cfg.InsecureAddressDiscovery,
   425  		WithInsecureSkipVerify(params.cfg.InsecureAddressDiscovery),
   426  	)
   427  	clt := newClient(params.cfg, dialer, params.tlsConfig)
   428  	if err := clt.dialGRPC(ctx, params.addr); err != nil {
   429  		return nil, trace.Wrap(err, "failed to connect to addr %v as a web proxy", params.addr)
   430  	}
   431  	return clt, nil
   432  }
   433  
   434  // tlsRoutingConnect connects to the Teleport Auth Server through the proxy using TLS Routing.
   435  func tlsRoutingConnect(ctx context.Context, params connectParams) (*Client, error) {
   436  	if params.sshConfig == nil {
   437  		return nil, trace.BadParameter("must provide ssh client config")
   438  	}
   439  	dialer := newTLSRoutingTunnelDialer(*params.sshConfig, params.cfg.KeepAlivePeriod, params.cfg.DialTimeout, params.addr, params.cfg.InsecureAddressDiscovery)
   440  	clt := newClient(params.cfg, dialer, params.tlsConfig)
   441  	if err := clt.dialGRPC(ctx, params.addr); err != nil {
   442  		return nil, trace.Wrap(err, "failed to connect to addr %v with TLS Routing dialer", params.addr)
   443  	}
   444  	return clt, nil
   445  }
   446  
   447  // tlsRoutingWithConnUpgradeConnect connects to the Teleport Auth Server
   448  // through the proxy using TLS Routing with ALPN connection upgrade.
   449  func tlsRoutingWithConnUpgradeConnect(ctx context.Context, params connectParams) (*Client, error) {
   450  	if params.sshConfig == nil {
   451  		return nil, trace.BadParameter("must provide ssh client config")
   452  	}
   453  	dialer := newTLSRoutingWithConnUpgradeDialer(*params.sshConfig, params)
   454  	clt := newClient(params.cfg, dialer, params.tlsConfig)
   455  	if err := clt.dialGRPC(ctx, params.addr); err != nil {
   456  		return nil, trace.Wrap(err, "failed to connect to addr %v with TLS Routing with ALPN connection upgrade dialer", params.addr)
   457  	}
   458  	return clt, nil
   459  }
   460  
   461  // dialerConnect connects to the Teleport Auth Server through a custom dialer.
   462  // The dialer must provide the address in a custom ContextDialerFunc function.
   463  func dialerConnect(ctx context.Context, params connectParams) (*Client, error) {
   464  	if params.dialer == nil {
   465  		if params.cfg.Dialer == nil {
   466  			return nil, trace.BadParameter("must provide dialer to connectParams.dialer or params.cfg.Dialer")
   467  		}
   468  		params.dialer = params.cfg.Dialer
   469  	}
   470  	clt := newClient(params.cfg, params.dialer, params.tlsConfig)
   471  	// Since the client uses a custom dialer to connect to the server and SNI
   472  	// is used for the TLS handshake, the address dialed here is arbitrary.
   473  	if err := clt.dialGRPC(ctx, constants.APIDomain); err != nil {
   474  		return nil, trace.Wrap(err, "failed to connect using pre-defined dialer")
   475  	}
   476  	return clt, nil
   477  }
   478  
   479  // dialGRPC dials a connection between server and client.
   480  func (c *Client) dialGRPC(ctx context.Context, addr string) error {
   481  	dialContext, cancel := context.WithTimeout(ctx, c.c.DialTimeout)
   482  	defer cancel()
   483  
   484  	cb, err := breaker.New(c.c.CircuitBreakerConfig)
   485  	if err != nil {
   486  		return trace.Wrap(err)
   487  	}
   488  
   489  	var dialOpts []grpc.DialOption
   490  	dialOpts = append(dialOpts, grpc.WithContextDialer(c.grpcDialer()))
   491  	dialOpts = append(dialOpts,
   492  		grpc.WithChainUnaryInterceptor(
   493  			otelUnaryClientInterceptor(),
   494  			metadata.UnaryClientInterceptor,
   495  			interceptors.GRPCClientUnaryErrorInterceptor,
   496  			interceptors.WithMFAUnaryInterceptor(c.PerformMFACeremony),
   497  			breaker.UnaryClientInterceptor(cb),
   498  		),
   499  		grpc.WithChainStreamInterceptor(
   500  			otelStreamClientInterceptor(),
   501  			metadata.StreamClientInterceptor,
   502  			interceptors.GRPCClientStreamErrorInterceptor,
   503  			breaker.StreamClientInterceptor(cb),
   504  		),
   505  	)
   506  	// Only set transportCredentials if tlsConfig is set. This makes it possible
   507  	// to explicitly provide grpc.WithTransportCredentials(insecure.NewCredentials())
   508  	// in the client's dial options.
   509  	if c.tlsConfig != nil {
   510  		dialOpts = append(dialOpts, grpc.WithTransportCredentials(credentials.NewTLS(c.tlsConfig)))
   511  	}
   512  	// must come last, otherwise provided opts may get clobbered by defaults above
   513  	dialOpts = append(dialOpts, c.c.DialOpts...)
   514  
   515  	conn, err := grpc.DialContext(dialContext, addr, dialOpts...)
   516  	if err != nil {
   517  		return trace.Wrap(err)
   518  	}
   519  
   520  	c.conn = conn
   521  	c.grpc = AuthServiceClient{
   522  		AuthServiceClient:            proto.NewAuthServiceClient(c.conn),
   523  		AssistServiceClient:          assist.NewAssistServiceClient(c.conn),
   524  		AuditLogServiceClient:        auditlogpb.NewAuditLogServiceClient(c.conn),
   525  		UserPreferencesServiceClient: userpreferencespb.NewUserPreferencesServiceClient(c.conn),
   526  	}
   527  	c.JoinServiceClient = NewJoinServiceClient(proto.NewJoinServiceClient(c.conn))
   528  
   529  	return nil
   530  }
   531  
   532  // We wrap the creation of the otelgrpc interceptors in a sync.Once - this is
   533  // because each time this is called, they create a new underlying metric. If
   534  // something (e.g tbot) is repeatedly creating new clients and closing them,
   535  // then this leads to a memory leak since the underlying metric is not cleaned
   536  // up.
   537  // See https://github.com/gravitational/teleport/issues/30759
   538  // See https://github.com/open-telemetry/opentelemetry-go-contrib/issues/4226
   539  var otelStreamClientInterceptor = sync.OnceValue(func() grpc.StreamClientInterceptor {
   540  	//nolint:staticcheck // SA1019. There is a data race in the stats.Handler that is replacing
   541  	// the interceptor. See https://github.com/open-telemetry/opentelemetry-go-contrib/issues/4576.
   542  	return otelgrpc.StreamClientInterceptor()
   543  })
   544  
   545  var otelUnaryClientInterceptor = sync.OnceValue(func() grpc.UnaryClientInterceptor {
   546  	//nolint:staticcheck // SA1019. There is a data race in the stats.Handler that is replacing
   547  	// the interceptor. See https://github.com/open-telemetry/opentelemetry-go-contrib/issues/4576.
   548  	return otelgrpc.UnaryClientInterceptor()
   549  })
   550  
   551  // ConfigureALPN configures ALPN SNI cluster routing information in TLS settings allowing for
   552  // allowing to dial auth service through Teleport Proxy directly without using SSH Tunnels.
   553  func ConfigureALPN(tlsConfig *tls.Config, clusterName string) *tls.Config {
   554  	if tlsConfig == nil {
   555  		return nil
   556  	}
   557  	if clusterName == "" {
   558  		return tlsConfig
   559  	}
   560  	out := tlsConfig.Clone()
   561  	routeInfo := fmt.Sprintf("%s%s", constants.ALPNSNIAuthProtocol, utils.EncodeClusterName(clusterName))
   562  	out.NextProtos = append([]string{routeInfo}, out.NextProtos...)
   563  	return out
   564  }
   565  
   566  // grpcDialer wraps the client's dialer with a grpcDialer.
   567  func (c *Client) grpcDialer() func(ctx context.Context, addr string) (net.Conn, error) {
   568  	return func(ctx context.Context, addr string) (net.Conn, error) {
   569  		if c.isClosed() {
   570  			return nil, trace.ConnectionProblem(nil, "client is closed")
   571  		}
   572  		conn, err := c.dialer.DialContext(ctx, "tcp", addr)
   573  		if err != nil {
   574  			return nil, trace.ConnectionProblem(err, "failed to dial: %v", err)
   575  		}
   576  		return conn, nil
   577  	}
   578  }
   579  
   580  // waitForConnectionReady waits for the client's grpc connection finish dialing, returning an error
   581  // if the ctx is canceled or the client's gRPC connection enters an unexpected state. This can be used
   582  // alongside the DialInBackground client config option to wait until background dialing has completed.
   583  func (c *Client) waitForConnectionReady(ctx context.Context) error {
   584  	for {
   585  		if c.conn == nil {
   586  			return errors.New("conn was closed")
   587  		}
   588  		switch state := c.conn.GetState(); state {
   589  		case connectivity.Ready:
   590  			return nil
   591  		case connectivity.TransientFailure, connectivity.Connecting, connectivity.Idle:
   592  			// Wait for expected state transitions. For details about grpc.ClientConn state changes
   593  			// see https://github.com/grpc/grpc/blob/master/doc/connectivity-semantics-and-api.md
   594  			if !c.conn.WaitForStateChange(ctx, state) {
   595  				// ctx canceled
   596  				return trace.Wrap(ctx.Err())
   597  			}
   598  		case connectivity.Shutdown:
   599  			return trace.Errorf("client gRPC connection entered an unexpected state: %v", state)
   600  		}
   601  	}
   602  }
   603  
   604  // Config contains configuration of the client
   605  type Config struct {
   606  	// Addrs is a list of teleport auth/proxy server addresses to dial.
   607  	Addrs []string
   608  	// Credentials are a list of credentials to use when attempting
   609  	// to connect to the server.
   610  	Credentials []Credentials
   611  	// Dialer is a custom dialer used to dial a server. The Dialer should
   612  	// have custom logic to provide an address to the dialer. If set, Dialer
   613  	// takes precedence over all other connection options.
   614  	Dialer ContextDialer
   615  	// DialOpts define options for dialing the client connection.
   616  	DialOpts []grpc.DialOption
   617  	// DialInBackground specifies to dial the connection in the background
   618  	// rather than blocking until the connection is up. A predefined Dialer
   619  	// or an auth server address must be provided.
   620  	DialInBackground bool
   621  	// DialTimeout defines how long to attempt dialing before timing out.
   622  	DialTimeout time.Duration
   623  	// KeepAlivePeriod defines period between keep alives.
   624  	KeepAlivePeriod time.Duration
   625  	// KeepAliveCount specifies the amount of missed keep alives
   626  	// to wait for before declaring the connection as broken.
   627  	KeepAliveCount int
   628  	// The web proxy uses a self-signed TLS certificate by default, which
   629  	// requires this field to be set. If the web proxy was provided with
   630  	// signed TLS certificates, this field should not be set.
   631  	InsecureAddressDiscovery bool
   632  	// ALPNSNIAuthDialClusterName if present the client will include ALPN SNI routing information in TLS Hello message
   633  	// allowing to dial auth service through Teleport Proxy directly without using SSH Tunnels.
   634  	ALPNSNIAuthDialClusterName string
   635  	// CircuitBreakerConfig defines how the circuit breaker should behave.
   636  	CircuitBreakerConfig breaker.Config
   637  	// Context is the base context to use for dialing. If not provided context.Background is used
   638  	Context context.Context
   639  	// ALPNConnUpgradeRequired indicates that ALPN connection upgrades are
   640  	// required for making TLS Routing requests.
   641  	//
   642  	// In DialInBackground mode without a Dialer, a valid value must be
   643  	// provided as it's assumed that the caller knows the context if connection
   644  	// upgrades are required for TLS Routing.
   645  	//
   646  	// In default mode, this value is optional as some of the connect methods
   647  	// will perform necessary tests to decide if connection upgrade is
   648  	// required.
   649  	ALPNConnUpgradeRequired bool
   650  	// PROXYHeaderGetter returns signed PROXY header that is sent to allow Proxy to propagate client's real IP to the
   651  	// auth server from the Proxy's web server, when we create user's client for the web session.
   652  	PROXYHeaderGetter PROXYHeaderGetter
   653  	// MFAPromptConstructor is used to create MFA prompts when needed.
   654  	// If nil, the client will not prompt for MFA.
   655  	MFAPromptConstructor mfa.PromptConstructor
   656  }
   657  
   658  // CheckAndSetDefaults checks and sets default config values.
   659  func (c *Config) CheckAndSetDefaults() error {
   660  	if len(c.Credentials) == 0 {
   661  		return trace.BadParameter("missing connection credentials")
   662  	}
   663  
   664  	if c.KeepAlivePeriod == 0 {
   665  		c.KeepAlivePeriod = defaults.ServerKeepAliveTTL()
   666  	}
   667  	if c.KeepAliveCount == 0 {
   668  		c.KeepAliveCount = defaults.KeepAliveCountMax
   669  	}
   670  	if c.DialTimeout == 0 {
   671  		c.DialTimeout = defaults.DefaultIOTimeout
   672  	}
   673  	if c.CircuitBreakerConfig.Trip == nil || c.CircuitBreakerConfig.IsSuccessful == nil {
   674  		c.CircuitBreakerConfig = breaker.DefaultBreakerConfig(clockwork.NewRealClock())
   675  	}
   676  
   677  	if c.Context == nil {
   678  		c.Context = context.Background()
   679  	}
   680  
   681  	c.DialOpts = append(c.DialOpts, grpc.WithKeepaliveParams(keepalive.ClientParameters{
   682  		Time:                c.KeepAlivePeriod,
   683  		Timeout:             c.KeepAlivePeriod * time.Duration(c.KeepAliveCount),
   684  		PermitWithoutStream: true,
   685  	}))
   686  	if !c.DialInBackground {
   687  		c.DialOpts = append(
   688  			c.DialOpts,
   689  			// Provides additional feedback on connection failure, otherwise,
   690  			// users will only receive a `context deadline exceeded` error when
   691  			// c.DialInBackground == false.
   692  			//
   693  			// grpc.WithReturnConnectionError implies grpc.WithBlock which is
   694  			// necessary for connection route selection to work properly.
   695  			grpc.WithReturnConnectionError(),
   696  		)
   697  	}
   698  
   699  	return nil
   700  }
   701  
   702  // Config returns the tls.Config the client connected with.
   703  func (c *Client) Config() *tls.Config {
   704  	return c.tlsConfig
   705  }
   706  
   707  // Dialer returns the ContextDialer the client connected with.
   708  func (c *Client) Dialer() ContextDialer {
   709  	return c.dialer
   710  }
   711  
   712  // GetConnection returns gRPC connection.
   713  func (c *Client) GetConnection() *grpc.ClientConn {
   714  	return c.conn
   715  }
   716  
   717  // SetMFAPromptConstructor sets the MFA prompt constructor for this client.
   718  func (c *Client) SetMFAPromptConstructor(pc mfa.PromptConstructor) {
   719  	c.c.MFAPromptConstructor = pc
   720  }
   721  
   722  // Close closes the Client connection to the auth server.
   723  func (c *Client) Close() error {
   724  	if c.setClosed() && c.conn != nil {
   725  		return trace.Wrap(c.conn.Close())
   726  	}
   727  	return nil
   728  }
   729  
   730  // isClosed returns whether the client is marked as closed.
   731  func (c *Client) isClosed() bool {
   732  	return atomic.LoadInt32(c.closedFlag) == 1
   733  }
   734  
   735  // setClosed marks the client as closed and returns true if it was open.
   736  func (c *Client) setClosed() bool {
   737  	return atomic.CompareAndSwapInt32(c.closedFlag, 0, 1)
   738  }
   739  
   740  // DevicesClient returns an unadorned Device Trust client, using the underlying
   741  // Auth gRPC connection.
   742  // Clients connecting to non-Enterprise clusters, or older Teleport versions,
   743  // still get a devices client when calling this method, but all RPCs will return
   744  // "not implemented" errors (as per the default gRPC behavior).
   745  func (c *Client) DevicesClient() devicepb.DeviceTrustServiceClient {
   746  	return devicepb.NewDeviceTrustServiceClient(c.conn)
   747  }
   748  
   749  // CreateDeviceResource creates a device using its resource representation.
   750  // Prefer using [DevicesClient] directly if you can.
   751  func (c *Client) CreateDeviceResource(ctx context.Context, res *types.DeviceV1) (*types.DeviceV1, error) {
   752  	dev, err := types.DeviceFromResource(res)
   753  	if err != nil {
   754  		return nil, trace.Wrap(err)
   755  	}
   756  
   757  	created, err := c.DevicesClient().CreateDevice(ctx, &devicepb.CreateDeviceRequest{
   758  		Device:           dev,
   759  		CreateAsResource: true,
   760  	})
   761  	if err != nil {
   762  		return nil, trace.Wrap(err)
   763  	}
   764  	return types.DeviceToResource(created), nil
   765  }
   766  
   767  // DeleteDeviceResource deletes a device using its ID (either devicepb.Device.Id
   768  // or its Metadata.Name).
   769  // Prefer using [DevicesClient] directly if you can.
   770  func (c *Client) DeleteDeviceResource(ctx context.Context, id string) error {
   771  	_, err := c.DevicesClient().DeleteDevice(ctx, &devicepb.DeleteDeviceRequest{
   772  		DeviceId: id,
   773  	})
   774  	return trace.Wrap(err)
   775  }
   776  
   777  // GetDeviceResource reads a device using its ID (either devicepb.Device.Id
   778  // or its Metadata.Name).
   779  // Prefer using [DevicesClient] directly if you can.
   780  func (c *Client) GetDeviceResource(ctx context.Context, id string) (*types.DeviceV1, error) {
   781  	dev, err := c.DevicesClient().GetDevice(ctx, &devicepb.GetDeviceRequest{
   782  		DeviceId: id,
   783  	})
   784  	if err != nil {
   785  		return nil, trace.Wrap(err)
   786  	}
   787  	return types.DeviceToResource(dev), nil
   788  }
   789  
   790  // UpsertDeviceResource creates or updates a device using its resource
   791  // representation.
   792  // Prefer using [DevicesClient] directly if you can.
   793  func (c *Client) UpsertDeviceResource(ctx context.Context, res *types.DeviceV1) (*types.DeviceV1, error) {
   794  	dev, err := types.DeviceFromResource(res)
   795  	if err != nil {
   796  		return nil, trace.Wrap(err)
   797  	}
   798  
   799  	upserted, err := c.DevicesClient().UpsertDevice(ctx, &devicepb.UpsertDeviceRequest{
   800  		Device:           dev,
   801  		CreateAsResource: true,
   802  	})
   803  	if err != nil {
   804  		return nil, trace.Wrap(err)
   805  	}
   806  	return types.DeviceToResource(upserted), nil
   807  }
   808  
   809  // LoginRuleClient returns an unadorned Login Rule client, using the underlying
   810  // Auth gRPC connection.
   811  // Clients connecting to non-Enterprise clusters, or older Teleport versions,
   812  // still get a login rule client when calling this method, but all RPCs will
   813  // return "not implemented" errors (as per the default gRPC behavior).
   814  func (c *Client) LoginRuleClient() loginrulepb.LoginRuleServiceClient {
   815  	return loginrulepb.NewLoginRuleServiceClient(c.conn)
   816  }
   817  
   818  // SecReportsClient returns Security client that can be used to fetch security reports.
   819  func (c *Client) SecReportsClient() *secreport.Client {
   820  	return secreport.NewClient(secreportsv1.NewSecReportsServiceClient(c.conn))
   821  }
   822  
   823  // SAMLIdPClient returns an unadorned SAML IdP client, using the underlying
   824  // Auth gRPC connection.
   825  // Clients connecting to non-Enterprise clusters, or older Teleport versions,
   826  // still get a SAML IdP client when calling this method, but all RPCs will
   827  // return "not implemented" errors (as per the default gRPC behavior).
   828  func (c *Client) SAMLIdPClient() samlidppb.SAMLIdPServiceClient {
   829  	return samlidppb.NewSAMLIdPServiceClient(c.conn)
   830  }
   831  
   832  // ExternalAuditStorageClient returns an unadorned External Audit Storage
   833  // client, using the underlying Auth gRPC connection.
   834  // Clients connecting to non-Enterprise clusters, or older Teleport versions,
   835  // still get a external audit client when calling this method, but all RPCs will
   836  // return "not implemented" errors (as per the default gRPC behavior).
   837  func (c *Client) ExternalAuditStorageClient() *externalauditstorage.Client {
   838  	return externalauditstorage.NewClient(externalauditstoragev1.NewExternalAuditStorageServiceClient(c.conn))
   839  }
   840  
   841  // TrustClient returns an unadorned Trust client, using the underlying
   842  // Auth gRPC connection.
   843  func (c *Client) TrustClient() trustpb.TrustServiceClient {
   844  	return trustpb.NewTrustServiceClient(c.conn)
   845  }
   846  
   847  // EmbeddingClient returns an unadorned Embedding client, using the underlying
   848  // Auth gRPC connection.
   849  func (c *Client) EmbeddingClient() assist.AssistEmbeddingServiceClient {
   850  	return assist.NewAssistEmbeddingServiceClient(c.conn)
   851  }
   852  
   853  // BotServiceClient returns an unadorned client for the bot service.
   854  func (c *Client) BotServiceClient() machineidv1pb.BotServiceClient {
   855  	return machineidv1pb.NewBotServiceClient(c.conn)
   856  }
   857  
   858  // PresenceServiceClient returns an unadorned client for the presence service.
   859  func (c *Client) PresenceServiceClient() presencepb.PresenceServiceClient {
   860  	return presencepb.NewPresenceServiceClient(c.conn)
   861  }
   862  
   863  // WorkloadIdentityServiceClient returns an unadorned client for the workload
   864  // identity service.
   865  func (c *Client) WorkloadIdentityServiceClient() machineidv1pb.WorkloadIdentityServiceClient {
   866  	return machineidv1pb.NewWorkloadIdentityServiceClient(c.conn)
   867  }
   868  
   869  // Ping gets basic info about the auth server.
   870  func (c *Client) Ping(ctx context.Context) (proto.PingResponse, error) {
   871  	rsp, err := c.grpc.Ping(ctx, &proto.PingRequest{})
   872  	if err != nil {
   873  		return proto.PingResponse{}, trace.Wrap(err)
   874  	}
   875  
   876  	return *rsp, nil
   877  }
   878  
   879  // CreateUser creates a new user from the specified descriptor.
   880  func (c *Client) CreateUser(ctx context.Context, user types.User) (types.User, error) {
   881  	userV2, ok := user.(*types.UserV2)
   882  	if !ok {
   883  		return nil, trace.BadParameter("unsupported user type %T", user)
   884  	}
   885  
   886  	resp, err := userspb.NewUsersServiceClient(c.conn).CreateUser(ctx, &userspb.CreateUserRequest{User: userV2})
   887  	if err != nil {
   888  		// TODO(tross): DELETE IN 16.0.0
   889  		if trace.IsNotImplemented(err) {
   890  			//nolint:staticcheck // SA1019. Kept for backward compatibility.
   891  			if _, err := c.grpc.CreateUser(ctx, userV2); err != nil {
   892  				return nil, trace.Wrap(err)
   893  			}
   894  
   895  			//nolint:staticcheck // SA1019. Kept for backward compatibility.
   896  			created, err := c.grpc.GetUser(ctx, &proto.GetUserRequest{Name: user.GetName()})
   897  			return created, trace.Wrap(err)
   898  		}
   899  
   900  		return nil, trace.Wrap(err)
   901  	}
   902  
   903  	return resp.User, trace.Wrap(err)
   904  }
   905  
   906  // UpsertUser creates a new user or updates an existing user.
   907  func (c *Client) UpsertUser(ctx context.Context, user types.User) (types.User, error) {
   908  	userV2, ok := user.(*types.UserV2)
   909  	if !ok {
   910  		return nil, trace.BadParameter("unsupported user type %T", user)
   911  	}
   912  
   913  	resp, err := userspb.NewUsersServiceClient(c.conn).UpsertUser(ctx, &userspb.UpsertUserRequest{User: userV2})
   914  	if err != nil {
   915  		return nil, trace.Wrap(err)
   916  	}
   917  
   918  	return resp.User, trace.Wrap(err)
   919  }
   920  
   921  // UpdateUser updates an existing user in a backend.
   922  func (c *Client) UpdateUser(ctx context.Context, user types.User) (types.User, error) {
   923  	userV2, ok := user.(*types.UserV2)
   924  	if !ok {
   925  		return nil, trace.BadParameter("unsupported user type %T", user)
   926  	}
   927  
   928  	resp, err := userspb.NewUsersServiceClient(c.conn).UpdateUser(ctx, &userspb.UpdateUserRequest{User: userV2})
   929  	if err != nil {
   930  		// TODO(tross): DELETE IN 16.0.0
   931  		if trace.IsNotImplemented(err) {
   932  			//nolint:staticcheck // SA1019. Kept for backward compatibility.
   933  			if _, err := c.grpc.UpdateUser(ctx, userV2); err != nil {
   934  				return nil, trace.Wrap(err)
   935  			}
   936  
   937  			//nolint:staticcheck // SA1019. Kept for backward compatibility.
   938  			updated, err := c.grpc.GetUser(ctx, &proto.GetUserRequest{Name: user.GetName()})
   939  			return updated, trace.Wrap(err)
   940  		}
   941  
   942  		return nil, trace.Wrap(err)
   943  	}
   944  
   945  	return resp.User, trace.Wrap(err)
   946  }
   947  
   948  // GetUser returns a list of usernames registered in the system.
   949  // withSecrets controls whether authentication details are returned.
   950  func (c *Client) GetUser(ctx context.Context, name string, withSecrets bool) (types.User, error) {
   951  	if name == "" {
   952  		return nil, trace.BadParameter("missing username")
   953  	}
   954  	resp, err := userspb.NewUsersServiceClient(c.conn).GetUser(ctx, &userspb.GetUserRequest{Name: name, WithSecrets: withSecrets})
   955  	if err != nil {
   956  		// TODO(tross): DELETE IN 16.0.0
   957  		if trace.IsNotImplemented(err) {
   958  			//nolint:staticcheck // SA1019. Kept for backward compatibility.
   959  			user, err := c.grpc.GetUser(ctx, &proto.GetUserRequest{
   960  				Name:        name,
   961  				WithSecrets: withSecrets,
   962  			})
   963  			return user, trace.Wrap(err)
   964  		}
   965  
   966  		return nil, trace.Wrap(err)
   967  	}
   968  	return resp.User, nil
   969  }
   970  
   971  // GetCurrentUser returns current user as seen by the server.
   972  // Useful especially in the context of remote clusters which perform role and trait mapping.
   973  func (c *Client) GetCurrentUser(ctx context.Context) (types.User, error) {
   974  	resp, err := userspb.NewUsersServiceClient(c.conn).GetUser(ctx, &userspb.GetUserRequest{CurrentUser: true})
   975  	if err != nil {
   976  		// TODO(tross): DELETE IN 16.0.0
   977  		if trace.IsNotImplemented(err) {
   978  			//nolint:staticcheck // SA1019. Kept for backward compatibility.
   979  			currentUser, err := c.grpc.GetCurrentUser(ctx, &emptypb.Empty{})
   980  			return currentUser, trace.Wrap(err)
   981  		}
   982  		return nil, trace.Wrap(err)
   983  	}
   984  	return resp.User, nil
   985  }
   986  
   987  // GetCurrentUserRoles returns current user's roles.
   988  func (c *Client) GetCurrentUserRoles(ctx context.Context) ([]types.Role, error) {
   989  	stream, err := c.grpc.GetCurrentUserRoles(ctx, &emptypb.Empty{})
   990  	if err != nil {
   991  		return nil, trace.Wrap(err)
   992  	}
   993  	var roles []types.Role
   994  	for role, err := stream.Recv(); !errors.Is(err, io.EOF); role, err = stream.Recv() {
   995  		if err != nil {
   996  			return nil, trace.Wrap(err)
   997  		}
   998  		roles = append(roles, role)
   999  	}
  1000  	return roles, nil
  1001  }
  1002  
  1003  // GetUsers returns all currently registered users.
  1004  // withSecrets controls whether authentication details are returned.
  1005  func (c *Client) GetUsers(ctx context.Context, withSecrets bool) ([]types.User, error) {
  1006  	req := userspb.ListUsersRequest{
  1007  		WithSecrets: withSecrets,
  1008  	}
  1009  
  1010  	var out []types.User
  1011  	for {
  1012  		rsp, err := c.ListUsers(ctx, &req)
  1013  		if err != nil {
  1014  			// TODO(tross): DELETE IN 16.0.0
  1015  			if trace.IsNotImplemented(err) {
  1016  				return c.getUsersCompat(ctx, withSecrets)
  1017  			}
  1018  
  1019  			return nil, trace.Wrap(err)
  1020  		}
  1021  
  1022  		for _, user := range rsp.Users {
  1023  			out = append(out, user)
  1024  		}
  1025  
  1026  		req.PageToken = rsp.NextPageToken
  1027  		if req.PageToken == "" {
  1028  			break
  1029  		}
  1030  	}
  1031  
  1032  	return out, nil
  1033  }
  1034  
  1035  // getUsersCompat is a fallback used to load users when talking to older auth servers that
  1036  // don't implement the newer ListUsers method.
  1037  func (c *Client) getUsersCompat(ctx context.Context, withSecrets bool) ([]types.User, error) {
  1038  	//nolint:staticcheck // SA1019. Kept for backward compatibility.
  1039  	stream, err := c.grpc.GetUsers(ctx, &proto.GetUsersRequest{
  1040  		WithSecrets: withSecrets,
  1041  	})
  1042  	if err != nil {
  1043  		return nil, trace.Wrap(err)
  1044  	}
  1045  	var users []types.User
  1046  	for user, err := stream.Recv(); !errors.Is(err, io.EOF); user, err = stream.Recv() {
  1047  		if err != nil {
  1048  			return nil, trace.Wrap(err)
  1049  		}
  1050  		users = append(users, user)
  1051  	}
  1052  	return users, nil
  1053  }
  1054  
  1055  // ListUsers returns a page of users.
  1056  func (c *Client) ListUsers(ctx context.Context, req *userspb.ListUsersRequest) (*userspb.ListUsersResponse, error) {
  1057  	var header gmetadata.MD
  1058  
  1059  	rsp, err := userspb.NewUsersServiceClient(c.conn).ListUsers(ctx, req, grpc.Header(&header))
  1060  	if err != nil {
  1061  		return nil, trace.Wrap(err)
  1062  	}
  1063  
  1064  	if req.Filter == nil {
  1065  		// remaining logic is all filter compat that we can skip
  1066  		return rsp, nil
  1067  	}
  1068  
  1069  	vs, _ := metadata.VersionFromMetadata(header)
  1070  	ver, _ := semver.NewVersion(vs)
  1071  	if ver != nil && ver.Major >= 16 {
  1072  		// auth implements all expected filtering features
  1073  		return rsp, nil
  1074  	}
  1075  
  1076  	filtered := rsp.Users[:0]
  1077  	for _, user := range rsp.Users {
  1078  		if req.Filter.Match(user) {
  1079  			filtered = append(filtered, user)
  1080  		}
  1081  	}
  1082  	rsp.Users = filtered
  1083  	return rsp, nil
  1084  }
  1085  
  1086  // DeleteUser deletes a user by name.
  1087  func (c *Client) DeleteUser(ctx context.Context, user string) error {
  1088  	_, err := userspb.NewUsersServiceClient(c.conn).DeleteUser(ctx, &userspb.DeleteUserRequest{Name: user})
  1089  	// TODO(tross): DELETE IN 16.0.0
  1090  	if trace.IsNotImplemented(err) {
  1091  		//nolint:staticcheck // SA1019. Kept for backward compatibility.
  1092  		_, err := c.grpc.DeleteUser(ctx, &proto.DeleteUserRequest{Name: user})
  1093  		return trace.Wrap(err)
  1094  	}
  1095  
  1096  	return trace.Wrap(err)
  1097  }
  1098  
  1099  // GenerateUserCerts takes the public key in the OpenSSH `authorized_keys` plain
  1100  // text format, signs it using User Certificate Authority signing key and
  1101  // returns the resulting certificates.
  1102  func (c *Client) GenerateUserCerts(ctx context.Context, req proto.UserCertsRequest) (*proto.Certs, error) {
  1103  	certs, err := c.grpc.GenerateUserCerts(ctx, &req)
  1104  	if err != nil {
  1105  		return nil, trace.Wrap(err)
  1106  	}
  1107  	return certs, nil
  1108  }
  1109  
  1110  // GenerateHostCerts generates host certificates.
  1111  func (c *Client) GenerateHostCerts(ctx context.Context, req *proto.HostCertsRequest) (*proto.Certs, error) {
  1112  	if err := req.CheckAndSetDefaults(); err != nil {
  1113  		return nil, trace.Wrap(err)
  1114  	}
  1115  	certs, err := c.grpc.GenerateHostCerts(ctx, req)
  1116  	if err != nil {
  1117  		return nil, trace.Wrap(err)
  1118  	}
  1119  	return certs, nil
  1120  }
  1121  
  1122  // GenerateOpenSSHCert signs a SSH certificate that can be used
  1123  // to connect to Agentless nodes.
  1124  func (c *Client) GenerateOpenSSHCert(ctx context.Context, req *proto.OpenSSHCertRequest) (*proto.OpenSSHCert, error) {
  1125  	cert, err := c.grpc.GenerateOpenSSHCert(ctx, req)
  1126  	if err != nil {
  1127  		return nil, trace.Wrap(err)
  1128  	}
  1129  	return cert, nil
  1130  }
  1131  
  1132  // EmitAuditEvent sends an auditable event to the auth server.
  1133  func (c *Client) EmitAuditEvent(ctx context.Context, event events.AuditEvent) error {
  1134  	grpcEvent, err := events.ToOneOf(event)
  1135  	if err != nil {
  1136  		return trace.Wrap(err)
  1137  	}
  1138  	_, err = c.grpc.EmitAuditEvent(context.WithoutCancel(ctx), grpcEvent)
  1139  	if err != nil {
  1140  		return trace.Wrap(err)
  1141  	}
  1142  	return nil
  1143  }
  1144  
  1145  // GetResetPasswordToken returns a reset password token for the specified tokenID.
  1146  func (c *Client) GetResetPasswordToken(ctx context.Context, tokenID string) (types.UserToken, error) {
  1147  	token, err := c.grpc.GetResetPasswordToken(ctx, &proto.GetResetPasswordTokenRequest{
  1148  		TokenID: tokenID,
  1149  	})
  1150  	if err != nil {
  1151  		return nil, trace.Wrap(err)
  1152  	}
  1153  
  1154  	return token, nil
  1155  }
  1156  
  1157  // CreateResetPasswordToken creates reset password token.
  1158  func (c *Client) CreateResetPasswordToken(ctx context.Context, req *proto.CreateResetPasswordTokenRequest) (types.UserToken, error) {
  1159  	token, err := c.grpc.CreateResetPasswordToken(ctx, req)
  1160  	if err != nil {
  1161  		return nil, trace.Wrap(err)
  1162  	}
  1163  
  1164  	return token, nil
  1165  }
  1166  
  1167  // GetAccessRequests retrieves a list of all access requests matching the provided filter.
  1168  func (c *Client) GetAccessRequests(ctx context.Context, filter types.AccessRequestFilter) ([]types.AccessRequest, error) {
  1169  	requests, err := c.ListAllAccessRequests(ctx, &proto.ListAccessRequestsRequest{
  1170  		Filter: &filter,
  1171  	})
  1172  	if err != nil {
  1173  		return nil, trace.Wrap(err)
  1174  	}
  1175  
  1176  	ireqs := make([]types.AccessRequest, 0, len(requests))
  1177  	for _, r := range requests {
  1178  		ireqs = append(ireqs, r)
  1179  	}
  1180  
  1181  	return ireqs, nil
  1182  }
  1183  
  1184  // ListAccessRequests is an access request getter with pagination and sorting options.
  1185  func (c *Client) ListAccessRequests(ctx context.Context, req *proto.ListAccessRequestsRequest) (*proto.ListAccessRequestsResponse, error) {
  1186  	rsp, err := c.grpc.ListAccessRequests(ctx, req)
  1187  	return rsp, trace.Wrap(err)
  1188  }
  1189  
  1190  // ListAllAccessRequests aggregates all access requests via the ListAccessRequests api. This is equivalent to calling GetAccessRequests
  1191  // except that it supports custom sort order/indexes. Calling this method rather than ListAccessRequests also provides the advantage
  1192  // that it can fallback to calling the old GetAccessRequests grpc method if it encounters and outdated control plane. For that reason,
  1193  // implementations that don't actually *need* pagination are better served by calling this method.
  1194  func (c *Client) ListAllAccessRequests(ctx context.Context, req *proto.ListAccessRequestsRequest) ([]*types.AccessRequestV3, error) {
  1195  	var requests []*types.AccessRequestV3
  1196  	for {
  1197  		rsp, err := c.ListAccessRequests(ctx, req)
  1198  		if err != nil {
  1199  			if trace.IsNotImplemented(err) {
  1200  				return c.listAllAccessRequestsCompat(ctx, req)
  1201  			}
  1202  
  1203  			return nil, trace.Wrap(err)
  1204  		}
  1205  
  1206  		requests = append(requests, rsp.AccessRequests...)
  1207  
  1208  		req.StartKey = rsp.NextKey
  1209  		if req.StartKey == "" {
  1210  			break
  1211  		}
  1212  	}
  1213  
  1214  	return requests, nil
  1215  }
  1216  
  1217  // listAllAccessRequestsCompat is a helper that simulates ListAllAccessRequests behavior via the old GetAccessRequests method.
  1218  func (c *Client) listAllAccessRequestsCompat(ctx context.Context, req *proto.ListAccessRequestsRequest) ([]*types.AccessRequestV3, error) {
  1219  	var filter types.AccessRequestFilter
  1220  	if req.Filter != nil {
  1221  		filter = *req.Filter
  1222  	}
  1223  	requests, err := c.getAccessRequests(ctx, filter)
  1224  	if err != nil {
  1225  		return nil, trace.Wrap(err)
  1226  	}
  1227  
  1228  	switch req.Sort {
  1229  	case proto.AccessRequestSort_DEFAULT:
  1230  		// no custom sort order needed
  1231  	case proto.AccessRequestSort_CREATED:
  1232  		slices.SortFunc(requests, func(a, b *types.AccessRequestV3) int {
  1233  			return a.GetCreationTime().Compare(b.GetCreationTime())
  1234  		})
  1235  	case proto.AccessRequestSort_STATE:
  1236  		slices.SortFunc(requests, func(a, b *types.AccessRequestV3) int {
  1237  			return cmp.Compare(a.GetState().String(), b.GetState().String())
  1238  		})
  1239  	default:
  1240  		return nil, trace.BadParameter("list access request compat fallback does not support sort order %q", req.Sort)
  1241  	}
  1242  
  1243  	if req.Descending {
  1244  		slices.Reverse(requests)
  1245  	}
  1246  
  1247  	return requests, nil
  1248  }
  1249  
  1250  // getAccessRequests calls the old GetAccessRequests method. used by back-compat logic when interacting with
  1251  // an outdated control-plane that doesn't support ListAccessRequests.
  1252  func (c *Client) getAccessRequests(ctx context.Context, filter types.AccessRequestFilter) ([]*types.AccessRequestV3, error) {
  1253  	stream, err := c.grpc.GetAccessRequestsV2(ctx, &filter)
  1254  	if err != nil {
  1255  		return nil, trace.Wrap(err)
  1256  	}
  1257  
  1258  	var reqs []*types.AccessRequestV3
  1259  	for {
  1260  		req, err := stream.Recv()
  1261  		if errors.Is(err, io.EOF) {
  1262  			break
  1263  		}
  1264  
  1265  		if err != nil {
  1266  			return nil, trace.Wrap(err)
  1267  		}
  1268  		reqs = append(reqs, req)
  1269  	}
  1270  
  1271  	return reqs, nil
  1272  }
  1273  
  1274  // CreateAccessRequestV2 registers a new access request with the auth server.
  1275  func (c *Client) CreateAccessRequestV2(ctx context.Context, req types.AccessRequest) (types.AccessRequest, error) {
  1276  	r, ok := req.(*types.AccessRequestV3)
  1277  	if !ok {
  1278  		return nil, trace.BadParameter("unexpected access request type %T", req)
  1279  	}
  1280  	resp, err := c.grpc.CreateAccessRequestV2(ctx, r)
  1281  	return resp, trace.Wrap(err)
  1282  }
  1283  
  1284  // DeleteAccessRequest deletes an access request.
  1285  func (c *Client) DeleteAccessRequest(ctx context.Context, reqID string) error {
  1286  	_, err := c.grpc.DeleteAccessRequest(ctx, &proto.RequestID{ID: reqID})
  1287  	return trace.Wrap(err)
  1288  }
  1289  
  1290  // GetAccessRequestAllowedPromotions returns the list of promotions allowed for the given access request.
  1291  func (c *Client) GetAccessRequestAllowedPromotions(ctx context.Context, req types.AccessRequest) (*types.AccessRequestAllowedPromotions, error) {
  1292  	resp, err := c.grpc.GetAccessRequestAllowedPromotions(ctx, &proto.AccessRequestAllowedPromotionRequest{
  1293  		AccessRequestID: req.GetName(),
  1294  	})
  1295  	if err != nil {
  1296  		return nil, trace.Wrap(err)
  1297  	}
  1298  	return resp.AllowedPromotions, nil
  1299  }
  1300  
  1301  // SetAccessRequestState updates the state of an existing access request.
  1302  func (c *Client) SetAccessRequestState(ctx context.Context, params types.AccessRequestUpdate) error {
  1303  	setter := proto.RequestStateSetter{
  1304  		ID:              params.RequestID,
  1305  		State:           params.State,
  1306  		Reason:          params.Reason,
  1307  		Annotations:     params.Annotations,
  1308  		Roles:           params.Roles,
  1309  		AssumeStartTime: params.AssumeStartTime,
  1310  	}
  1311  	if d := utils.GetDelegator(ctx); d != "" {
  1312  		setter.Delegator = d
  1313  	}
  1314  	_, err := c.grpc.SetAccessRequestState(ctx, &setter)
  1315  	return trace.Wrap(err)
  1316  }
  1317  
  1318  // SubmitAccessReview applies a review to a request and returns the post-application state.
  1319  func (c *Client) SubmitAccessReview(ctx context.Context, params types.AccessReviewSubmission) (types.AccessRequest, error) {
  1320  	req, err := c.grpc.SubmitAccessReview(ctx, &params)
  1321  	if err != nil {
  1322  		return nil, trace.Wrap(err)
  1323  	}
  1324  	return req, nil
  1325  }
  1326  
  1327  // GetAccessCapabilities requests the access capabilities of a user.
  1328  func (c *Client) GetAccessCapabilities(ctx context.Context, req types.AccessCapabilitiesRequest) (*types.AccessCapabilities, error) {
  1329  	caps, err := c.grpc.GetAccessCapabilities(ctx, &req)
  1330  	if err != nil {
  1331  		return nil, trace.Wrap(err)
  1332  	}
  1333  	return caps, nil
  1334  }
  1335  
  1336  // GetPluginData loads all plugin data matching the supplied filter.
  1337  func (c *Client) GetPluginData(ctx context.Context, filter types.PluginDataFilter) ([]types.PluginData, error) {
  1338  	seq, err := c.grpc.GetPluginData(ctx, &filter)
  1339  	if err != nil {
  1340  		return nil, trace.Wrap(err)
  1341  	}
  1342  	data := make([]types.PluginData, 0, len(seq.PluginData))
  1343  	for _, d := range seq.PluginData {
  1344  		data = append(data, d)
  1345  	}
  1346  	return data, nil
  1347  }
  1348  
  1349  // UpdatePluginData updates a per-resource PluginData entry.
  1350  func (c *Client) UpdatePluginData(ctx context.Context, params types.PluginDataUpdateParams) error {
  1351  	_, err := c.grpc.UpdatePluginData(ctx, &params)
  1352  	return trace.Wrap(err)
  1353  }
  1354  
  1355  // AcquireSemaphore acquires lease with requested resources from semaphore.
  1356  func (c *Client) AcquireSemaphore(ctx context.Context, params types.AcquireSemaphoreRequest) (*types.SemaphoreLease, error) {
  1357  	lease, err := c.grpc.AcquireSemaphore(ctx, &params)
  1358  	if err != nil {
  1359  		return nil, trace.Wrap(err)
  1360  	}
  1361  	return lease, nil
  1362  }
  1363  
  1364  // KeepAliveSemaphoreLease updates semaphore lease.
  1365  func (c *Client) KeepAliveSemaphoreLease(ctx context.Context, lease types.SemaphoreLease) error {
  1366  	_, err := c.grpc.KeepAliveSemaphoreLease(ctx, &lease)
  1367  	return trace.Wrap(err)
  1368  }
  1369  
  1370  // CancelSemaphoreLease cancels semaphore lease early.
  1371  func (c *Client) CancelSemaphoreLease(ctx context.Context, lease types.SemaphoreLease) error {
  1372  	_, err := c.grpc.CancelSemaphoreLease(ctx, &lease)
  1373  	return trace.Wrap(err)
  1374  }
  1375  
  1376  // GetSemaphores returns a list of all semaphores matching the supplied filter.
  1377  func (c *Client) GetSemaphores(ctx context.Context, filter types.SemaphoreFilter) ([]types.Semaphore, error) {
  1378  	rsp, err := c.grpc.GetSemaphores(ctx, &filter)
  1379  	if err != nil {
  1380  		return nil, trace.Wrap(err)
  1381  	}
  1382  	sems := make([]types.Semaphore, 0, len(rsp.Semaphores))
  1383  	for _, s := range rsp.Semaphores {
  1384  		sems = append(sems, s)
  1385  	}
  1386  	return sems, nil
  1387  }
  1388  
  1389  // DeleteSemaphore deletes a semaphore matching the supplied filter.
  1390  func (c *Client) DeleteSemaphore(ctx context.Context, filter types.SemaphoreFilter) error {
  1391  	_, err := c.grpc.DeleteSemaphore(ctx, &filter)
  1392  	return trace.Wrap(err)
  1393  }
  1394  
  1395  // GetKubernetesServers returns the list of kubernetes servers registered in the
  1396  // cluster.
  1397  func (c *Client) GetKubernetesServers(ctx context.Context) ([]types.KubeServer, error) {
  1398  	servers, err := GetAllResources[types.KubeServer](ctx, c, &proto.ListResourcesRequest{
  1399  		Namespace:    defaults.Namespace,
  1400  		ResourceType: types.KindKubeServer,
  1401  	})
  1402  	return servers, trace.Wrap(err)
  1403  }
  1404  
  1405  // DeleteKubernetesServer deletes a named kubernetes server.
  1406  func (c *Client) DeleteKubernetesServer(ctx context.Context, hostID, name string) error {
  1407  	_, err := c.grpc.DeleteKubernetesServer(ctx, &proto.DeleteKubernetesServerRequest{
  1408  		HostID: hostID,
  1409  		Name:   name,
  1410  	})
  1411  	return trace.Wrap(err)
  1412  }
  1413  
  1414  // DeleteAllKubernetesServers deletes all registered kubernetes servers.
  1415  func (c *Client) DeleteAllKubernetesServers(ctx context.Context) error {
  1416  	_, err := c.grpc.DeleteAllKubernetesServers(ctx, &proto.DeleteAllKubernetesServersRequest{})
  1417  	return trace.Wrap(err)
  1418  }
  1419  
  1420  // UpsertKubernetesServer is used by kubernetes services to report their presence
  1421  // to other auth servers in form of heartbeat expiring after ttl period.
  1422  func (c *Client) UpsertKubernetesServer(ctx context.Context, s types.KubeServer) (*types.KeepAlive, error) {
  1423  	server, ok := s.(*types.KubernetesServerV3)
  1424  	if !ok {
  1425  		return nil, trace.BadParameter("invalid type %T, expected *types.KubernetesServerV3", server)
  1426  	}
  1427  	keepAlive, err := c.grpc.UpsertKubernetesServer(ctx, &proto.UpsertKubernetesServerRequest{Server: server})
  1428  	if err != nil {
  1429  		return nil, trace.Wrap(err)
  1430  	}
  1431  	return keepAlive, nil
  1432  }
  1433  
  1434  // GetApplicationServers returns all registered application servers.
  1435  func (c *Client) GetApplicationServers(ctx context.Context, namespace string) ([]types.AppServer, error) {
  1436  	servers, err := GetAllResources[types.AppServer](ctx, c, &proto.ListResourcesRequest{
  1437  		Namespace:    namespace,
  1438  		ResourceType: types.KindAppServer,
  1439  	})
  1440  	return servers, trace.Wrap(err)
  1441  }
  1442  
  1443  // UpsertApplicationServer registers an application server.
  1444  func (c *Client) UpsertApplicationServer(ctx context.Context, server types.AppServer) (*types.KeepAlive, error) {
  1445  	s, ok := server.(*types.AppServerV3)
  1446  	if !ok {
  1447  		return nil, trace.BadParameter("invalid type %T", server)
  1448  	}
  1449  	keepAlive, err := c.grpc.UpsertApplicationServer(ctx, &proto.UpsertApplicationServerRequest{
  1450  		Server: s,
  1451  	})
  1452  	if err != nil {
  1453  		return nil, trace.Wrap(err)
  1454  	}
  1455  	return keepAlive, nil
  1456  }
  1457  
  1458  // DeleteApplicationServer removes specified application server.
  1459  func (c *Client) DeleteApplicationServer(ctx context.Context, namespace, hostID, name string) error {
  1460  	_, err := c.grpc.DeleteApplicationServer(ctx, &proto.DeleteApplicationServerRequest{
  1461  		Namespace: namespace,
  1462  		HostID:    hostID,
  1463  		Name:      name,
  1464  	})
  1465  	return trace.Wrap(err)
  1466  }
  1467  
  1468  // DeleteAllApplicationServers removes all registered application servers.
  1469  func (c *Client) DeleteAllApplicationServers(ctx context.Context, namespace string) error {
  1470  	_, err := c.grpc.DeleteAllApplicationServers(ctx, &proto.DeleteAllApplicationServersRequest{
  1471  		Namespace: namespace,
  1472  	})
  1473  	return trace.Wrap(err)
  1474  }
  1475  
  1476  // GetAppSession gets an application web session.
  1477  func (c *Client) GetAppSession(ctx context.Context, req types.GetAppSessionRequest) (types.WebSession, error) {
  1478  	resp, err := c.grpc.GetAppSession(ctx, &proto.GetAppSessionRequest{
  1479  		SessionID: req.SessionID,
  1480  	})
  1481  	if err != nil {
  1482  		return nil, trace.Wrap(err)
  1483  	}
  1484  
  1485  	return resp.GetSession(), nil
  1486  }
  1487  
  1488  // ListAppSessions gets a paginated list of application web sessions.
  1489  func (c *Client) ListAppSessions(ctx context.Context, pageSize int, pageToken, user string) ([]types.WebSession, string, error) {
  1490  	resp, err := c.grpc.ListAppSessions(
  1491  		ctx,
  1492  		&proto.ListAppSessionsRequest{
  1493  			PageSize:  int32(pageSize),
  1494  			PageToken: pageToken,
  1495  			User:      user,
  1496  		})
  1497  	if err != nil {
  1498  		return nil, "", trace.Wrap(err)
  1499  	}
  1500  
  1501  	out := make([]types.WebSession, 0, len(resp.GetSessions()))
  1502  	for _, v := range resp.GetSessions() {
  1503  		out = append(out, v)
  1504  	}
  1505  	return out, resp.NextPageToken, nil
  1506  }
  1507  
  1508  // GetSnowflakeSessions gets all Snowflake web sessions.
  1509  func (c *Client) GetSnowflakeSessions(ctx context.Context) ([]types.WebSession, error) {
  1510  	resp, err := c.grpc.GetSnowflakeSessions(ctx, &emptypb.Empty{})
  1511  	if err != nil {
  1512  		return nil, trace.Wrap(err)
  1513  	}
  1514  
  1515  	out := make([]types.WebSession, 0, len(resp.GetSessions()))
  1516  	for _, v := range resp.GetSessions() {
  1517  		out = append(out, v)
  1518  	}
  1519  	return out, nil
  1520  }
  1521  
  1522  // ListSAMLIdPSessions gets a paginated list of SAML IdP sessions.
  1523  func (c *Client) ListSAMLIdPSessions(ctx context.Context, pageSize int, pageToken, user string) ([]types.WebSession, string, error) {
  1524  	resp, err := c.grpc.ListSAMLIdPSessions(
  1525  		ctx,
  1526  		&proto.ListSAMLIdPSessionsRequest{
  1527  			PageSize:  int32(pageSize),
  1528  			PageToken: pageToken,
  1529  			User:      user,
  1530  		})
  1531  	if err != nil {
  1532  		return nil, "", trace.Wrap(err)
  1533  	}
  1534  
  1535  	out := make([]types.WebSession, 0, len(resp.GetSessions()))
  1536  	for _, v := range resp.GetSessions() {
  1537  		out = append(out, v)
  1538  	}
  1539  	return out, resp.NextPageToken, nil
  1540  }
  1541  
  1542  // CreateAppSession creates an application web session. Application web
  1543  // sessions represent a browser session the client holds.
  1544  func (c *Client) CreateAppSession(ctx context.Context, req *proto.CreateAppSessionRequest) (types.WebSession, error) {
  1545  	resp, err := c.grpc.CreateAppSession(ctx, req)
  1546  	if err != nil {
  1547  		return nil, trace.Wrap(err)
  1548  	}
  1549  
  1550  	return resp.GetSession(), nil
  1551  }
  1552  
  1553  // CreateSnowflakeSession creates a Snowflake web session.
  1554  func (c *Client) CreateSnowflakeSession(ctx context.Context, req types.CreateSnowflakeSessionRequest) (types.WebSession, error) {
  1555  	resp, err := c.grpc.CreateSnowflakeSession(ctx, &proto.CreateSnowflakeSessionRequest{
  1556  		Username:     req.Username,
  1557  		SessionToken: req.SessionToken,
  1558  		TokenTTL:     proto.Duration(req.TokenTTL),
  1559  	})
  1560  	if err != nil {
  1561  		return nil, trace.Wrap(err)
  1562  	}
  1563  
  1564  	return resp.GetSession(), nil
  1565  }
  1566  
  1567  // CreateSAMLIdPSession creates a SAML IdP session.
  1568  func (c *Client) CreateSAMLIdPSession(ctx context.Context, req types.CreateSAMLIdPSessionRequest) (types.WebSession, error) {
  1569  	resp, err := c.grpc.CreateSAMLIdPSession(ctx, &proto.CreateSAMLIdPSessionRequest{
  1570  		SessionID:   req.SessionID,
  1571  		Username:    req.Username,
  1572  		SAMLSession: req.SAMLSession,
  1573  	})
  1574  	if err != nil {
  1575  		return nil, trace.Wrap(err)
  1576  	}
  1577  
  1578  	return resp.GetSession(), nil
  1579  }
  1580  
  1581  // GetSnowflakeSession gets a Snowflake web session.
  1582  func (c *Client) GetSnowflakeSession(ctx context.Context, req types.GetSnowflakeSessionRequest) (types.WebSession, error) {
  1583  	resp, err := c.grpc.GetSnowflakeSession(ctx, &proto.GetSnowflakeSessionRequest{
  1584  		SessionID: req.SessionID,
  1585  	})
  1586  	if err != nil {
  1587  		return nil, trace.Wrap(err)
  1588  	}
  1589  
  1590  	return resp.GetSession(), nil
  1591  }
  1592  
  1593  // GetSAMLIdPSession gets a SAML IdP session.
  1594  func (c *Client) GetSAMLIdPSession(ctx context.Context, req types.GetSAMLIdPSessionRequest) (types.WebSession, error) {
  1595  	resp, err := c.grpc.GetSAMLIdPSession(ctx, &proto.GetSAMLIdPSessionRequest{
  1596  		SessionID: req.SessionID,
  1597  	})
  1598  	if err != nil {
  1599  		return nil, trace.Wrap(err)
  1600  	}
  1601  
  1602  	return resp.GetSession(), nil
  1603  }
  1604  
  1605  // DeleteAppSession removes an application web session.
  1606  func (c *Client) DeleteAppSession(ctx context.Context, req types.DeleteAppSessionRequest) error {
  1607  	_, err := c.grpc.DeleteAppSession(ctx, &proto.DeleteAppSessionRequest{
  1608  		SessionID: req.SessionID,
  1609  	})
  1610  	return trace.Wrap(err)
  1611  }
  1612  
  1613  // DeleteSnowflakeSession removes a Snowflake web session.
  1614  func (c *Client) DeleteSnowflakeSession(ctx context.Context, req types.DeleteSnowflakeSessionRequest) error {
  1615  	_, err := c.grpc.DeleteSnowflakeSession(ctx, &proto.DeleteSnowflakeSessionRequest{
  1616  		SessionID: req.SessionID,
  1617  	})
  1618  	return trace.Wrap(err)
  1619  }
  1620  
  1621  // DeleteSAMLIdPSession removes a SAML IdP session.
  1622  func (c *Client) DeleteSAMLIdPSession(ctx context.Context, req types.DeleteSAMLIdPSessionRequest) error {
  1623  	_, err := c.grpc.DeleteSAMLIdPSession(ctx, &proto.DeleteSAMLIdPSessionRequest{
  1624  		SessionID: req.SessionID,
  1625  	})
  1626  	return trace.Wrap(err)
  1627  }
  1628  
  1629  // DeleteAllAppSessions removes all application web sessions.
  1630  func (c *Client) DeleteAllAppSessions(ctx context.Context) error {
  1631  	_, err := c.grpc.DeleteAllAppSessions(ctx, &emptypb.Empty{})
  1632  	return trace.Wrap(err)
  1633  }
  1634  
  1635  // DeleteAllSnowflakeSessions removes all Snowflake web sessions.
  1636  func (c *Client) DeleteAllSnowflakeSessions(ctx context.Context) error {
  1637  	_, err := c.grpc.DeleteAllSnowflakeSessions(ctx, &emptypb.Empty{})
  1638  	return trace.Wrap(err)
  1639  }
  1640  
  1641  // DeleteAllSAMLIdPSessions removes all SAML IdP sessions.
  1642  func (c *Client) DeleteAllSAMLIdPSessions(ctx context.Context) error {
  1643  	_, err := c.grpc.DeleteAllSAMLIdPSessions(ctx, &emptypb.Empty{})
  1644  	return trace.Wrap(err)
  1645  }
  1646  
  1647  // DeleteUserAppSessions deletes all user’s application sessions.
  1648  func (c *Client) DeleteUserAppSessions(ctx context.Context, req *proto.DeleteUserAppSessionsRequest) error {
  1649  	_, err := c.grpc.DeleteUserAppSessions(ctx, req)
  1650  	return trace.Wrap(err)
  1651  }
  1652  
  1653  // DeleteUserSAMLIdPSessions deletes all user’s SAML IdP sessions.
  1654  func (c *Client) DeleteUserSAMLIdPSessions(ctx context.Context, username string) error {
  1655  	req := &proto.DeleteUserSAMLIdPSessionsRequest{
  1656  		Username: username,
  1657  	}
  1658  	_, err := c.grpc.DeleteUserSAMLIdPSessions(ctx, req)
  1659  	return trace.Wrap(err)
  1660  }
  1661  
  1662  // GenerateAppToken creates a JWT token with application access.
  1663  func (c *Client) GenerateAppToken(ctx context.Context, req types.GenerateAppTokenRequest) (string, error) {
  1664  	traits := map[string]*wrappers.StringValues{}
  1665  	for traitName, traitValues := range req.Traits {
  1666  		traits[traitName] = &wrappers.StringValues{
  1667  			Values: traitValues,
  1668  		}
  1669  	}
  1670  	resp, err := c.grpc.GenerateAppToken(ctx, &proto.GenerateAppTokenRequest{
  1671  		Username: req.Username,
  1672  		Roles:    req.Roles,
  1673  		Traits:   traits,
  1674  		URI:      req.URI,
  1675  		Expires:  req.Expires,
  1676  	})
  1677  	if err != nil {
  1678  		return "", trace.Wrap(err)
  1679  	}
  1680  
  1681  	return resp.GetToken(), nil
  1682  }
  1683  
  1684  // GenerateSnowflakeJWT generates JWT in the Snowflake required format.
  1685  func (c *Client) GenerateSnowflakeJWT(ctx context.Context, req types.GenerateSnowflakeJWT) (string, error) {
  1686  	resp, err := c.grpc.GenerateSnowflakeJWT(ctx, &proto.SnowflakeJWTRequest{
  1687  		UserName:    req.Username,
  1688  		AccountName: req.Account,
  1689  	})
  1690  	if err != nil {
  1691  		return "", trace.Wrap(err)
  1692  	}
  1693  
  1694  	return resp.GetToken(), nil
  1695  }
  1696  
  1697  // GetDatabaseServers returns all registered database proxy servers.
  1698  //
  1699  // Note that in HA setups, a registered database may have multiple
  1700  // DatabaseServer entries. Web UI and `tsh db ls` extract databases from this
  1701  // list and remove duplicates by name.
  1702  func (c *Client) GetDatabaseServers(ctx context.Context, namespace string) ([]types.DatabaseServer, error) {
  1703  	servers, err := GetAllResources[types.DatabaseServer](ctx, c, &proto.ListResourcesRequest{
  1704  		Namespace:    namespace,
  1705  		ResourceType: types.KindDatabaseServer,
  1706  	})
  1707  	return servers, trace.Wrap(err)
  1708  }
  1709  
  1710  // UpsertDatabaseServer registers a new database proxy server.
  1711  func (c *Client) UpsertDatabaseServer(ctx context.Context, server types.DatabaseServer) (*types.KeepAlive, error) {
  1712  	s, ok := server.(*types.DatabaseServerV3)
  1713  	if !ok {
  1714  		return nil, trace.BadParameter("invalid type %T", server)
  1715  	}
  1716  	keepAlive, err := c.grpc.UpsertDatabaseServer(ctx, &proto.UpsertDatabaseServerRequest{
  1717  		Server: s,
  1718  	})
  1719  	if err != nil {
  1720  		return nil, trace.Wrap(err)
  1721  	}
  1722  	return keepAlive, nil
  1723  }
  1724  
  1725  // DeleteDatabaseServer removes the specified database proxy server.
  1726  func (c *Client) DeleteDatabaseServer(ctx context.Context, namespace, hostID, name string) error {
  1727  	_, err := c.grpc.DeleteDatabaseServer(ctx, &proto.DeleteDatabaseServerRequest{
  1728  		Namespace: namespace,
  1729  		HostID:    hostID,
  1730  		Name:      name,
  1731  	})
  1732  	if err != nil {
  1733  		return trace.Wrap(err)
  1734  	}
  1735  	return nil
  1736  }
  1737  
  1738  // DeleteAllDatabaseServers removes all registered database proxy servers.
  1739  func (c *Client) DeleteAllDatabaseServers(ctx context.Context, namespace string) error {
  1740  	_, err := c.grpc.DeleteAllDatabaseServers(ctx, &proto.DeleteAllDatabaseServersRequest{
  1741  		Namespace: namespace,
  1742  	})
  1743  	if err != nil {
  1744  		return trace.Wrap(err)
  1745  	}
  1746  	return nil
  1747  }
  1748  
  1749  // SignDatabaseCSR generates a client certificate used by proxy when talking
  1750  // to a remote database service.
  1751  func (c *Client) SignDatabaseCSR(ctx context.Context, req *proto.DatabaseCSRRequest) (*proto.DatabaseCSRResponse, error) {
  1752  	resp, err := c.grpc.SignDatabaseCSR(ctx, req)
  1753  	if err != nil {
  1754  		return nil, trace.Wrap(err)
  1755  	}
  1756  	return resp, nil
  1757  }
  1758  
  1759  // GenerateDatabaseCert generates a client certificate used by a database
  1760  // service to authenticate with the database instance, or a server certificate
  1761  // for configuring a self-hosted database, depending on the requester_name.
  1762  func (c *Client) GenerateDatabaseCert(ctx context.Context, req *proto.DatabaseCertRequest) (*proto.DatabaseCertResponse, error) {
  1763  	resp, err := c.grpc.GenerateDatabaseCert(ctx, req)
  1764  	if err != nil {
  1765  		return nil, trace.Wrap(err)
  1766  	}
  1767  	return resp, nil
  1768  }
  1769  
  1770  // GetRole returns role by name
  1771  func (c *Client) GetRole(ctx context.Context, name string) (types.Role, error) {
  1772  	if name == "" {
  1773  		return nil, trace.BadParameter("missing name")
  1774  	}
  1775  	role, err := c.grpc.GetRole(ctx, &proto.GetRoleRequest{Name: name})
  1776  	if err != nil {
  1777  		return nil, trace.Wrap(err)
  1778  	}
  1779  	return role, nil
  1780  }
  1781  
  1782  // GetRoles returns a list of roles
  1783  func (c *Client) GetRoles(ctx context.Context) ([]types.Role, error) {
  1784  	var roles []types.Role
  1785  	var req proto.ListRolesRequest
  1786  	for {
  1787  		rsp, err := c.ListRoles(ctx, &req)
  1788  		if err != nil {
  1789  			if trace.IsNotImplemented(err) {
  1790  				// fallback to calling the old non-paginated role API.
  1791  				roles, err = c.getRoles(ctx)
  1792  				return roles, trace.Wrap(err)
  1793  			}
  1794  			return nil, trace.Wrap(err)
  1795  		}
  1796  
  1797  		for _, r := range rsp.Roles {
  1798  			roles = append(roles, r)
  1799  		}
  1800  		req.StartKey = rsp.NextKey
  1801  		if req.StartKey == "" {
  1802  			break
  1803  		}
  1804  	}
  1805  
  1806  	return roles, nil
  1807  }
  1808  
  1809  // getRoles calls the old non-paginated GetRoles method.
  1810  //
  1811  // DELETE IN 17.0
  1812  func (c *Client) getRoles(ctx context.Context) ([]types.Role, error) {
  1813  	resp, err := c.grpc.GetRoles(ctx, &emptypb.Empty{})
  1814  	if err != nil {
  1815  		return nil, trace.Wrap(err)
  1816  	}
  1817  	roles := make([]types.Role, 0, len(resp.GetRoles()))
  1818  	for _, role := range resp.GetRoles() {
  1819  		roles = append(roles, role)
  1820  	}
  1821  	return roles, nil
  1822  }
  1823  
  1824  // ListRoles is a paginated role getter.
  1825  func (c *Client) ListRoles(ctx context.Context, req *proto.ListRolesRequest) (*proto.ListRolesResponse, error) {
  1826  	var header gmetadata.MD
  1827  	rsp, err := c.grpc.ListRoles(ctx, req, grpc.Header(&header))
  1828  	if err != nil {
  1829  		return nil, trace.Wrap(err)
  1830  	}
  1831  
  1832  	if req.Filter == nil {
  1833  		// remaining logic is all filter compat that we can skip
  1834  		return rsp, nil
  1835  	}
  1836  
  1837  	vs, _ := metadata.VersionFromMetadata(header)
  1838  	ver, _ := semver.NewVersion(vs)
  1839  	if ver != nil && ver.Major >= 16 {
  1840  		// auth implements all expected filtering features
  1841  		return rsp, nil
  1842  	}
  1843  
  1844  	filtered := rsp.Roles[:0]
  1845  	for _, role := range rsp.Roles {
  1846  		if req.Filter.Match(role) {
  1847  			filtered = append(filtered, role)
  1848  		}
  1849  	}
  1850  	rsp.Roles = filtered
  1851  
  1852  	return rsp, nil
  1853  }
  1854  
  1855  // CreateRole creates a new role.
  1856  func (c *Client) CreateRole(ctx context.Context, role types.Role) (types.Role, error) {
  1857  	r, ok := role.(*types.RoleV6)
  1858  	if !ok {
  1859  		return nil, trace.BadParameter("invalid type %T", role)
  1860  	}
  1861  
  1862  	created, err := c.grpc.CreateRole(ctx, &proto.CreateRoleRequest{Role: r})
  1863  	return created, trace.Wrap(err)
  1864  }
  1865  
  1866  // UpdateRole updates an already existing role.
  1867  func (c *Client) UpdateRole(ctx context.Context, role types.Role) (types.Role, error) {
  1868  	r, ok := role.(*types.RoleV6)
  1869  	if !ok {
  1870  		return nil, trace.BadParameter("invalid type %T", role)
  1871  	}
  1872  
  1873  	updated, err := c.grpc.UpdateRole(ctx, &proto.UpdateRoleRequest{Role: r})
  1874  	return updated, trace.Wrap(err)
  1875  }
  1876  
  1877  // UpsertRole creates or updates a role.
  1878  func (c *Client) UpsertRole(ctx context.Context, role types.Role) (types.Role, error) {
  1879  	r, ok := role.(*types.RoleV6)
  1880  	if !ok {
  1881  		return nil, trace.BadParameter("invalid type %T", role)
  1882  	}
  1883  
  1884  	upserted, err := c.grpc.UpsertRoleV2(ctx, &proto.UpsertRoleRequest{Role: r})
  1885  	if err != nil && trace.IsNotImplemented(err) {
  1886  		//nolint:staticcheck // SA1019. Kept for backward compatibility.
  1887  		_, err := c.grpc.UpsertRole(ctx, r)
  1888  		if err != nil {
  1889  			return nil, trace.Wrap(err)
  1890  		}
  1891  
  1892  		r, err := c.grpc.GetRole(ctx, &proto.GetRoleRequest{Name: role.GetName()})
  1893  		return r, trace.Wrap(err)
  1894  	}
  1895  
  1896  	return upserted, trace.Wrap(err)
  1897  }
  1898  
  1899  // DeleteRole deletes role by name
  1900  func (c *Client) DeleteRole(ctx context.Context, name string) error {
  1901  	if name == "" {
  1902  		return trace.BadParameter("missing name")
  1903  	}
  1904  	_, err := c.grpc.DeleteRole(ctx, &proto.DeleteRoleRequest{Name: name})
  1905  	return trace.Wrap(err)
  1906  }
  1907  
  1908  // AddMFADeviceSync adds a new MFA device.
  1909  func (c *Client) AddMFADeviceSync(ctx context.Context, in *proto.AddMFADeviceSyncRequest) (*proto.AddMFADeviceSyncResponse, error) {
  1910  	res, err := c.grpc.AddMFADeviceSync(ctx, in)
  1911  	return res, trace.Wrap(err)
  1912  }
  1913  
  1914  // DeleteMFADeviceSync deletes a users MFA device.
  1915  func (c *Client) DeleteMFADeviceSync(ctx context.Context, in *proto.DeleteMFADeviceSyncRequest) error {
  1916  	_, err := c.grpc.DeleteMFADeviceSync(ctx, in)
  1917  	return trace.Wrap(err)
  1918  }
  1919  
  1920  func (c *Client) GetMFADevices(ctx context.Context, in *proto.GetMFADevicesRequest) (*proto.GetMFADevicesResponse, error) {
  1921  	resp, err := c.grpc.GetMFADevices(ctx, in)
  1922  	if err != nil {
  1923  		return nil, trace.Wrap(err)
  1924  	}
  1925  	return resp, nil
  1926  }
  1927  
  1928  func (c *Client) IsMFARequired(ctx context.Context, req *proto.IsMFARequiredRequest) (*proto.IsMFARequiredResponse, error) {
  1929  	resp, err := c.grpc.IsMFARequired(ctx, req)
  1930  	if err != nil {
  1931  		return nil, trace.Wrap(err)
  1932  	}
  1933  	return resp, nil
  1934  }
  1935  
  1936  // GetOIDCConnector returns an OIDC connector by name.
  1937  func (c *Client) GetOIDCConnector(ctx context.Context, name string, withSecrets bool) (types.OIDCConnector, error) {
  1938  	if name == "" {
  1939  		return nil, trace.BadParameter("cannot get OIDC Connector, missing name")
  1940  	}
  1941  	req := &types.ResourceWithSecretsRequest{Name: name, WithSecrets: withSecrets}
  1942  	resp, err := c.grpc.GetOIDCConnector(ctx, req)
  1943  	if err != nil {
  1944  		return nil, trace.Wrap(err)
  1945  	}
  1946  	return resp, nil
  1947  }
  1948  
  1949  // GetOIDCConnectors returns a list of OIDC connectors.
  1950  func (c *Client) GetOIDCConnectors(ctx context.Context, withSecrets bool) ([]types.OIDCConnector, error) {
  1951  	req := &types.ResourcesWithSecretsRequest{WithSecrets: withSecrets}
  1952  	resp, err := c.grpc.GetOIDCConnectors(ctx, req)
  1953  	if err != nil {
  1954  		return nil, trace.Wrap(err)
  1955  	}
  1956  	oidcConnectors := make([]types.OIDCConnector, len(resp.OIDCConnectors))
  1957  	for i, oidcConnector := range resp.OIDCConnectors {
  1958  		oidcConnectors[i] = oidcConnector
  1959  	}
  1960  	return oidcConnectors, nil
  1961  }
  1962  
  1963  // CreateOIDCConnector creates an OIDC connector.
  1964  func (c *Client) CreateOIDCConnector(ctx context.Context, connector types.OIDCConnector) (types.OIDCConnector, error) {
  1965  	oidcConnector, ok := connector.(*types.OIDCConnectorV3)
  1966  	if !ok {
  1967  		return nil, trace.BadParameter("invalid type %T", connector)
  1968  	}
  1969  	conn, err := c.grpc.CreateOIDCConnector(ctx, &proto.CreateOIDCConnectorRequest{Connector: oidcConnector})
  1970  	return conn, trace.Wrap(err)
  1971  }
  1972  
  1973  // UpdateOIDCConnector updates an OIDC connector.
  1974  func (c *Client) UpdateOIDCConnector(ctx context.Context, connector types.OIDCConnector) (types.OIDCConnector, error) {
  1975  	oidcConnector, ok := connector.(*types.OIDCConnectorV3)
  1976  	if !ok {
  1977  		return nil, trace.BadParameter("invalid type %T", oidcConnector)
  1978  	}
  1979  	conn, err := c.grpc.UpdateOIDCConnector(ctx, &proto.UpdateOIDCConnectorRequest{Connector: oidcConnector})
  1980  	return conn, trace.Wrap(err)
  1981  }
  1982  
  1983  // UpsertOIDCConnector creates or updates an OIDC connector.
  1984  func (c *Client) UpsertOIDCConnector(ctx context.Context, oidcConnector types.OIDCConnector) (types.OIDCConnector, error) {
  1985  	connector, ok := oidcConnector.(*types.OIDCConnectorV3)
  1986  	if !ok {
  1987  		return nil, trace.BadParameter("invalid type %T", oidcConnector)
  1988  	}
  1989  
  1990  	upserted, err := c.grpc.UpsertOIDCConnectorV2(ctx, &proto.UpsertOIDCConnectorRequest{Connector: connector})
  1991  	// TODO(tross) DELETE IN 16.0.0
  1992  	if err != nil && trace.IsNotImplemented(err) {
  1993  		//nolint:staticcheck // SA1019. Kept for backward compatibility.
  1994  		if _, err := c.grpc.UpsertOIDCConnector(ctx, connector); err != nil {
  1995  			return nil, trace.Wrap(err)
  1996  		}
  1997  
  1998  		conn, err := c.GetOIDCConnector(ctx, oidcConnector.GetName(), false)
  1999  		if err != nil {
  2000  			return nil, trace.Wrap(err)
  2001  		}
  2002  
  2003  		// Override the secrets with the values from the passed in connector since
  2004  		// the call to GetOIDCConnector above did not request secrets.
  2005  		conn.SetClientSecret(connector.GetClientSecret())
  2006  		conn.SetGoogleServiceAccount(connector.GetGoogleServiceAccount())
  2007  
  2008  		return conn, nil
  2009  	}
  2010  	return upserted, trace.Wrap(err)
  2011  }
  2012  
  2013  // DeleteOIDCConnector deletes an OIDC connector by name.
  2014  func (c *Client) DeleteOIDCConnector(ctx context.Context, name string) error {
  2015  	if name == "" {
  2016  		return trace.BadParameter("cannot delete OIDC Connector, missing name")
  2017  	}
  2018  	_, err := c.grpc.DeleteOIDCConnector(ctx, &types.ResourceRequest{Name: name})
  2019  	return trace.Wrap(err)
  2020  }
  2021  
  2022  // CreateOIDCAuthRequest creates OIDCAuthRequest.
  2023  func (c *Client) CreateOIDCAuthRequest(ctx context.Context, req types.OIDCAuthRequest) (*types.OIDCAuthRequest, error) {
  2024  	resp, err := c.grpc.CreateOIDCAuthRequest(ctx, &req)
  2025  	if err != nil {
  2026  		return nil, trace.Wrap(err)
  2027  	}
  2028  	return resp, nil
  2029  }
  2030  
  2031  // GetOIDCAuthRequest gets an OIDCAuthRequest by state token.
  2032  func (c *Client) GetOIDCAuthRequest(ctx context.Context, stateToken string) (*types.OIDCAuthRequest, error) {
  2033  	req := &proto.GetOIDCAuthRequestRequest{StateToken: stateToken}
  2034  	resp, err := c.grpc.GetOIDCAuthRequest(ctx, req)
  2035  	if err != nil {
  2036  		return nil, trace.Wrap(err)
  2037  	}
  2038  	return resp, nil
  2039  }
  2040  
  2041  // GetSAMLConnector returns a SAML connector by name.
  2042  func (c *Client) GetSAMLConnector(ctx context.Context, name string, withSecrets bool) (types.SAMLConnector, error) {
  2043  	if name == "" {
  2044  		return nil, trace.BadParameter("cannot get SAML Connector, missing name")
  2045  	}
  2046  	req := &types.ResourceWithSecretsRequest{Name: name, WithSecrets: withSecrets}
  2047  	resp, err := c.grpc.GetSAMLConnector(ctx, req)
  2048  	if err != nil {
  2049  		return nil, trace.Wrap(err)
  2050  	}
  2051  	return resp, nil
  2052  }
  2053  
  2054  // GetSAMLConnectors returns a list of SAML connectors.
  2055  func (c *Client) GetSAMLConnectors(ctx context.Context, withSecrets bool) ([]types.SAMLConnector, error) {
  2056  	req := &types.ResourcesWithSecretsRequest{WithSecrets: withSecrets}
  2057  	resp, err := c.grpc.GetSAMLConnectors(ctx, req)
  2058  	if err != nil {
  2059  		return nil, trace.Wrap(err)
  2060  	}
  2061  	samlConnectors := make([]types.SAMLConnector, len(resp.SAMLConnectors))
  2062  	for i, samlConnector := range resp.SAMLConnectors {
  2063  		samlConnectors[i] = samlConnector
  2064  	}
  2065  	return samlConnectors, nil
  2066  }
  2067  
  2068  // CreateSAMLConnector creates a SAML connector.
  2069  func (c *Client) CreateSAMLConnector(ctx context.Context, connector types.SAMLConnector) (types.SAMLConnector, error) {
  2070  	samlConnectorV2, ok := connector.(*types.SAMLConnectorV2)
  2071  	if !ok {
  2072  		return nil, trace.BadParameter("invalid type %T", connector)
  2073  	}
  2074  	conn, err := c.grpc.CreateSAMLConnector(ctx, &proto.CreateSAMLConnectorRequest{Connector: samlConnectorV2})
  2075  	return conn, trace.Wrap(err)
  2076  }
  2077  
  2078  // UpdateSAMLConnector updates a SAML connector.
  2079  func (c *Client) UpdateSAMLConnector(ctx context.Context, connector types.SAMLConnector) (types.SAMLConnector, error) {
  2080  	samlConnectorV2, ok := connector.(*types.SAMLConnectorV2)
  2081  	if !ok {
  2082  		return nil, trace.BadParameter("invalid type %T", connector)
  2083  	}
  2084  	conn, err := c.grpc.UpdateSAMLConnector(ctx, &proto.UpdateSAMLConnectorRequest{Connector: samlConnectorV2})
  2085  	return conn, trace.Wrap(err)
  2086  }
  2087  
  2088  // UpsertSAMLConnector creates or updates a SAML connector.
  2089  func (c *Client) UpsertSAMLConnector(ctx context.Context, connector types.SAMLConnector) (types.SAMLConnector, error) {
  2090  	samlConnector, ok := connector.(*types.SAMLConnectorV2)
  2091  	if !ok {
  2092  		return nil, trace.BadParameter("invalid type %T", connector)
  2093  	}
  2094  
  2095  	upserted, err := c.grpc.UpsertSAMLConnectorV2(ctx, &proto.UpsertSAMLConnectorRequest{Connector: samlConnector})
  2096  	// TODO(tross) DELETE IN 16.0.0
  2097  	if err != nil && trace.IsNotImplemented(err) {
  2098  		//nolint:staticcheck // SA1019. Kept for backward compatibility.
  2099  		if _, err := c.grpc.UpsertSAMLConnector(ctx, samlConnector); err != nil {
  2100  			return nil, trace.Wrap(err)
  2101  		}
  2102  		conn, err := c.GetSAMLConnector(ctx, samlConnector.GetName(), false)
  2103  		if err != nil {
  2104  			return nil, trace.Wrap(err)
  2105  		}
  2106  
  2107  		// Override the secrets with the values from the passed in connector since
  2108  		// the call to GetSAMLConnector above did not request secrets.
  2109  		conn.SetSigningKeyPair(connector.GetSigningKeyPair())
  2110  
  2111  		return conn, nil
  2112  	}
  2113  	return upserted, trace.Wrap(err)
  2114  }
  2115  
  2116  // DeleteSAMLConnector deletes a SAML connector by name.
  2117  func (c *Client) DeleteSAMLConnector(ctx context.Context, name string) error {
  2118  	if name == "" {
  2119  		return trace.BadParameter("cannot delete SAML Connector, missing name")
  2120  	}
  2121  	_, err := c.grpc.DeleteSAMLConnector(ctx, &types.ResourceRequest{Name: name})
  2122  	return trace.Wrap(err)
  2123  }
  2124  
  2125  // CreateSAMLAuthRequest creates SAMLAuthRequest.
  2126  func (c *Client) CreateSAMLAuthRequest(ctx context.Context, req types.SAMLAuthRequest) (*types.SAMLAuthRequest, error) {
  2127  	resp, err := c.grpc.CreateSAMLAuthRequest(ctx, &req)
  2128  	if err != nil {
  2129  		return nil, trace.Wrap(err)
  2130  	}
  2131  	return resp, nil
  2132  }
  2133  
  2134  // GetSAMLAuthRequest gets a SAMLAuthRequest by id.
  2135  func (c *Client) GetSAMLAuthRequest(ctx context.Context, id string) (*types.SAMLAuthRequest, error) {
  2136  	req := &proto.GetSAMLAuthRequestRequest{ID: id}
  2137  	resp, err := c.grpc.GetSAMLAuthRequest(ctx, req)
  2138  	if err != nil {
  2139  		return nil, trace.Wrap(err)
  2140  	}
  2141  	return resp, nil
  2142  }
  2143  
  2144  // GetGithubConnector returns a Github connector by name.
  2145  func (c *Client) GetGithubConnector(ctx context.Context, name string, withSecrets bool) (types.GithubConnector, error) {
  2146  	if name == "" {
  2147  		return nil, trace.BadParameter("cannot get GitHub Connector, missing name")
  2148  	}
  2149  	req := &types.ResourceWithSecretsRequest{Name: name, WithSecrets: withSecrets}
  2150  	resp, err := c.grpc.GetGithubConnector(ctx, req)
  2151  	if err != nil {
  2152  		return nil, trace.Wrap(err)
  2153  	}
  2154  	return resp, nil
  2155  }
  2156  
  2157  // GetGithubConnectors returns a list of Github connectors.
  2158  func (c *Client) GetGithubConnectors(ctx context.Context, withSecrets bool) ([]types.GithubConnector, error) {
  2159  	req := &types.ResourcesWithSecretsRequest{WithSecrets: withSecrets}
  2160  	resp, err := c.grpc.GetGithubConnectors(ctx, req)
  2161  	if err != nil {
  2162  		return nil, trace.Wrap(err)
  2163  	}
  2164  	githubConnectors := make([]types.GithubConnector, len(resp.GithubConnectors))
  2165  	for i, githubConnector := range resp.GithubConnectors {
  2166  		githubConnectors[i] = githubConnector
  2167  	}
  2168  	return githubConnectors, nil
  2169  }
  2170  
  2171  // CreateGithubConnector creates a Github connector.
  2172  func (c *Client) CreateGithubConnector(ctx context.Context, connector types.GithubConnector) (types.GithubConnector, error) {
  2173  	githubConnector, ok := connector.(*types.GithubConnectorV3)
  2174  	if !ok {
  2175  		return nil, trace.BadParameter("invalid type %T", connector)
  2176  	}
  2177  	conn, err := c.grpc.CreateGithubConnector(ctx, &proto.CreateGithubConnectorRequest{Connector: githubConnector})
  2178  	return conn, trace.Wrap(err)
  2179  }
  2180  
  2181  // UpdateGithubConnector updates a Github connector.
  2182  func (c *Client) UpdateGithubConnector(ctx context.Context, connector types.GithubConnector) (types.GithubConnector, error) {
  2183  	githubConnector, ok := connector.(*types.GithubConnectorV3)
  2184  	if !ok {
  2185  		return nil, trace.BadParameter("invalid type %T", connector)
  2186  	}
  2187  	conn, err := c.grpc.UpdateGithubConnector(ctx, &proto.UpdateGithubConnectorRequest{Connector: githubConnector})
  2188  	return conn, trace.Wrap(err)
  2189  }
  2190  
  2191  // UpsertGithubConnector creates or updates a Github connector.
  2192  func (c *Client) UpsertGithubConnector(ctx context.Context, connector types.GithubConnector) (types.GithubConnector, error) {
  2193  	githubConnector, ok := connector.(*types.GithubConnectorV3)
  2194  	if !ok {
  2195  		return nil, trace.BadParameter("invalid type %T", connector)
  2196  	}
  2197  	conn, err := c.grpc.UpsertGithubConnectorV2(ctx, &proto.UpsertGithubConnectorRequest{Connector: githubConnector})
  2198  	// TODO(tross) DELETE IN 16.0.0
  2199  	if err != nil && trace.IsNotImplemented(err) {
  2200  		//nolint:staticcheck // SA1019. Kept for backward compatibility testing.
  2201  		if _, err := c.grpc.UpsertGithubConnector(ctx, githubConnector); err != nil {
  2202  			return nil, trace.Wrap(err)
  2203  		}
  2204  
  2205  		resp, err := c.grpc.GetGithubConnector(ctx, &types.ResourceWithSecretsRequest{Name: connector.GetName(), WithSecrets: false})
  2206  		if err != nil {
  2207  			return nil, trace.Wrap(err)
  2208  		}
  2209  
  2210  		// Override the client secret with the value from the passed in connector since
  2211  		// the call to GetGithubConnector above did not request secrets.
  2212  		resp.SetClientSecret(connector.GetClientSecret())
  2213  
  2214  		return resp, nil
  2215  	}
  2216  	return conn, trace.Wrap(err)
  2217  }
  2218  
  2219  // DeleteGithubConnector deletes a Github connector by name.
  2220  func (c *Client) DeleteGithubConnector(ctx context.Context, name string) error {
  2221  	if name == "" {
  2222  		return trace.BadParameter("cannot delete GitHub Connector, missing name")
  2223  	}
  2224  	_, err := c.grpc.DeleteGithubConnector(ctx, &types.ResourceRequest{Name: name})
  2225  	return trace.Wrap(err)
  2226  }
  2227  
  2228  // CreateGithubAuthRequest creates GithubAuthRequest.
  2229  func (c *Client) CreateGithubAuthRequest(ctx context.Context, req types.GithubAuthRequest) (*types.GithubAuthRequest, error) {
  2230  	resp, err := c.grpc.CreateGithubAuthRequest(ctx, &req)
  2231  	if err != nil {
  2232  		return nil, trace.Wrap(err)
  2233  	}
  2234  	return resp, nil
  2235  }
  2236  
  2237  // GetGithubAuthRequest gets a GithubAuthRequest by state token.
  2238  func (c *Client) GetGithubAuthRequest(ctx context.Context, stateToken string) (*types.GithubAuthRequest, error) {
  2239  	req := &proto.GetGithubAuthRequestRequest{StateToken: stateToken}
  2240  	resp, err := c.grpc.GetGithubAuthRequest(ctx, req)
  2241  	if err != nil {
  2242  		return nil, trace.Wrap(err)
  2243  	}
  2244  	return resp, nil
  2245  }
  2246  
  2247  // GetSSODiagnosticInfo returns SSO diagnostic info records for a specific SSO Auth request.
  2248  func (c *Client) GetSSODiagnosticInfo(ctx context.Context, authRequestKind string, authRequestID string) (*types.SSODiagnosticInfo, error) {
  2249  	req := &proto.GetSSODiagnosticInfoRequest{AuthRequestKind: authRequestKind, AuthRequestID: authRequestID}
  2250  	resp, err := c.grpc.GetSSODiagnosticInfo(ctx, req)
  2251  	if err != nil {
  2252  		return nil, trace.Wrap(err)
  2253  	}
  2254  	return resp, nil
  2255  }
  2256  
  2257  // GetServerInfos returns a stream of ServerInfos.
  2258  func (c *Client) GetServerInfos(ctx context.Context) stream.Stream[types.ServerInfo] {
  2259  	// set up cancelable context so that Stream.Done can close the stream if the caller
  2260  	// halts early.
  2261  	ctx, cancel := context.WithCancel(ctx)
  2262  
  2263  	serverInfos, err := c.grpc.GetServerInfos(ctx, &emptypb.Empty{})
  2264  	if err != nil {
  2265  		cancel()
  2266  		return stream.Fail[types.ServerInfo](trace.Wrap(err))
  2267  	}
  2268  	return stream.Func(func() (types.ServerInfo, error) {
  2269  		si, err := serverInfos.Recv()
  2270  		if err != nil {
  2271  			if errors.Is(err, io.EOF) {
  2272  				// io.EOF signals that stream has completed successfully
  2273  				return nil, io.EOF
  2274  			}
  2275  			return nil, trace.Wrap(err)
  2276  		}
  2277  		return si, nil
  2278  	}, cancel)
  2279  }
  2280  
  2281  // GetServerInfo returns a ServerInfo by name.
  2282  func (c *Client) GetServerInfo(ctx context.Context, name string) (types.ServerInfo, error) {
  2283  	if name == "" {
  2284  		return nil, trace.BadParameter("cannot get server info, missing name")
  2285  	}
  2286  	req := &types.ResourceRequest{Name: name}
  2287  	resp, err := c.grpc.GetServerInfo(ctx, req)
  2288  	if err != nil {
  2289  		return nil, trace.Wrap(err)
  2290  	}
  2291  	return resp, nil
  2292  }
  2293  
  2294  // UpsertServerInfo upserts a ServerInfo.
  2295  func (c *Client) UpsertServerInfo(ctx context.Context, serverInfo types.ServerInfo) error {
  2296  	si, ok := serverInfo.(*types.ServerInfoV1)
  2297  	if !ok {
  2298  		return trace.BadParameter("invalid type %T", serverInfo)
  2299  	}
  2300  	_, err := c.grpc.UpsertServerInfo(ctx, si)
  2301  	return trace.Wrap(err)
  2302  }
  2303  
  2304  // DeleteServerInfo deletes a ServerInfo by name.
  2305  func (c *Client) DeleteServerInfo(ctx context.Context, name string) error {
  2306  	if name == "" {
  2307  		return trace.BadParameter("cannot delete server info, missing name")
  2308  	}
  2309  	req := &types.ResourceRequest{Name: name}
  2310  	_, err := c.grpc.DeleteServerInfo(ctx, req)
  2311  	return trace.Wrap(err)
  2312  }
  2313  
  2314  // DeleteAllServerInfos deletes all ServerInfos.
  2315  func (c *Client) DeleteAllServerInfos(ctx context.Context) error {
  2316  	_, err := c.grpc.DeleteAllServerInfos(ctx, &emptypb.Empty{})
  2317  	return trace.Wrap(err)
  2318  }
  2319  
  2320  // GetTrustedCluster returns a Trusted Cluster by name.
  2321  func (c *Client) GetTrustedCluster(ctx context.Context, name string) (types.TrustedCluster, error) {
  2322  	if name == "" {
  2323  		return nil, trace.BadParameter("cannot get trusted cluster, missing name")
  2324  	}
  2325  	req := &types.ResourceRequest{Name: name}
  2326  	resp, err := c.grpc.GetTrustedCluster(ctx, req)
  2327  	if err != nil {
  2328  		return nil, trace.Wrap(err)
  2329  	}
  2330  	return resp, nil
  2331  }
  2332  
  2333  // GetTrustedClusters returns a list of Trusted Clusters.
  2334  func (c *Client) GetTrustedClusters(ctx context.Context) ([]types.TrustedCluster, error) {
  2335  	resp, err := c.grpc.GetTrustedClusters(ctx, &emptypb.Empty{})
  2336  	if err != nil {
  2337  		return nil, trace.Wrap(err)
  2338  	}
  2339  	trustedClusters := make([]types.TrustedCluster, len(resp.TrustedClusters))
  2340  	for i, trustedCluster := range resp.TrustedClusters {
  2341  		trustedClusters[i] = trustedCluster
  2342  	}
  2343  	return trustedClusters, nil
  2344  }
  2345  
  2346  // UpsertTrustedCluster creates or updates a Trusted Cluster.
  2347  func (c *Client) UpsertTrustedCluster(ctx context.Context, trusedCluster types.TrustedCluster) (types.TrustedCluster, error) {
  2348  	trustedCluster, ok := trusedCluster.(*types.TrustedClusterV2)
  2349  	if !ok {
  2350  		return nil, trace.BadParameter("invalid type %T", trusedCluster)
  2351  	}
  2352  	resp, err := c.grpc.UpsertTrustedCluster(ctx, trustedCluster)
  2353  	if err != nil {
  2354  		return nil, trace.Wrap(err)
  2355  	}
  2356  	return resp, nil
  2357  }
  2358  
  2359  // DeleteTrustedCluster deletes a Trusted Cluster by name.
  2360  func (c *Client) DeleteTrustedCluster(ctx context.Context, name string) error {
  2361  	if name == "" {
  2362  		return trace.BadParameter("cannot delete trusted cluster, missing name")
  2363  	}
  2364  	_, err := c.grpc.DeleteTrustedCluster(ctx, &types.ResourceRequest{Name: name})
  2365  	return trace.Wrap(err)
  2366  }
  2367  
  2368  // GetToken returns a provision token by name.
  2369  func (c *Client) GetToken(ctx context.Context, name string) (types.ProvisionToken, error) {
  2370  	if name == "" {
  2371  		return nil, trace.BadParameter("cannot get token, missing name")
  2372  	}
  2373  	resp, err := c.grpc.GetToken(ctx, &types.ResourceRequest{Name: name})
  2374  	if err != nil {
  2375  		return nil, trace.Wrap(err)
  2376  	}
  2377  	return resp, nil
  2378  }
  2379  
  2380  // GetTokens returns a list of active provision tokens for nodes and users.
  2381  func (c *Client) GetTokens(ctx context.Context) ([]types.ProvisionToken, error) {
  2382  	resp, err := c.grpc.GetTokens(ctx, &emptypb.Empty{})
  2383  	if err != nil {
  2384  		return nil, trace.Wrap(err)
  2385  	}
  2386  
  2387  	tokens := make([]types.ProvisionToken, len(resp.ProvisionTokens))
  2388  	for i, token := range resp.ProvisionTokens {
  2389  		tokens[i] = token
  2390  	}
  2391  	return tokens, nil
  2392  }
  2393  
  2394  // UpsertToken creates or updates a provision token.
  2395  func (c *Client) UpsertToken(ctx context.Context, token types.ProvisionToken) error {
  2396  	tokenV2, ok := token.(*types.ProvisionTokenV2)
  2397  	if !ok {
  2398  		return trace.BadParameter("invalid type %T", token)
  2399  	}
  2400  
  2401  	_, err := c.grpc.UpsertTokenV2(ctx, &proto.UpsertTokenV2Request{
  2402  		Token: &proto.UpsertTokenV2Request_V2{
  2403  			V2: tokenV2,
  2404  		},
  2405  	})
  2406  	return trace.Wrap(err)
  2407  }
  2408  
  2409  // CreateToken creates a provision token.
  2410  func (c *Client) CreateToken(ctx context.Context, token types.ProvisionToken) error {
  2411  	tokenV2, ok := token.(*types.ProvisionTokenV2)
  2412  	if !ok {
  2413  		return trace.BadParameter("invalid type %T", token)
  2414  	}
  2415  
  2416  	_, err := c.grpc.CreateTokenV2(ctx, &proto.CreateTokenV2Request{
  2417  		Token: &proto.CreateTokenV2Request_V2{
  2418  			V2: tokenV2,
  2419  		},
  2420  	})
  2421  	return trace.Wrap(err)
  2422  }
  2423  
  2424  // DeleteToken deletes a provision token by name.
  2425  func (c *Client) DeleteToken(ctx context.Context, name string) error {
  2426  	if name == "" {
  2427  		return trace.BadParameter("cannot delete token, missing name")
  2428  	}
  2429  	_, err := c.grpc.DeleteToken(ctx, &types.ResourceRequest{Name: name})
  2430  	return trace.Wrap(err)
  2431  }
  2432  
  2433  // GetNode returns a node by name and namespace.
  2434  func (c *Client) GetNode(ctx context.Context, namespace, name string) (types.Server, error) {
  2435  	resp, err := c.grpc.GetNode(ctx, &types.ResourceInNamespaceRequest{
  2436  		Name:      name,
  2437  		Namespace: namespace,
  2438  	})
  2439  	if err != nil {
  2440  		return nil, trace.Wrap(err)
  2441  	}
  2442  	return resp, nil
  2443  }
  2444  
  2445  // GetNodes returns a complete list of nodes that the user has access to in the given namespace.
  2446  func (c *Client) GetNodes(ctx context.Context, namespace string) ([]types.Server, error) {
  2447  	servers, err := GetAllResources[types.Server](ctx, c, &proto.ListResourcesRequest{
  2448  		ResourceType: types.KindNode,
  2449  		Namespace:    namespace,
  2450  	})
  2451  
  2452  	return servers, trace.Wrap(err)
  2453  }
  2454  
  2455  // UpsertNode is used by SSH servers to report their presence
  2456  // to the auth servers in form of heartbeat expiring after ttl period.
  2457  func (c *Client) UpsertNode(ctx context.Context, node types.Server) (*types.KeepAlive, error) {
  2458  	if node.GetNamespace() == "" {
  2459  		return nil, trace.BadParameter("missing node namespace")
  2460  	}
  2461  	serverV2, ok := node.(*types.ServerV2)
  2462  	if !ok {
  2463  		return nil, trace.BadParameter("invalid type %T", node)
  2464  	}
  2465  	keepAlive, err := c.grpc.UpsertNode(ctx, serverV2)
  2466  	if err != nil {
  2467  		return nil, trace.Wrap(err)
  2468  	}
  2469  	return keepAlive, nil
  2470  }
  2471  
  2472  // DeleteNode deletes a node by name and namespace.
  2473  func (c *Client) DeleteNode(ctx context.Context, namespace, name string) error {
  2474  	if namespace == "" {
  2475  		return trace.BadParameter("missing parameter namespace")
  2476  	}
  2477  	if name == "" {
  2478  		return trace.BadParameter("missing parameter name")
  2479  	}
  2480  	_, err := c.grpc.DeleteNode(ctx, &types.ResourceInNamespaceRequest{
  2481  		Name:      name,
  2482  		Namespace: namespace,
  2483  	})
  2484  	return trace.Wrap(err)
  2485  }
  2486  
  2487  // DeleteAllNodes deletes all nodes in a given namespace.
  2488  func (c *Client) DeleteAllNodes(ctx context.Context, namespace string) error {
  2489  	if namespace == "" {
  2490  		return trace.BadParameter("missing parameter namespace")
  2491  	}
  2492  	_, err := c.grpc.DeleteAllNodes(ctx, &types.ResourcesInNamespaceRequest{Namespace: namespace})
  2493  	return trace.Wrap(err)
  2494  }
  2495  
  2496  // StreamSessionEvents streams audit events from a given session recording.
  2497  func (c *Client) StreamSessionEvents(ctx context.Context, sessionID string, startIndex int64) (chan events.AuditEvent, chan error) {
  2498  	request := &proto.StreamSessionEventsRequest{
  2499  		SessionID:  sessionID,
  2500  		StartIndex: int32(startIndex),
  2501  	}
  2502  
  2503  	ch := make(chan events.AuditEvent)
  2504  	e := make(chan error, 1)
  2505  
  2506  	stream, err := c.grpc.StreamSessionEvents(ctx, request)
  2507  	if err != nil {
  2508  		e <- trace.Wrap(err)
  2509  		return ch, e
  2510  	}
  2511  
  2512  	go func() {
  2513  	outer:
  2514  		for {
  2515  			oneOf, err := stream.Recv()
  2516  			if err != nil {
  2517  				if !errors.Is(err, io.EOF) {
  2518  					e <- trace.Wrap(err)
  2519  				} else {
  2520  					close(ch)
  2521  				}
  2522  
  2523  				break outer
  2524  			}
  2525  
  2526  			event, err := events.FromOneOf(*oneOf)
  2527  			if err != nil {
  2528  				e <- trace.Wrap(err)
  2529  				break outer
  2530  			}
  2531  
  2532  			select {
  2533  			case ch <- event:
  2534  			case <-ctx.Done():
  2535  				e <- trace.Wrap(ctx.Err())
  2536  				break outer
  2537  			}
  2538  		}
  2539  	}()
  2540  
  2541  	return ch, e
  2542  }
  2543  
  2544  // SearchEvents allows searching for events with a full pagination support.
  2545  func (c *Client) SearchEvents(ctx context.Context, fromUTC, toUTC time.Time, namespace string, eventTypes []string, limit int, order types.EventOrder, startKey string) ([]events.AuditEvent, string, error) {
  2546  	request := &proto.GetEventsRequest{
  2547  		Namespace:  namespace,
  2548  		StartDate:  fromUTC,
  2549  		EndDate:    toUTC,
  2550  		EventTypes: eventTypes,
  2551  		Limit:      int32(limit),
  2552  		StartKey:   startKey,
  2553  		Order:      proto.Order(order),
  2554  	}
  2555  
  2556  	response, err := c.grpc.GetEvents(ctx, request)
  2557  	if err != nil {
  2558  		return nil, "", trace.Wrap(err)
  2559  	}
  2560  
  2561  	decodedEvents := make([]events.AuditEvent, 0, len(response.Items))
  2562  	for _, rawEvent := range response.Items {
  2563  		event, err := events.FromOneOf(*rawEvent)
  2564  		if err != nil {
  2565  			if trace.IsBadParameter(err) {
  2566  				slog.WarnContext(ctx, "skipping unknown event", "error", err)
  2567  				continue
  2568  			}
  2569  			return nil, "", trace.Wrap(err)
  2570  		}
  2571  		decodedEvents = append(decodedEvents, event)
  2572  	}
  2573  
  2574  	return decodedEvents, response.LastKey, nil
  2575  }
  2576  
  2577  // SearchUnstructuredEvents allows searching for events with a full pagination support
  2578  // and returns events in an unstructured format (json like).
  2579  // This method is used by the Teleport event-handler plugin to receive events
  2580  // from the auth server wihout having to support the Protobuf event schema.
  2581  func (c *Client) SearchUnstructuredEvents(ctx context.Context, fromUTC, toUTC time.Time, namespace string, eventTypes []string, limit int, order types.EventOrder, startKey string) ([]*auditlogpb.EventUnstructured, string, error) {
  2582  	request := &auditlogpb.GetUnstructuredEventsRequest{
  2583  		Namespace:  namespace,
  2584  		StartDate:  timestamppb.New(fromUTC),
  2585  		EndDate:    timestamppb.New(toUTC),
  2586  		EventTypes: eventTypes,
  2587  		Limit:      int32(limit),
  2588  		StartKey:   startKey,
  2589  		Order:      auditlogpb.Order(order),
  2590  	}
  2591  
  2592  	response, err := c.grpc.GetUnstructuredEvents(ctx, request)
  2593  	if err != nil {
  2594  		return nil, "", trace.Wrap(err)
  2595  	}
  2596  
  2597  	return response.Items, response.LastKey, nil
  2598  }
  2599  
  2600  // StreamUnstructuredSessionEvents streams audit events from a given session recording in an unstructured format.
  2601  // This method is used by the Teleport event-handler plugin to receive events
  2602  // from the auth server wihout having to support the Protobuf event schema.
  2603  func (c *Client) StreamUnstructuredSessionEvents(ctx context.Context, sessionID string, startIndex int64) (chan *auditlogpb.EventUnstructured, chan error) {
  2604  	request := &auditlogpb.StreamUnstructuredSessionEventsRequest{
  2605  		SessionId:  sessionID,
  2606  		StartIndex: int32(startIndex),
  2607  	}
  2608  
  2609  	ch := make(chan *auditlogpb.EventUnstructured)
  2610  	e := make(chan error, 1)
  2611  
  2612  	stream, err := c.grpc.StreamUnstructuredSessionEvents(ctx, request)
  2613  	if err != nil {
  2614  		if trace.IsNotImplemented(trace.Wrap(err)) {
  2615  			// If the server does not support the unstructured events API,
  2616  			// fallback to the legacy API.
  2617  			// This code patch shouldn't be triggered because the server
  2618  			// returns the error only if the client calls Recv() on the stream.
  2619  			// However, we keep this code patch here just in case there is a bug
  2620  			// on the client grpc side.
  2621  			c.streamUnstructuredSessionEventsFallback(ctx, sessionID, startIndex, ch, e)
  2622  		} else {
  2623  			e <- trace.Wrap(err)
  2624  		}
  2625  		return ch, e
  2626  	}
  2627  	go func() {
  2628  		for {
  2629  			event, err := stream.Recv()
  2630  			if err != nil {
  2631  				if !errors.Is(err, io.EOF) {
  2632  					// If the server does not support the unstructured events API, it will
  2633  					// return an error with code Unimplemented. This error is received
  2634  					// the first time the client calls Recv() on the stream.
  2635  					// If the client receives this error, it should fallback to the legacy
  2636  					// API that spins another goroutine to convert the events to the
  2637  					// unstructured format and sends them to the channel ch.
  2638  					// Once we decide to spin the goroutine, we can leave this loop without
  2639  					// reporting any error to the caller.
  2640  					if trace.IsNotImplemented(trace.Wrap(err)) {
  2641  						// If the server does not support the unstructured events API,
  2642  						// fallback to the legacy API.
  2643  						go c.streamUnstructuredSessionEventsFallback(ctx, sessionID, startIndex, ch, e)
  2644  						return
  2645  					}
  2646  					e <- trace.Wrap(err)
  2647  				} else {
  2648  					close(ch)
  2649  				}
  2650  				return
  2651  			}
  2652  
  2653  			select {
  2654  			case ch <- event:
  2655  			case <-ctx.Done():
  2656  				e <- trace.Wrap(ctx.Err())
  2657  				return
  2658  			}
  2659  		}
  2660  	}()
  2661  
  2662  	return ch, e
  2663  }
  2664  
  2665  // streamUnstructuredSessionEventsFallback is a fallback implementation of the
  2666  // StreamUnstructuredSessionEvents method that is used when the server does not
  2667  // support the unstructured events API. This method uses the old API to stream
  2668  // events from the server and converts them to the unstructured format. This
  2669  // method converts the events at event handler plugin side, which can cause
  2670  // the plugin to miss some events if the plugin is not updated to the latest
  2671  // version.
  2672  // NOTE(tigrato): This code was reintroduced in 15.0.0 because the gRPC method was renamed
  2673  // incorrectly in 13.1-14.3 which caused the server to return Unimplemented
  2674  // error to the client and the client to fallback to the legacy API.
  2675  // TODO(tigrato): DELETE IN 16.0.0
  2676  func (c *Client) streamUnstructuredSessionEventsFallback(ctx context.Context, sessionID string, startIndex int64, ch chan *auditlogpb.EventUnstructured, e chan error) {
  2677  	request := &proto.StreamSessionEventsRequest{
  2678  		SessionID:  sessionID,
  2679  		StartIndex: int32(startIndex),
  2680  	}
  2681  
  2682  	stream, err := c.grpc.StreamSessionEvents(ctx, request)
  2683  	if err != nil {
  2684  		e <- trace.Wrap(err)
  2685  		return
  2686  	}
  2687  
  2688  	go func() {
  2689  		for {
  2690  			oneOf, err := stream.Recv()
  2691  			if err != nil {
  2692  				if !errors.Is(err, io.EOF) {
  2693  					e <- trace.Wrap(err)
  2694  				} else {
  2695  					close(ch)
  2696  				}
  2697  
  2698  				return
  2699  			}
  2700  
  2701  			event, err := events.FromOneOf(*oneOf)
  2702  			if err != nil {
  2703  				e <- trace.Wrap(err)
  2704  				return
  2705  			}
  2706  
  2707  			unstructedEvent, err := events.ToUnstructured(event)
  2708  			if err != nil {
  2709  				e <- trace.Wrap(err)
  2710  				return
  2711  			}
  2712  
  2713  			select {
  2714  			case ch <- unstructedEvent:
  2715  			case <-ctx.Done():
  2716  				e <- trace.Wrap(ctx.Err())
  2717  				return
  2718  			}
  2719  		}
  2720  	}()
  2721  }
  2722  
  2723  // SearchSessionEvents allows searching for session events with a full pagination support.
  2724  func (c *Client) SearchSessionEvents(ctx context.Context, fromUTC time.Time, toUTC time.Time, limit int, order types.EventOrder, startKey string) ([]events.AuditEvent, string, error) {
  2725  	request := &proto.GetSessionEventsRequest{
  2726  		StartDate: fromUTC,
  2727  		EndDate:   toUTC,
  2728  		Limit:     int32(limit),
  2729  		StartKey:  startKey,
  2730  		Order:     proto.Order(order),
  2731  	}
  2732  
  2733  	response, err := c.grpc.GetSessionEvents(ctx, request)
  2734  	if err != nil {
  2735  		return nil, "", trace.Wrap(err)
  2736  	}
  2737  
  2738  	decodedEvents := make([]events.AuditEvent, 0, len(response.Items))
  2739  	for _, rawEvent := range response.Items {
  2740  		event, err := events.FromOneOf(*rawEvent)
  2741  		if err != nil {
  2742  			return nil, "", trace.Wrap(err)
  2743  		}
  2744  		decodedEvents = append(decodedEvents, event)
  2745  	}
  2746  
  2747  	return decodedEvents, response.LastKey, nil
  2748  }
  2749  
  2750  // ClusterConfigClient returns an unadorned Cluster Configuration client, using the underlying
  2751  // Auth gRPC connection.
  2752  func (c *Client) ClusterConfigClient() clusterconfigpb.ClusterConfigServiceClient {
  2753  	return clusterconfigpb.NewClusterConfigServiceClient(c.conn)
  2754  }
  2755  
  2756  // GetClusterNetworkingConfig gets cluster networking configuration.
  2757  func (c *Client) GetClusterNetworkingConfig(ctx context.Context) (types.ClusterNetworkingConfig, error) {
  2758  	resp, err := c.ClusterConfigClient().GetClusterNetworkingConfig(ctx, &clusterconfigpb.GetClusterNetworkingConfigRequest{})
  2759  	if err != nil && trace.IsNotImplemented(err) {
  2760  		resp, err = c.grpc.GetClusterNetworkingConfig(ctx, &emptypb.Empty{})
  2761  	}
  2762  	return resp, trace.Wrap(err)
  2763  }
  2764  
  2765  // SetClusterNetworkingConfig sets cluster networking configuration.
  2766  // Deprecated: Use UpdateClusterNetworkingConfig or UpsertClusterNetworkingConfig instead.
  2767  func (c *Client) SetClusterNetworkingConfig(ctx context.Context, netConfig *types.ClusterNetworkingConfigV2) error {
  2768  	_, err := c.grpc.SetClusterNetworkingConfig(ctx, netConfig)
  2769  	return trace.Wrap(err)
  2770  }
  2771  
  2772  // setClusterNetworkingConfig sets cluster networking configuration.
  2773  func (c *Client) setClusterNetworkingConfig(ctx context.Context, netConfig *types.ClusterNetworkingConfigV2) (types.ClusterNetworkingConfig, error) {
  2774  	_, err := c.grpc.SetClusterNetworkingConfig(ctx, netConfig)
  2775  	if err != nil {
  2776  		return nil, trace.Wrap(err)
  2777  	}
  2778  
  2779  	cfg, err := c.grpc.GetClusterNetworkingConfig(ctx, &emptypb.Empty{})
  2780  	return cfg, trace.Wrap(err)
  2781  }
  2782  
  2783  // UpdateClusterNetworkingConfig updates an existing cluster networking configuration.
  2784  func (c *Client) UpdateClusterNetworkingConfig(ctx context.Context, cfg types.ClusterNetworkingConfig) (types.ClusterNetworkingConfig, error) {
  2785  	v2, ok := cfg.(*types.ClusterNetworkingConfigV2)
  2786  	if !ok {
  2787  		return nil, trace.BadParameter("unsupported cluster networking config type %T", cfg)
  2788  	}
  2789  
  2790  	updated, err := c.ClusterConfigClient().UpdateClusterNetworkingConfig(ctx, &clusterconfigpb.UpdateClusterNetworkingConfigRequest{ClusterNetworkConfig: v2})
  2791  	// TODO(tross) DELETE IN v18.0.0
  2792  	if trace.IsNotImplemented(err) {
  2793  		cnc, err := c.setClusterNetworkingConfig(ctx, v2)
  2794  		return cnc, trace.Wrap(err)
  2795  	}
  2796  
  2797  	return updated, trace.Wrap(err)
  2798  }
  2799  
  2800  // UpsertClusterNetworkingConfig creates a new configuration or overwrites the existing cluster networking configuration.
  2801  func (c *Client) UpsertClusterNetworkingConfig(ctx context.Context, cfg types.ClusterNetworkingConfig) (types.ClusterNetworkingConfig, error) {
  2802  	v2, ok := cfg.(*types.ClusterNetworkingConfigV2)
  2803  	if !ok {
  2804  		return nil, trace.BadParameter("unsupported cluster networking config type %T", cfg)
  2805  	}
  2806  
  2807  	updated, err := c.ClusterConfigClient().UpsertClusterNetworkingConfig(ctx, &clusterconfigpb.UpsertClusterNetworkingConfigRequest{ClusterNetworkConfig: v2})
  2808  	// TODO(tross) DELETE IN v18.0.0
  2809  	if trace.IsNotImplemented(err) {
  2810  		cnc, err := c.setClusterNetworkingConfig(ctx, v2)
  2811  		return cnc, trace.Wrap(err)
  2812  	}
  2813  
  2814  	return updated, trace.Wrap(err)
  2815  }
  2816  
  2817  // ResetClusterNetworkingConfig resets cluster networking configuration to defaults.
  2818  func (c *Client) ResetClusterNetworkingConfig(ctx context.Context) error {
  2819  	_, err := c.ClusterConfigClient().ResetClusterNetworkingConfig(ctx, &clusterconfigpb.ResetClusterNetworkingConfigRequest{})
  2820  	if err != nil && trace.IsNotImplemented(err) {
  2821  		_, err := c.grpc.ResetClusterNetworkingConfig(ctx, &emptypb.Empty{})
  2822  		return trace.Wrap(err)
  2823  	}
  2824  
  2825  	return trace.Wrap(err)
  2826  }
  2827  
  2828  // GetSessionRecordingConfig gets session recording configuration.
  2829  func (c *Client) GetSessionRecordingConfig(ctx context.Context) (types.SessionRecordingConfig, error) {
  2830  	resp, err := c.ClusterConfigClient().GetSessionRecordingConfig(ctx, &clusterconfigpb.GetSessionRecordingConfigRequest{})
  2831  	if err != nil && trace.IsNotImplemented(err) {
  2832  		resp, err = c.grpc.GetSessionRecordingConfig(ctx, &emptypb.Empty{})
  2833  	}
  2834  
  2835  	return resp, trace.Wrap(err)
  2836  }
  2837  
  2838  // SetSessionRecordingConfig sets session recording configuration.
  2839  // Deprecated: Use UpdateSessionRecordingConfig or UpsertSessionRecordingConfig instead.
  2840  func (c *Client) SetSessionRecordingConfig(ctx context.Context, recConfig types.SessionRecordingConfig) error {
  2841  	recConfigV2, ok := recConfig.(*types.SessionRecordingConfigV2)
  2842  	if !ok {
  2843  		return trace.BadParameter("invalid type %T", recConfig)
  2844  	}
  2845  
  2846  	_, err := c.grpc.SetSessionRecordingConfig(ctx, recConfigV2)
  2847  	return trace.Wrap(err)
  2848  }
  2849  
  2850  // setSessionRecordingConfig sets session recording configuration.
  2851  func (c *Client) setSessionRecordingConfig(ctx context.Context, recConfig types.SessionRecordingConfig) (types.SessionRecordingConfig, error) {
  2852  	recConfigV2, ok := recConfig.(*types.SessionRecordingConfigV2)
  2853  	if !ok {
  2854  		return nil, trace.BadParameter("invalid type %T", recConfig)
  2855  	}
  2856  
  2857  	if _, err := c.grpc.SetSessionRecordingConfig(ctx, recConfigV2); err != nil {
  2858  		return nil, trace.Wrap(err)
  2859  	}
  2860  
  2861  	cfg, err := c.grpc.GetSessionRecordingConfig(ctx, &emptypb.Empty{})
  2862  	return cfg, trace.Wrap(err)
  2863  }
  2864  
  2865  // ResetSessionRecordingConfig resets session recording configuration to defaults.
  2866  func (c *Client) ResetSessionRecordingConfig(ctx context.Context) error {
  2867  	_, err := c.ClusterConfigClient().ResetSessionRecordingConfig(ctx, &clusterconfigpb.ResetSessionRecordingConfigRequest{})
  2868  	if err != nil && trace.IsNotImplemented(err) {
  2869  		_, err := c.grpc.ResetSessionRecordingConfig(ctx, &emptypb.Empty{})
  2870  		return trace.Wrap(err)
  2871  	}
  2872  
  2873  	return trace.Wrap(err)
  2874  }
  2875  
  2876  // UpdateSessionRecordingConfig updates an existing session recording configuration.
  2877  func (c *Client) UpdateSessionRecordingConfig(ctx context.Context, cfg types.SessionRecordingConfig) (types.SessionRecordingConfig, error) {
  2878  	v2, ok := cfg.(*types.SessionRecordingConfigV2)
  2879  	if !ok {
  2880  		return nil, trace.BadParameter("unsupported session recording config type %T", cfg)
  2881  	}
  2882  
  2883  	updated, err := c.ClusterConfigClient().UpdateSessionRecordingConfig(ctx, &clusterconfigpb.UpdateSessionRecordingConfigRequest{SessionRecordingConfig: v2})
  2884  	// TODO(tross) DELETE IN v18.0.0
  2885  	if trace.IsNotImplemented(err) {
  2886  		cfg, err = c.setSessionRecordingConfig(ctx, v2)
  2887  		return cfg, trace.Wrap(err)
  2888  	}
  2889  	return updated, trace.Wrap(err)
  2890  }
  2891  
  2892  // UpsertSessionRecordingConfig creates a new configuration or overwrites the existing session recording configuration.
  2893  func (c *Client) UpsertSessionRecordingConfig(ctx context.Context, cfg types.SessionRecordingConfig) (types.SessionRecordingConfig, error) {
  2894  	v2, ok := cfg.(*types.SessionRecordingConfigV2)
  2895  	if !ok {
  2896  		return nil, trace.BadParameter("unsupported session recording config type %T", cfg)
  2897  	}
  2898  
  2899  	updated, err := c.ClusterConfigClient().UpsertSessionRecordingConfig(ctx, &clusterconfigpb.UpsertSessionRecordingConfigRequest{SessionRecordingConfig: v2})
  2900  	// TODO(tross) DELETE IN v18.0.0
  2901  	if trace.IsNotImplemented(err) {
  2902  		cfg, err = c.setSessionRecordingConfig(ctx, v2)
  2903  		return cfg, trace.Wrap(err)
  2904  	}
  2905  	return updated, trace.Wrap(err)
  2906  }
  2907  
  2908  // GetAuthPreference gets the active cluster auth preference.
  2909  func (c *Client) GetAuthPreference(ctx context.Context) (types.AuthPreference, error) {
  2910  	pref, err := c.ClusterConfigClient().GetAuthPreference(ctx, &clusterconfigpb.GetAuthPreferenceRequest{})
  2911  	// TODO(tross) DELETE IN v18.0.0
  2912  	if err != nil && trace.IsNotImplemented(err) {
  2913  		pref, err = c.grpc.GetAuthPreference(ctx, &emptypb.Empty{})
  2914  		if err != nil {
  2915  			return nil, trace.Wrap(err)
  2916  		}
  2917  
  2918  		// An old server would send PIVSlot instead of HardwareKey.PIVSlot
  2919  		// TODO(Joerger): DELETE IN 17.0.0
  2920  		pref.CheckSetPIVSlot()
  2921  	}
  2922  
  2923  	return pref, trace.Wrap(err)
  2924  }
  2925  
  2926  // SetAuthPreference sets cluster auth preference via the legacy mechanism.
  2927  // Deprecated: Use UpdateAuthPreference or UpsertAuthPreference instead.
  2928  // TODO(tross) DELETE IN v18.0.0
  2929  func (c *Client) SetAuthPreference(ctx context.Context, authPref types.AuthPreference) error {
  2930  	authPrefV2, ok := authPref.(*types.AuthPreferenceV2)
  2931  	if !ok {
  2932  		return trace.BadParameter("invalid type %T", authPref)
  2933  	}
  2934  
  2935  	// An old server would expect PIVSlot instead of HardwareKey.PIVSlot
  2936  	// TODO(Joerger): DELETE IN 17.0.0
  2937  	authPrefV2.CheckSetPIVSlot()
  2938  
  2939  	_, err := c.grpc.SetAuthPreference(ctx, authPrefV2)
  2940  	return trace.Wrap(err)
  2941  }
  2942  
  2943  // setAuthPreference sets cluster auth preference via the legacy mechanism.
  2944  // TODO(tross) DELETE IN v18.0.0
  2945  func (c *Client) setAuthPreference(ctx context.Context, authPref *types.AuthPreferenceV2) (types.AuthPreference, error) {
  2946  	// An old server would expect PIVSlot instead of HardwareKey.PIVSlot
  2947  	// TODO(Joerger): DELETE IN 17.0.0
  2948  	authPref.CheckSetPIVSlot()
  2949  
  2950  	_, err := c.grpc.SetAuthPreference(ctx, authPref)
  2951  	if err != nil {
  2952  		return nil, trace.Wrap(err)
  2953  	}
  2954  
  2955  	pref, err := c.grpc.GetAuthPreference(ctx, &emptypb.Empty{})
  2956  	return pref, trace.Wrap(err)
  2957  }
  2958  
  2959  // ResetAuthPreference resets cluster auth preference to defaults.
  2960  func (c *Client) ResetAuthPreference(ctx context.Context) error {
  2961  	_, err := c.ClusterConfigClient().ResetAuthPreference(ctx, &clusterconfigpb.ResetAuthPreferenceRequest{})
  2962  	// TODO(tross) DELETE IN v18.0.0
  2963  	if err != nil && trace.IsNotImplemented(err) {
  2964  		_, err := c.grpc.ResetAuthPreference(ctx, &emptypb.Empty{})
  2965  		return trace.Wrap(err)
  2966  	}
  2967  	return trace.Wrap(err)
  2968  }
  2969  
  2970  // UpdateAuthPreference updates an existing auth preference.
  2971  func (c *Client) UpdateAuthPreference(ctx context.Context, p types.AuthPreference) (types.AuthPreference, error) {
  2972  	v2, ok := p.(*types.AuthPreferenceV2)
  2973  	if !ok {
  2974  		return nil, trace.BadParameter("unsupported auth preference type %T", p)
  2975  	}
  2976  
  2977  	updated, err := c.ClusterConfigClient().UpdateAuthPreference(ctx, &clusterconfigpb.UpdateAuthPreferenceRequest{AuthPreference: v2})
  2978  	// TODO(tross) DELETE IN v18.0.0
  2979  	if trace.IsNotImplemented(err) {
  2980  		pref, err := c.setAuthPreference(ctx, v2)
  2981  		return pref, trace.Wrap(err)
  2982  	}
  2983  	return updated, trace.Wrap(err)
  2984  }
  2985  
  2986  // UpsertAuthPreference creates a new preference or overwrites the existing auth preference.
  2987  func (c *Client) UpsertAuthPreference(ctx context.Context, p types.AuthPreference) (types.AuthPreference, error) {
  2988  	v2, ok := p.(*types.AuthPreferenceV2)
  2989  	if !ok {
  2990  		return nil, trace.BadParameter("unsupported auth preference type %T", p)
  2991  	}
  2992  
  2993  	updated, err := c.ClusterConfigClient().UpsertAuthPreference(ctx, &clusterconfigpb.UpsertAuthPreferenceRequest{AuthPreference: v2})
  2994  	// TODO(tross) DELETE IN v18.0.0
  2995  	if trace.IsNotImplemented(err) {
  2996  		pref, err := c.setAuthPreference(ctx, v2)
  2997  		return pref, trace.Wrap(err)
  2998  	}
  2999  	return updated, trace.Wrap(err)
  3000  }
  3001  
  3002  // GetClusterAuditConfig gets cluster audit configuration.
  3003  func (c *Client) GetClusterAuditConfig(ctx context.Context) (types.ClusterAuditConfig, error) {
  3004  	resp, err := c.grpc.GetClusterAuditConfig(ctx, &emptypb.Empty{})
  3005  	if err != nil {
  3006  		return nil, trace.Wrap(err)
  3007  	}
  3008  	return resp, nil
  3009  }
  3010  
  3011  // GetClusterAccessGraphConfig retrieves the Cluster Access Graph configuration from Auth server.
  3012  func (c *Client) GetClusterAccessGraphConfig(ctx context.Context) (*clusterconfigpb.AccessGraphConfig, error) {
  3013  	rsp, err := c.ClusterConfigClient().GetClusterAccessGraphConfig(ctx, &clusterconfigpb.GetClusterAccessGraphConfigRequest{})
  3014  	if err != nil {
  3015  		return nil, trace.Wrap(err)
  3016  	}
  3017  	return rsp.AccessGraph, nil
  3018  }
  3019  
  3020  // GetInstaller gets all installer script resources
  3021  func (c *Client) GetInstallers(ctx context.Context) ([]types.Installer, error) {
  3022  	resp, err := c.grpc.GetInstallers(ctx, &emptypb.Empty{})
  3023  	if err != nil {
  3024  		return nil, trace.Wrap(err)
  3025  	}
  3026  	installers := make([]types.Installer, len(resp.Installers))
  3027  	for i, inst := range resp.Installers {
  3028  		installers[i] = inst
  3029  	}
  3030  	return installers, nil
  3031  }
  3032  
  3033  // GetUIConfig gets the configuration for the UI served by the proxy service
  3034  func (c *Client) GetUIConfig(ctx context.Context) (types.UIConfig, error) {
  3035  	resp, err := c.grpc.GetUIConfig(ctx, &emptypb.Empty{})
  3036  	return resp, trace.Wrap(err)
  3037  }
  3038  
  3039  // SetUIConfig sets the configuration for the UI served by the proxy service
  3040  func (c *Client) SetUIConfig(ctx context.Context, uic types.UIConfig) error {
  3041  	uicV1, ok := uic.(*types.UIConfigV1)
  3042  	if !ok {
  3043  		return trace.BadParameter("invalid type %T", uic)
  3044  	}
  3045  	_, err := c.grpc.SetUIConfig(ctx, uicV1)
  3046  	return trace.Wrap(err)
  3047  }
  3048  
  3049  func (c *Client) DeleteUIConfig(ctx context.Context) error {
  3050  	_, err := c.grpc.DeleteUIConfig(ctx, &emptypb.Empty{})
  3051  	return trace.Wrap(err)
  3052  }
  3053  
  3054  // GetInstaller gets the cluster installer resource
  3055  func (c *Client) GetInstaller(ctx context.Context, name string) (types.Installer, error) {
  3056  	resp, err := c.grpc.GetInstaller(ctx, &types.ResourceRequest{Name: name})
  3057  	if err != nil {
  3058  		return nil, trace.Wrap(err)
  3059  	}
  3060  	return resp, nil
  3061  }
  3062  
  3063  // SetInstaller sets the cluster installer resource
  3064  func (c *Client) SetInstaller(ctx context.Context, inst types.Installer) error {
  3065  	instV1, ok := inst.(*types.InstallerV1)
  3066  	if !ok {
  3067  		return trace.BadParameter("invalid type %T", inst)
  3068  	}
  3069  	_, err := c.grpc.SetInstaller(ctx, instV1)
  3070  	return trace.Wrap(err)
  3071  }
  3072  
  3073  // DeleteInstaller deletes the cluster installer resource
  3074  func (c *Client) DeleteInstaller(ctx context.Context, name string) error {
  3075  	_, err := c.grpc.DeleteInstaller(ctx, &types.ResourceRequest{Name: name})
  3076  	return trace.Wrap(err)
  3077  }
  3078  
  3079  // DeleteAllInstallers deletes all the installer resources.
  3080  func (c *Client) DeleteAllInstallers(ctx context.Context) error {
  3081  	_, err := c.grpc.DeleteAllInstallers(ctx, &emptypb.Empty{})
  3082  	return trace.Wrap(err)
  3083  }
  3084  
  3085  // GetLock gets a lock by name.
  3086  func (c *Client) GetLock(ctx context.Context, name string) (types.Lock, error) {
  3087  	if name == "" {
  3088  		return nil, trace.BadParameter("missing lock name")
  3089  	}
  3090  	resp, err := c.grpc.GetLock(ctx, &proto.GetLockRequest{Name: name})
  3091  	if err != nil {
  3092  		return nil, trace.Wrap(err)
  3093  	}
  3094  	return resp, nil
  3095  }
  3096  
  3097  // GetLocks gets all/in-force locks that match at least one of the targets when specified.
  3098  func (c *Client) GetLocks(ctx context.Context, inForceOnly bool, targets ...types.LockTarget) ([]types.Lock, error) {
  3099  	targetPtrs := make([]*types.LockTarget, len(targets))
  3100  	for i := range targets {
  3101  		targetPtrs[i] = &targets[i]
  3102  	}
  3103  	resp, err := c.grpc.GetLocks(ctx, &proto.GetLocksRequest{
  3104  		InForceOnly: inForceOnly,
  3105  		Targets:     targetPtrs,
  3106  	})
  3107  	if err != nil {
  3108  		return nil, trace.Wrap(err)
  3109  	}
  3110  	locks := make([]types.Lock, 0, len(resp.Locks))
  3111  	for _, lock := range resp.Locks {
  3112  		locks = append(locks, lock)
  3113  	}
  3114  	return locks, nil
  3115  }
  3116  
  3117  // UpsertLock upserts a lock.
  3118  func (c *Client) UpsertLock(ctx context.Context, lock types.Lock) error {
  3119  	lockV2, ok := lock.(*types.LockV2)
  3120  	if !ok {
  3121  		return trace.BadParameter("invalid type %T", lock)
  3122  	}
  3123  	_, err := c.grpc.UpsertLock(ctx, lockV2)
  3124  	return trace.Wrap(err)
  3125  }
  3126  
  3127  // DeleteLock deletes a lock.
  3128  func (c *Client) DeleteLock(ctx context.Context, name string) error {
  3129  	if name == "" {
  3130  		return trace.BadParameter("missing lock name")
  3131  	}
  3132  	_, err := c.grpc.DeleteLock(ctx, &proto.DeleteLockRequest{Name: name})
  3133  	return trace.Wrap(err)
  3134  }
  3135  
  3136  // ReplaceRemoteLocks replaces the set of locks associated with a remote cluster.
  3137  func (c *Client) ReplaceRemoteLocks(ctx context.Context, clusterName string, locks []types.Lock) error {
  3138  	if clusterName == "" {
  3139  		return trace.BadParameter("missing cluster name")
  3140  	}
  3141  	lockV2s := make([]*types.LockV2, 0, len(locks))
  3142  	for _, lock := range locks {
  3143  		lockV2, ok := lock.(*types.LockV2)
  3144  		if !ok {
  3145  			return trace.BadParameter("unexpected lock type %T", lock)
  3146  		}
  3147  		lockV2s = append(lockV2s, lockV2)
  3148  	}
  3149  	_, err := c.grpc.ReplaceRemoteLocks(ctx, &proto.ReplaceRemoteLocksRequest{
  3150  		ClusterName: clusterName,
  3151  		Locks:       lockV2s,
  3152  	})
  3153  	return trace.Wrap(err)
  3154  }
  3155  
  3156  // GetNetworkRestrictions retrieves the network restrictions
  3157  func (c *Client) GetNetworkRestrictions(ctx context.Context) (types.NetworkRestrictions, error) {
  3158  	nr, err := c.grpc.GetNetworkRestrictions(ctx, &emptypb.Empty{})
  3159  	if err != nil {
  3160  		return nil, trace.Wrap(err)
  3161  	}
  3162  	return nr, nil
  3163  }
  3164  
  3165  // SetNetworkRestrictions updates the network restrictions
  3166  func (c *Client) SetNetworkRestrictions(ctx context.Context, nr types.NetworkRestrictions) error {
  3167  	restrictionsV4, ok := nr.(*types.NetworkRestrictionsV4)
  3168  	if !ok {
  3169  		return trace.BadParameter("invalid type %T", nr)
  3170  	}
  3171  	_, err := c.grpc.SetNetworkRestrictions(ctx, restrictionsV4)
  3172  	if err != nil {
  3173  		return trace.Wrap(err)
  3174  	}
  3175  	return nil
  3176  }
  3177  
  3178  // DeleteNetworkRestrictions deletes the network restrictions
  3179  func (c *Client) DeleteNetworkRestrictions(ctx context.Context) error {
  3180  	_, err := c.grpc.DeleteNetworkRestrictions(ctx, &emptypb.Empty{})
  3181  	if err != nil {
  3182  		return trace.Wrap(err)
  3183  	}
  3184  	return nil
  3185  }
  3186  
  3187  // CreateApp creates a new application resource.
  3188  func (c *Client) CreateApp(ctx context.Context, app types.Application) error {
  3189  	appV3, ok := app.(*types.AppV3)
  3190  	if !ok {
  3191  		return trace.BadParameter("unsupported application type %T", app)
  3192  	}
  3193  	_, err := c.grpc.CreateApp(ctx, appV3)
  3194  	return trace.Wrap(err)
  3195  }
  3196  
  3197  // UpdateApp updates existing application resource.
  3198  func (c *Client) UpdateApp(ctx context.Context, app types.Application) error {
  3199  	appV3, ok := app.(*types.AppV3)
  3200  	if !ok {
  3201  		return trace.BadParameter("unsupported application type %T", app)
  3202  	}
  3203  	_, err := c.grpc.UpdateApp(ctx, appV3)
  3204  	return trace.Wrap(err)
  3205  }
  3206  
  3207  // GetApp returns the specified application resource.
  3208  //
  3209  // Note that application resources here refers to "dynamically-added"
  3210  // applications such as applications created by `tctl create`, or the CreateApp
  3211  // API. Applications defined in the `app_service.apps` section of the service
  3212  // YAML configuration are not collected in this API.
  3213  //
  3214  // For a full list of registered applications that are served by an application
  3215  // service, use GetApplicationServers instead.
  3216  func (c *Client) GetApp(ctx context.Context, name string) (types.Application, error) {
  3217  	if name == "" {
  3218  		return nil, trace.BadParameter("missing application name")
  3219  	}
  3220  	app, err := c.grpc.GetApp(ctx, &types.ResourceRequest{Name: name})
  3221  	if err != nil {
  3222  		return nil, trace.Wrap(err)
  3223  	}
  3224  	return app, nil
  3225  }
  3226  
  3227  // GetApps returns all application resources.
  3228  //
  3229  // Note that application resources here refers to "dynamically-added"
  3230  // applications such as applications created by `tctl create`, or the CreateApp
  3231  // API. Applications defined in the `app_service.apps` section of the service
  3232  // YAML configuration are not collected in this API.
  3233  //
  3234  // For a full list of registered applications that are served by an application
  3235  // service, use GetApplicationServers instead.
  3236  func (c *Client) GetApps(ctx context.Context) ([]types.Application, error) {
  3237  	items, err := c.grpc.GetApps(ctx, &emptypb.Empty{})
  3238  	if err != nil {
  3239  		return nil, trace.Wrap(err)
  3240  	}
  3241  	apps := make([]types.Application, len(items.Apps))
  3242  	for i := range items.Apps {
  3243  		apps[i] = items.Apps[i]
  3244  	}
  3245  	return apps, nil
  3246  }
  3247  
  3248  // DeleteApp deletes specified application resource.
  3249  func (c *Client) DeleteApp(ctx context.Context, name string) error {
  3250  	_, err := c.grpc.DeleteApp(ctx, &types.ResourceRequest{Name: name})
  3251  	return trace.Wrap(err)
  3252  }
  3253  
  3254  // DeleteAllApps deletes all application resources.
  3255  func (c *Client) DeleteAllApps(ctx context.Context) error {
  3256  	_, err := c.grpc.DeleteAllApps(ctx, &emptypb.Empty{})
  3257  	return trace.Wrap(err)
  3258  }
  3259  
  3260  // CreateKubernetesCluster creates a new kubernetes cluster resource.
  3261  func (c *Client) CreateKubernetesCluster(ctx context.Context, cluster types.KubeCluster) error {
  3262  	kubeClusterV3, ok := cluster.(*types.KubernetesClusterV3)
  3263  	if !ok {
  3264  		return trace.BadParameter("unsupported kubernetes cluster type %T", cluster)
  3265  	}
  3266  	_, err := c.grpc.CreateKubernetesCluster(ctx, kubeClusterV3)
  3267  	return trace.Wrap(err)
  3268  }
  3269  
  3270  // UpdateKubernetesCluster updates existing kubernetes cluster resource.
  3271  func (c *Client) UpdateKubernetesCluster(ctx context.Context, cluster types.KubeCluster) error {
  3272  	kubeClusterV3, ok := cluster.(*types.KubernetesClusterV3)
  3273  	if !ok {
  3274  		return trace.BadParameter("unsupported kubernetes cluster type %T", cluster)
  3275  	}
  3276  	_, err := c.grpc.UpdateKubernetesCluster(ctx, kubeClusterV3)
  3277  	return trace.Wrap(err)
  3278  }
  3279  
  3280  // GetKubernetesCluster returns the specified kubernetes resource.
  3281  func (c *Client) GetKubernetesCluster(ctx context.Context, name string) (types.KubeCluster, error) {
  3282  	if name == "" {
  3283  		return nil, trace.BadParameter("missing kubernetes cluster name")
  3284  	}
  3285  	cluster, err := c.grpc.GetKubernetesCluster(ctx, &types.ResourceRequest{Name: name})
  3286  	if err != nil {
  3287  		return nil, trace.Wrap(err)
  3288  	}
  3289  	return cluster, nil
  3290  }
  3291  
  3292  // GetKubernetesClusters returns all kubernetes cluster resources.
  3293  func (c *Client) GetKubernetesClusters(ctx context.Context) ([]types.KubeCluster, error) {
  3294  	items, err := c.grpc.GetKubernetesClusters(ctx, &emptypb.Empty{})
  3295  	if err != nil {
  3296  		return nil, trace.Wrap(err)
  3297  	}
  3298  	clusters := make([]types.KubeCluster, len(items.KubernetesClusters))
  3299  	for i := range items.KubernetesClusters {
  3300  		clusters[i] = items.KubernetesClusters[i]
  3301  	}
  3302  	return clusters, nil
  3303  }
  3304  
  3305  // DeleteKubernetesCluster deletes specified kubernetes cluster resource.
  3306  func (c *Client) DeleteKubernetesCluster(ctx context.Context, name string) error {
  3307  	_, err := c.grpc.DeleteKubernetesCluster(ctx, &types.ResourceRequest{Name: name})
  3308  	return trace.Wrap(err)
  3309  }
  3310  
  3311  // DeleteAllKubernetesClusters deletes all kubernetes cluster resources.
  3312  func (c *Client) DeleteAllKubernetesClusters(ctx context.Context) error {
  3313  	_, err := c.grpc.DeleteAllKubernetesClusters(ctx, &emptypb.Empty{})
  3314  	return trace.Wrap(err)
  3315  }
  3316  
  3317  // GetKubernetesWaitingContainerClient an unadorned KubeWaitingContainers
  3318  // client, using the underlying Auth gRPC connection.
  3319  func (c *Client) GetKubernetesWaitingContainerClient() *kubewaitingcontainerclient.Client {
  3320  	return kubewaitingcontainerclient.NewClient(kubewaitingcontainerpb.NewKubeWaitingContainersServiceClient(c.conn))
  3321  }
  3322  
  3323  // ListKubernetesWaitingContainers lists Kubernetes ephemeral
  3324  // containers that are waiting to be created until moderated
  3325  // session conditions are met.
  3326  func (c *Client) ListKubernetesWaitingContainers(ctx context.Context, pageSize int, pageToken string) ([]*kubewaitingcontainerpb.KubernetesWaitingContainer, string, error) {
  3327  	return c.GetKubernetesWaitingContainerClient().ListKubernetesWaitingContainers(ctx, pageSize, pageToken)
  3328  }
  3329  
  3330  // GetKubernetesWaitingContainer returns a Kubernetes ephemeral
  3331  // container that are waiting to be created until moderated
  3332  // session conditions are met.
  3333  func (c *Client) GetKubernetesWaitingContainer(ctx context.Context, req *kubewaitingcontainerpb.GetKubernetesWaitingContainerRequest) (*kubewaitingcontainerpb.KubernetesWaitingContainer, error) {
  3334  	return c.GetKubernetesWaitingContainerClient().GetKubernetesWaitingContainer(ctx, req)
  3335  }
  3336  
  3337  // CreateKubernetesWaitingContainer creates a Kubernetes ephemeral
  3338  // container that are waiting to be created until moderated
  3339  // session conditions are met.
  3340  func (c *Client) CreateKubernetesWaitingContainer(ctx context.Context, waitingPod *kubewaitingcontainerpb.KubernetesWaitingContainer) (*kubewaitingcontainerpb.KubernetesWaitingContainer, error) {
  3341  	return c.GetKubernetesWaitingContainerClient().CreateKubernetesWaitingContainer(ctx, waitingPod)
  3342  }
  3343  
  3344  // DeleteKubernetesWaitingContainer deletes a Kubernetes ephemeral
  3345  // container that are waiting to be created until moderated
  3346  // session conditions are met.
  3347  func (c *Client) DeleteKubernetesWaitingContainer(ctx context.Context, req *kubewaitingcontainerpb.DeleteKubernetesWaitingContainerRequest) error {
  3348  	return c.GetKubernetesWaitingContainerClient().DeleteKubernetesWaitingContainer(ctx, req)
  3349  }
  3350  
  3351  // CreateDatabase creates a new database resource.
  3352  func (c *Client) CreateDatabase(ctx context.Context, database types.Database) error {
  3353  	databaseV3, ok := database.(*types.DatabaseV3)
  3354  	if !ok {
  3355  		return trace.BadParameter("unsupported database type %T", database)
  3356  	}
  3357  	_, err := c.grpc.CreateDatabase(ctx, databaseV3)
  3358  	return trace.Wrap(err)
  3359  }
  3360  
  3361  // UpdateDatabase updates existing database resource.
  3362  func (c *Client) UpdateDatabase(ctx context.Context, database types.Database) error {
  3363  	databaseV3, ok := database.(*types.DatabaseV3)
  3364  	if !ok {
  3365  		return trace.BadParameter("unsupported database type %T", database)
  3366  	}
  3367  	_, err := c.grpc.UpdateDatabase(ctx, databaseV3)
  3368  	return trace.Wrap(err)
  3369  }
  3370  
  3371  // GetDatabase returns the specified database resource.
  3372  //
  3373  // Note that database resources here refers to "dynamically-added" databases
  3374  // such as databases created by `tctl create`, the discovery service, or the
  3375  // CreateDatabase API. Databases discovered by the database agent (legacy
  3376  // discovery flow using `database_service.aws/database_service.azure`) and
  3377  // static databases defined in the `database_service.databases` section of the
  3378  // service YAML configuration are not collected in this API.
  3379  //
  3380  // For a full list of registered databases that are served by a database
  3381  // service, use GetDatabaseServers instead.
  3382  func (c *Client) GetDatabase(ctx context.Context, name string) (types.Database, error) {
  3383  	if name == "" {
  3384  		return nil, trace.BadParameter("missing database name")
  3385  	}
  3386  	database, err := c.grpc.GetDatabase(ctx, &types.ResourceRequest{Name: name})
  3387  	if err != nil {
  3388  		return nil, trace.Wrap(err)
  3389  	}
  3390  	return database, nil
  3391  }
  3392  
  3393  // GetDatabases returns all database resources.
  3394  //
  3395  // Note that database resources here refers to "dynamically-added" databases
  3396  // such as databases created by `tctl create`, the discovery service, or the
  3397  // CreateDatabase API. Databases discovered by the database agent (legacy
  3398  // discovery flow using `database_service.aws/database_service.azure`) and
  3399  // static databases defined in the `database_service.databases` section of the
  3400  // service YAML configuration are not collected in this API.
  3401  //
  3402  // For a full list of registered databases that are served by a database
  3403  // service, use GetDatabaseServers instead.
  3404  func (c *Client) GetDatabases(ctx context.Context) ([]types.Database, error) {
  3405  	items, err := c.grpc.GetDatabases(ctx, &emptypb.Empty{})
  3406  	if err != nil {
  3407  		return nil, trace.Wrap(err)
  3408  	}
  3409  	databases := make([]types.Database, len(items.Databases))
  3410  	for i := range items.Databases {
  3411  		databases[i] = items.Databases[i]
  3412  	}
  3413  	return databases, nil
  3414  }
  3415  
  3416  // DeleteDatabase deletes specified database resource.
  3417  func (c *Client) DeleteDatabase(ctx context.Context, name string) error {
  3418  	_, err := c.grpc.DeleteDatabase(ctx, &types.ResourceRequest{Name: name})
  3419  	return trace.Wrap(err)
  3420  }
  3421  
  3422  // DeleteAllDatabases deletes all database resources.
  3423  func (c *Client) DeleteAllDatabases(ctx context.Context) error {
  3424  	_, err := c.grpc.DeleteAllDatabases(ctx, &emptypb.Empty{})
  3425  	return trace.Wrap(err)
  3426  }
  3427  
  3428  // UpsertDatabaseService creates or updates existing DatabaseService resource.
  3429  func (c *Client) UpsertDatabaseService(ctx context.Context, service types.DatabaseService) (*types.KeepAlive, error) {
  3430  	serviceV1, ok := service.(*types.DatabaseServiceV1)
  3431  	if !ok {
  3432  		return nil, trace.BadParameter("unsupported DatabaseService type %T", serviceV1)
  3433  	}
  3434  	keepAlive, err := c.grpc.UpsertDatabaseService(ctx, &proto.UpsertDatabaseServiceRequest{
  3435  		Service: serviceV1,
  3436  	})
  3437  
  3438  	return keepAlive, trace.Wrap(err)
  3439  }
  3440  
  3441  // DeleteDatabaseService deletes a specific DatabaseService resource.
  3442  func (c *Client) DeleteDatabaseService(ctx context.Context, name string) error {
  3443  	_, err := c.grpc.DeleteDatabaseService(ctx, &types.ResourceRequest{Name: name})
  3444  	return trace.Wrap(err)
  3445  }
  3446  
  3447  // DeleteAllDatabaseServices deletes all DatabaseService resources.
  3448  // If an error occurs, a partial delete may happen.
  3449  func (c *Client) DeleteAllDatabaseServices(ctx context.Context) error {
  3450  	_, err := c.grpc.DeleteAllDatabaseServices(ctx, &proto.DeleteAllDatabaseServicesRequest{})
  3451  	return trace.Wrap(err)
  3452  }
  3453  
  3454  // GetDatabaseObjectImportRules retrieves all database object import rules.
  3455  func (c *Client) GetDatabaseObjectImportRules(ctx context.Context) ([]*dbobjectimportrulev1.DatabaseObjectImportRule, error) {
  3456  	var out []*dbobjectimportrulev1.DatabaseObjectImportRule
  3457  	req := &dbobjectimportrulev1.ListDatabaseObjectImportRulesRequest{}
  3458  	client := c.DatabaseObjectImportRuleClient()
  3459  	for {
  3460  		resp, err := client.ListDatabaseObjectImportRules(ctx, req)
  3461  		if err != nil {
  3462  			return nil, trace.Wrap(err)
  3463  		}
  3464  		out = append(out, resp.Rules...)
  3465  
  3466  		if resp.NextPageToken == "" {
  3467  			break
  3468  		}
  3469  		req.PageToken = resp.NextPageToken
  3470  	}
  3471  
  3472  	return out, nil
  3473  }
  3474  
  3475  // GetDatabaseObjects retrieves all database objects.
  3476  func (c *Client) GetDatabaseObjects(ctx context.Context) ([]*dbobjectv1.DatabaseObject, error) {
  3477  	var out []*dbobjectv1.DatabaseObject
  3478  	req := &dbobjectv1.ListDatabaseObjectsRequest{}
  3479  	client := c.DatabaseObjectClient()
  3480  	for {
  3481  		resp, err := client.ListDatabaseObjects(ctx, req)
  3482  		if err != nil {
  3483  			return nil, trace.Wrap(err)
  3484  		}
  3485  		out = append(out, resp.Objects...)
  3486  
  3487  		if resp.NextPageToken == "" {
  3488  			break
  3489  		}
  3490  		req.PageToken = resp.NextPageToken
  3491  	}
  3492  
  3493  	return out, nil
  3494  }
  3495  
  3496  // GetWindowsDesktopServices returns all registered windows desktop services.
  3497  func (c *Client) GetWindowsDesktopServices(ctx context.Context) ([]types.WindowsDesktopService, error) {
  3498  	resp, err := c.grpc.GetWindowsDesktopServices(ctx, &emptypb.Empty{})
  3499  	if err != nil {
  3500  		return nil, trace.Wrap(err)
  3501  	}
  3502  	services := make([]types.WindowsDesktopService, 0, len(resp.GetServices()))
  3503  	for _, service := range resp.GetServices() {
  3504  		services = append(services, service)
  3505  	}
  3506  	return services, nil
  3507  }
  3508  
  3509  // GetWindowsDesktopService returns a registered windows desktop service by name.
  3510  func (c *Client) GetWindowsDesktopService(ctx context.Context, name string) (types.WindowsDesktopService, error) {
  3511  	resp, err := c.grpc.GetWindowsDesktopService(ctx, &proto.GetWindowsDesktopServiceRequest{Name: name})
  3512  	if err != nil {
  3513  		return nil, trace.Wrap(err)
  3514  	}
  3515  	return resp.GetService(), nil
  3516  }
  3517  
  3518  // UpsertWindowsDesktopService registers a new windows desktop service.
  3519  func (c *Client) UpsertWindowsDesktopService(ctx context.Context, service types.WindowsDesktopService) (*types.KeepAlive, error) {
  3520  	s, ok := service.(*types.WindowsDesktopServiceV3)
  3521  	if !ok {
  3522  		return nil, trace.BadParameter("invalid type %T", service)
  3523  	}
  3524  	keepAlive, err := c.grpc.UpsertWindowsDesktopService(ctx, s)
  3525  	if err != nil {
  3526  		return nil, trace.Wrap(err)
  3527  	}
  3528  	return keepAlive, nil
  3529  }
  3530  
  3531  // DeleteWindowsDesktopService removes the specified windows desktop service.
  3532  func (c *Client) DeleteWindowsDesktopService(ctx context.Context, name string) error {
  3533  	_, err := c.grpc.DeleteWindowsDesktopService(ctx, &proto.DeleteWindowsDesktopServiceRequest{
  3534  		Name: name,
  3535  	})
  3536  	if err != nil {
  3537  		return trace.Wrap(err)
  3538  	}
  3539  	return nil
  3540  }
  3541  
  3542  // DeleteAllWindowsDesktopServices removes all registered windows desktop services.
  3543  func (c *Client) DeleteAllWindowsDesktopServices(ctx context.Context) error {
  3544  	_, err := c.grpc.DeleteAllWindowsDesktopServices(ctx, &emptypb.Empty{})
  3545  	if err != nil {
  3546  		return trace.Wrap(err)
  3547  	}
  3548  	return nil
  3549  }
  3550  
  3551  // GetWindowsDesktops returns all registered windows desktop hosts.
  3552  func (c *Client) GetWindowsDesktops(ctx context.Context, filter types.WindowsDesktopFilter) ([]types.WindowsDesktop, error) {
  3553  	resp, err := c.grpc.GetWindowsDesktops(ctx, &filter)
  3554  	if err != nil {
  3555  		return nil, trace.Wrap(err)
  3556  	}
  3557  	desktops := make([]types.WindowsDesktop, 0, len(resp.GetDesktops()))
  3558  	for _, desktop := range resp.GetDesktops() {
  3559  		desktops = append(desktops, desktop)
  3560  	}
  3561  	return desktops, nil
  3562  }
  3563  
  3564  // CreateWindowsDesktop registers a new windows desktop host.
  3565  func (c *Client) CreateWindowsDesktop(ctx context.Context, desktop types.WindowsDesktop) error {
  3566  	d, ok := desktop.(*types.WindowsDesktopV3)
  3567  	if !ok {
  3568  		return trace.BadParameter("invalid type %T", desktop)
  3569  	}
  3570  	_, err := c.grpc.CreateWindowsDesktop(ctx, d)
  3571  	return trace.Wrap(err)
  3572  }
  3573  
  3574  // UpdateWindowsDesktop updates an existing windows desktop host.
  3575  func (c *Client) UpdateWindowsDesktop(ctx context.Context, desktop types.WindowsDesktop) error {
  3576  	d, ok := desktop.(*types.WindowsDesktopV3)
  3577  	if !ok {
  3578  		return trace.BadParameter("invalid type %T", desktop)
  3579  	}
  3580  	_, err := c.grpc.UpdateWindowsDesktop(ctx, d)
  3581  	return trace.Wrap(err)
  3582  }
  3583  
  3584  // UpsertWindowsDesktop updates a windows desktop resource, creating it if it doesn't exist.
  3585  func (c *Client) UpsertWindowsDesktop(ctx context.Context, desktop types.WindowsDesktop) error {
  3586  	d, ok := desktop.(*types.WindowsDesktopV3)
  3587  	if !ok {
  3588  		return trace.BadParameter("invalid type %T", desktop)
  3589  	}
  3590  	_, err := c.grpc.UpsertWindowsDesktop(ctx, d)
  3591  	return trace.Wrap(err)
  3592  }
  3593  
  3594  // DeleteWindowsDesktop removes the specified windows desktop host.
  3595  // Note: unlike GetWindowsDesktops, this will delete at-most one desktop.
  3596  // Passing an empty host ID will not trigger "delete all" behavior. To delete
  3597  // all desktops, use DeleteAllWindowsDesktops.
  3598  func (c *Client) DeleteWindowsDesktop(ctx context.Context, hostID, name string) error {
  3599  	_, err := c.grpc.DeleteWindowsDesktop(ctx, &proto.DeleteWindowsDesktopRequest{
  3600  		Name:   name,
  3601  		HostID: hostID,
  3602  	})
  3603  	if err != nil {
  3604  		return trace.Wrap(err)
  3605  	}
  3606  	return nil
  3607  }
  3608  
  3609  // DeleteAllWindowsDesktops removes all registered windows desktop hosts.
  3610  func (c *Client) DeleteAllWindowsDesktops(ctx context.Context) error {
  3611  	_, err := c.grpc.DeleteAllWindowsDesktops(ctx, &emptypb.Empty{})
  3612  	if err != nil {
  3613  		return trace.Wrap(err)
  3614  	}
  3615  	return nil
  3616  }
  3617  
  3618  // GenerateWindowsDesktopCert generates client certificate for Windows RDP authentication.
  3619  func (c *Client) GenerateWindowsDesktopCert(ctx context.Context, req *proto.WindowsDesktopCertRequest) (*proto.WindowsDesktopCertResponse, error) {
  3620  	resp, err := c.grpc.GenerateWindowsDesktopCert(ctx, req)
  3621  	if err != nil {
  3622  		return nil, trace.Wrap(err)
  3623  	}
  3624  	return resp, nil
  3625  }
  3626  
  3627  // ChangeUserAuthentication allows a user with a reset or invite token to change their password and if enabled also adds a new mfa device.
  3628  // Upon success, creates new web session and creates new set of recovery codes (if user meets requirements).
  3629  func (c *Client) ChangeUserAuthentication(ctx context.Context, req *proto.ChangeUserAuthenticationRequest) (*proto.ChangeUserAuthenticationResponse, error) {
  3630  	res, err := c.grpc.ChangeUserAuthentication(ctx, req)
  3631  	return res, trace.Wrap(err)
  3632  }
  3633  
  3634  // StartAccountRecovery creates a recovery start token for a user who successfully verified their username and their recovery code.
  3635  // This token is used as part of a URL that will be emailed to the user (not done in this request).
  3636  // Represents step 1 of the account recovery process.
  3637  func (c *Client) StartAccountRecovery(ctx context.Context, req *proto.StartAccountRecoveryRequest) (types.UserToken, error) {
  3638  	res, err := c.grpc.StartAccountRecovery(ctx, req)
  3639  	return res, trace.Wrap(err)
  3640  }
  3641  
  3642  // VerifyAccountRecovery creates a recovery approved token after successful verification of users password or second factor
  3643  // (authn depending on what user needed to recover). This token will allow users to perform protected actions while not logged in.
  3644  // Represents step 2 of the account recovery process after RPC StartAccountRecovery.
  3645  func (c *Client) VerifyAccountRecovery(ctx context.Context, req *proto.VerifyAccountRecoveryRequest) (types.UserToken, error) {
  3646  	res, err := c.grpc.VerifyAccountRecovery(ctx, req)
  3647  	return res, trace.Wrap(err)
  3648  }
  3649  
  3650  // CompleteAccountRecovery sets a new password or adds a new mfa device,
  3651  // allowing user to regain access to their account using the new credentials.
  3652  // Represents the last step in the account recovery process after RPC's StartAccountRecovery and VerifyAccountRecovery.
  3653  func (c *Client) CompleteAccountRecovery(ctx context.Context, req *proto.CompleteAccountRecoveryRequest) error {
  3654  	_, err := c.grpc.CompleteAccountRecovery(ctx, req)
  3655  	return trace.Wrap(err)
  3656  }
  3657  
  3658  // CreateAccountRecoveryCodes creates new set of recovery codes for a user, replacing and invalidating any previously owned codes.
  3659  func (c *Client) CreateAccountRecoveryCodes(ctx context.Context, req *proto.CreateAccountRecoveryCodesRequest) (*proto.RecoveryCodes, error) {
  3660  	res, err := c.grpc.CreateAccountRecoveryCodes(ctx, req)
  3661  	return res, trace.Wrap(err)
  3662  }
  3663  
  3664  // GetAccountRecoveryToken returns a user token resource after verifying the token in
  3665  // request is not expired and is of the correct recovery type.
  3666  func (c *Client) GetAccountRecoveryToken(ctx context.Context, req *proto.GetAccountRecoveryTokenRequest) (types.UserToken, error) {
  3667  	res, err := c.grpc.GetAccountRecoveryToken(ctx, req)
  3668  	return res, trace.Wrap(err)
  3669  }
  3670  
  3671  // GetAccountRecoveryCodes returns the user in context their recovery codes resource without any secrets.
  3672  func (c *Client) GetAccountRecoveryCodes(ctx context.Context, req *proto.GetAccountRecoveryCodesRequest) (*proto.RecoveryCodes, error) {
  3673  	res, err := c.grpc.GetAccountRecoveryCodes(ctx, req)
  3674  	return res, trace.Wrap(err)
  3675  }
  3676  
  3677  // CreateAuthenticateChallenge creates and returns MFA challenges for a users registered MFA devices.
  3678  func (c *Client) CreateAuthenticateChallenge(ctx context.Context, in *proto.CreateAuthenticateChallengeRequest) (*proto.MFAAuthenticateChallenge, error) {
  3679  	resp, err := c.grpc.CreateAuthenticateChallenge(ctx, in)
  3680  	return resp, trace.Wrap(err)
  3681  }
  3682  
  3683  // CreatePrivilegeToken is implemented by AuthService.CreatePrivilegeToken.
  3684  func (c *Client) CreatePrivilegeToken(ctx context.Context, req *proto.CreatePrivilegeTokenRequest) (*types.UserTokenV3, error) {
  3685  	resp, err := c.grpc.CreatePrivilegeToken(ctx, req)
  3686  	return resp, trace.Wrap(err)
  3687  }
  3688  
  3689  // CreateRegisterChallenge creates and returns MFA register challenge for a new MFA device.
  3690  func (c *Client) CreateRegisterChallenge(ctx context.Context, in *proto.CreateRegisterChallengeRequest) (*proto.MFARegisterChallenge, error) {
  3691  	resp, err := c.grpc.CreateRegisterChallenge(ctx, in)
  3692  	return resp, trace.Wrap(err)
  3693  }
  3694  
  3695  // GenerateCertAuthorityCRL generates an empty CRL for a CA.
  3696  func (c *Client) GenerateCertAuthorityCRL(ctx context.Context, req *proto.CertAuthorityRequest) (*proto.CRL, error) {
  3697  	resp, err := c.grpc.GenerateCertAuthorityCRL(ctx, req)
  3698  	return resp, trace.Wrap(err)
  3699  }
  3700  
  3701  // ListResources returns a paginated list of nodes that the user has access to.
  3702  // `nextKey` is used as `startKey` in another call to ListResources to retrieve
  3703  // the next page. If you want to list all resources pages, check the
  3704  // `GetResourcesWithFilters` function.
  3705  // It will return a `trace.LimitExceeded` error if the page exceeds gRPC max
  3706  // message size.
  3707  func (c *Client) ListResources(ctx context.Context, req proto.ListResourcesRequest) (*types.ListResourcesResponse, error) {
  3708  	if err := req.CheckAndSetDefaults(); err != nil {
  3709  		return nil, trace.Wrap(err)
  3710  	}
  3711  
  3712  	resp, err := c.grpc.ListResources(ctx, &req)
  3713  	if err != nil {
  3714  		return nil, trace.Wrap(err)
  3715  	}
  3716  
  3717  	resources := make([]types.ResourceWithLabels, len(resp.GetResources()))
  3718  	for i, respResource := range resp.GetResources() {
  3719  		switch req.ResourceType {
  3720  		case types.KindDatabaseServer:
  3721  			resources[i] = respResource.GetDatabaseServer()
  3722  		case types.KindDatabaseService:
  3723  			resources[i] = respResource.GetDatabaseService()
  3724  		case types.KindAppServer:
  3725  			resources[i] = respResource.GetAppServer()
  3726  		case types.KindNode:
  3727  			resources[i] = respResource.GetNode()
  3728  		case types.KindWindowsDesktop:
  3729  			resources[i] = respResource.GetWindowsDesktop()
  3730  		case types.KindWindowsDesktopService:
  3731  			resources[i] = respResource.GetWindowsDesktopService()
  3732  		case types.KindKubernetesCluster:
  3733  			resources[i] = respResource.GetKubeCluster()
  3734  		case types.KindKubeServer:
  3735  			resources[i] = respResource.GetKubernetesServer()
  3736  		case types.KindUserGroup:
  3737  			resources[i] = respResource.GetUserGroup()
  3738  		case types.KindAppOrSAMLIdPServiceProvider:
  3739  			//nolint:staticcheck // SA1019. TODO(sshah) DELETE IN 17.0
  3740  			resources[i] = respResource.GetAppServerOrSAMLIdPServiceProvider()
  3741  		case types.KindSAMLIdPServiceProvider:
  3742  			resources[i] = respResource.GetSAMLIdPServiceProvider()
  3743  		default:
  3744  			return nil, trace.NotImplemented("resource type %s does not support pagination", req.ResourceType)
  3745  		}
  3746  	}
  3747  
  3748  	return &types.ListResourcesResponse{
  3749  		Resources:  resources,
  3750  		NextKey:    resp.NextKey,
  3751  		TotalCount: int(resp.TotalCount),
  3752  	}, nil
  3753  }
  3754  
  3755  // GetResources returns a paginated list of resources that the user has access to.
  3756  // `nextKey` is used as `startKey` in another call to GetResources to retrieve
  3757  // the next page.
  3758  // It will return a `trace.LimitExceeded` error if the page exceeds gRPC max
  3759  // message size.
  3760  func (c *Client) GetResources(ctx context.Context, req *proto.ListResourcesRequest) (*proto.ListResourcesResponse, error) {
  3761  	if err := req.CheckAndSetDefaults(); err != nil {
  3762  		return nil, trace.Wrap(err)
  3763  	}
  3764  
  3765  	resp, err := c.grpc.ListResources(ctx, req)
  3766  	return resp, trace.Wrap(err)
  3767  }
  3768  
  3769  // ListUnifiedResources returns a paginated list of unified resources that the user has access to.
  3770  // `nextKey` is used as `startKey` in another call to ListUnifiedResources to retrieve
  3771  // the next page.
  3772  // It will return a `trace.LimitExceeded` error if the page exceeds gRPC max
  3773  // message size.
  3774  func (c *Client) ListUnifiedResources(ctx context.Context, req *proto.ListUnifiedResourcesRequest) (*proto.ListUnifiedResourcesResponse, error) {
  3775  	if err := req.CheckAndSetDefaults(); err != nil {
  3776  		return nil, trace.Wrap(err)
  3777  	}
  3778  
  3779  	resp, err := c.grpc.ListUnifiedResources(ctx, req)
  3780  	return resp, trace.Wrap(err)
  3781  }
  3782  
  3783  // GetResourcesClient is an interface used by GetResources to abstract over implementations of
  3784  // the ListResources method.
  3785  type GetResourcesClient interface {
  3786  	GetResources(ctx context.Context, req *proto.ListResourcesRequest) (*proto.ListResourcesResponse, error)
  3787  }
  3788  
  3789  // ListUnifiedResourcesClient is an interface used by ListUnifiedResources to abstract over implementations of
  3790  // the ListUnifiedResources method.
  3791  type ListUnifiedResourcesClient interface {
  3792  	ListUnifiedResources(ctx context.Context, req *proto.ListUnifiedResourcesRequest) (*proto.ListUnifiedResourcesResponse, error)
  3793  }
  3794  
  3795  // ResourcePage holds a page of results from [GetResourcePage].
  3796  type ResourcePage[T types.ResourceWithLabels] struct {
  3797  	// Resources retrieved for a single [proto.ListResourcesRequest]. The length of
  3798  	// the slice will be at most [proto.ListResourcesRequest.Limit].
  3799  	Resources []T
  3800  	// Total number of all resources matching the request. It will be greater than
  3801  	// the length of [Resources] if the number of matches exceeds the request limit.
  3802  	Total int
  3803  	// NextKey is the start of the next page
  3804  	NextKey string
  3805  }
  3806  
  3807  // convertEnrichedResource extracts the resource and any enriched information from the
  3808  // PaginatedResource returned from the rpc ListUnifiedResources.
  3809  func convertEnrichedResource(resource *proto.PaginatedResource) (*types.EnrichedResource, error) {
  3810  	if r := resource.GetNode(); r != nil {
  3811  		return &types.EnrichedResource{ResourceWithLabels: r, Logins: resource.Logins, RequiresRequest: resource.RequiresRequest}, nil
  3812  	} else if r := resource.GetDatabaseServer(); r != nil {
  3813  		return &types.EnrichedResource{ResourceWithLabels: r, RequiresRequest: resource.RequiresRequest}, nil
  3814  	} else if r := resource.GetDatabaseService(); r != nil {
  3815  		return &types.EnrichedResource{ResourceWithLabels: r, RequiresRequest: resource.RequiresRequest}, nil
  3816  	} else if r := resource.GetAppServerOrSAMLIdPServiceProvider(); r != nil { //nolint:staticcheck // SA1019. TODO(sshah) DELETE IN 17.0
  3817  		return &types.EnrichedResource{ResourceWithLabels: r, RequiresRequest: resource.RequiresRequest}, nil
  3818  	} else if r := resource.GetWindowsDesktop(); r != nil {
  3819  		return &types.EnrichedResource{ResourceWithLabels: r, Logins: resource.Logins, RequiresRequest: resource.RequiresRequest}, nil
  3820  	} else if r := resource.GetWindowsDesktopService(); r != nil {
  3821  		return &types.EnrichedResource{ResourceWithLabels: r, RequiresRequest: resource.RequiresRequest}, nil
  3822  	} else if r := resource.GetKubeCluster(); r != nil {
  3823  		return &types.EnrichedResource{ResourceWithLabels: r, RequiresRequest: resource.RequiresRequest}, nil
  3824  	} else if r := resource.GetKubernetesServer(); r != nil {
  3825  		return &types.EnrichedResource{ResourceWithLabels: r, RequiresRequest: resource.RequiresRequest}, nil
  3826  	} else if r := resource.GetUserGroup(); r != nil {
  3827  		return &types.EnrichedResource{ResourceWithLabels: r, RequiresRequest: resource.RequiresRequest}, nil
  3828  	} else if r := resource.GetAppServer(); r != nil {
  3829  		return &types.EnrichedResource{ResourceWithLabels: r, RequiresRequest: resource.RequiresRequest}, nil
  3830  	} else if r := resource.GetSAMLIdPServiceProvider(); r != nil {
  3831  		return &types.EnrichedResource{ResourceWithLabels: r, RequiresRequest: resource.RequiresRequest}, nil
  3832  	} else {
  3833  		return nil, trace.BadParameter("received unsupported resource %T", resource.Resource)
  3834  	}
  3835  }
  3836  
  3837  // GetUnifiedResourcePage is a helper for getting a single page of unified resources that match the provided request.
  3838  func GetUnifiedResourcePage(ctx context.Context, clt ListUnifiedResourcesClient, req *proto.ListUnifiedResourcesRequest) ([]*types.EnrichedResource, string, error) {
  3839  	var out []*types.EnrichedResource
  3840  
  3841  	// Set the limit to the default size if one was not provided within
  3842  	// an acceptable range.
  3843  	if req.Limit <= 0 || req.Limit > int32(defaults.DefaultChunkSize) {
  3844  		req.Limit = int32(defaults.DefaultChunkSize)
  3845  	}
  3846  
  3847  	for {
  3848  		resp, err := clt.ListUnifiedResources(ctx, req)
  3849  		if err != nil {
  3850  			if trace.IsLimitExceeded(err) {
  3851  				// Cut chunkSize in half if gRPC max message size is exceeded.
  3852  				req.Limit /= 2
  3853  				// This is an extremely unlikely scenario, but better to cover it anyways.
  3854  				if req.Limit == 0 {
  3855  					return nil, "", trace.Wrap(err, "resource is too large to retrieve")
  3856  				}
  3857  
  3858  				continue
  3859  			}
  3860  
  3861  			return nil, "", trace.Wrap(err)
  3862  		}
  3863  
  3864  		for _, respResource := range resp.Resources {
  3865  			resource, err := convertEnrichedResource(respResource)
  3866  			if err != nil {
  3867  				return nil, "", trace.Wrap(err)
  3868  			}
  3869  			out = append(out, resource)
  3870  		}
  3871  
  3872  		return out, resp.NextKey, nil
  3873  	}
  3874  }
  3875  
  3876  // GetEnrichedResourcePage is a helper for getting a single page of enriched resources.
  3877  func GetEnrichedResourcePage(ctx context.Context, clt GetResourcesClient, req *proto.ListResourcesRequest) (ResourcePage[*types.EnrichedResource], error) {
  3878  	var out ResourcePage[*types.EnrichedResource]
  3879  
  3880  	// Set the limit to the default size if one was not provided within
  3881  	// an acceptable range.
  3882  	if req.Limit <= 0 || req.Limit > int32(defaults.DefaultChunkSize) {
  3883  		req.Limit = int32(defaults.DefaultChunkSize)
  3884  	}
  3885  
  3886  	for {
  3887  		resp, err := clt.GetResources(ctx, req)
  3888  		if err != nil {
  3889  			if trace.IsLimitExceeded(err) {
  3890  				// Cut chunkSize in half if gRPC max message size is exceeded.
  3891  				req.Limit /= 2
  3892  				// This is an extremely unlikely scenario, but better to cover it anyways.
  3893  				if req.Limit == 0 {
  3894  					return out, trace.Wrap(err, "resource is too large to retrieve")
  3895  				}
  3896  
  3897  				continue
  3898  			}
  3899  
  3900  			return out, trace.Wrap(err)
  3901  		}
  3902  
  3903  		for _, respResource := range resp.Resources {
  3904  			var resource types.ResourceWithLabels
  3905  			switch req.ResourceType {
  3906  			case types.KindDatabaseServer:
  3907  				resource = respResource.GetDatabaseServer()
  3908  			case types.KindDatabaseService:
  3909  				resource = respResource.GetDatabaseService()
  3910  			case types.KindAppServer:
  3911  				resource = respResource.GetAppServer()
  3912  			case types.KindNode:
  3913  				resource = respResource.GetNode()
  3914  			case types.KindWindowsDesktop:
  3915  				resource = respResource.GetWindowsDesktop()
  3916  			case types.KindWindowsDesktopService:
  3917  				resource = respResource.GetWindowsDesktopService()
  3918  			case types.KindKubernetesCluster:
  3919  				resource = respResource.GetKubeCluster()
  3920  			case types.KindKubeServer:
  3921  				resource = respResource.GetKubernetesServer()
  3922  			case types.KindUserGroup:
  3923  				resource = respResource.GetUserGroup()
  3924  			case types.KindAppOrSAMLIdPServiceProvider:
  3925  				//nolint:staticcheck // SA1019. TODO(sshah) DELETE IN 17.0
  3926  				resource = respResource.GetAppServerOrSAMLIdPServiceProvider()
  3927  			case types.KindSAMLIdPServiceProvider:
  3928  				resource = respResource.GetSAMLIdPServiceProvider()
  3929  			default:
  3930  				out.Resources = nil
  3931  				return out, trace.NotImplemented("resource type %s does not support pagination", req.ResourceType)
  3932  			}
  3933  
  3934  			out.Resources = append(out.Resources, &types.EnrichedResource{ResourceWithLabels: resource, Logins: respResource.Logins})
  3935  		}
  3936  
  3937  		out.NextKey = resp.NextKey
  3938  		out.Total = int(resp.TotalCount)
  3939  
  3940  		return out, nil
  3941  	}
  3942  }
  3943  
  3944  // GetResourcePage is a helper for getting a single page of resources that match the provide request.
  3945  func GetResourcePage[T types.ResourceWithLabels](ctx context.Context, clt GetResourcesClient, req *proto.ListResourcesRequest) (ResourcePage[T], error) {
  3946  	var out ResourcePage[T]
  3947  
  3948  	// Set the limit to the default size if one was not provided within
  3949  	// an acceptable range.
  3950  	if req.Limit <= 0 || req.Limit > int32(defaults.DefaultChunkSize) {
  3951  		req.Limit = int32(defaults.DefaultChunkSize)
  3952  	}
  3953  
  3954  	for {
  3955  		resp, err := clt.GetResources(ctx, req)
  3956  		if err != nil {
  3957  			if trace.IsLimitExceeded(err) {
  3958  				// Cut chunkSize in half if gRPC max message size is exceeded.
  3959  				req.Limit /= 2
  3960  				// This is an extremely unlikely scenario, but better to cover it anyways.
  3961  				if req.Limit == 0 {
  3962  					return out, trace.Wrap(err, "resource is too large to retrieve")
  3963  				}
  3964  
  3965  				continue
  3966  			}
  3967  
  3968  			return out, trace.Wrap(err)
  3969  		}
  3970  
  3971  		for _, respResource := range resp.Resources {
  3972  			var resource types.ResourceWithLabels
  3973  			switch req.ResourceType {
  3974  			case types.KindDatabaseServer:
  3975  				resource = respResource.GetDatabaseServer()
  3976  			case types.KindDatabaseService:
  3977  				resource = respResource.GetDatabaseService()
  3978  			case types.KindAppServer:
  3979  				resource = respResource.GetAppServer()
  3980  			case types.KindNode:
  3981  				resource = respResource.GetNode()
  3982  			case types.KindWindowsDesktop:
  3983  				resource = respResource.GetWindowsDesktop()
  3984  			case types.KindWindowsDesktopService:
  3985  				resource = respResource.GetWindowsDesktopService()
  3986  			case types.KindKubernetesCluster:
  3987  				resource = respResource.GetKubeCluster()
  3988  			case types.KindKubeServer:
  3989  				resource = respResource.GetKubernetesServer()
  3990  			case types.KindUserGroup:
  3991  				resource = respResource.GetUserGroup()
  3992  			case types.KindAppOrSAMLIdPServiceProvider:
  3993  				//nolint:staticcheck // SA1019. TODO(sshah) DELETE IN 17.0
  3994  				resource = respResource.GetAppServerOrSAMLIdPServiceProvider()
  3995  			case types.KindSAMLIdPServiceProvider:
  3996  				resource = respResource.GetSAMLIdPServiceProvider()
  3997  			default:
  3998  				out.Resources = nil
  3999  				return out, trace.NotImplemented("resource type %s does not support pagination", req.ResourceType)
  4000  			}
  4001  
  4002  			t, ok := resource.(T)
  4003  			if !ok {
  4004  				out.Resources = nil
  4005  				return out, trace.BadParameter("received unexpected resource type %T", resource)
  4006  			}
  4007  			out.Resources = append(out.Resources, t)
  4008  		}
  4009  
  4010  		out.NextKey = resp.NextKey
  4011  		out.Total = int(resp.TotalCount)
  4012  
  4013  		return out, nil
  4014  	}
  4015  }
  4016  
  4017  // GetAllResources is a helper for getting all existing resources that match the provided request. In addition to
  4018  // iterating pages, it also correctly handles downsizing pages when LimitExceeded errors are encountered.
  4019  func GetAllResources[T types.ResourceWithLabels](ctx context.Context, clt GetResourcesClient, req *proto.ListResourcesRequest) ([]T, error) {
  4020  	var out []T
  4021  
  4022  	// Set the limit to the default size.
  4023  	req.Limit = int32(defaults.DefaultChunkSize)
  4024  	for {
  4025  		page, err := GetResourcePage[T](ctx, clt, req)
  4026  		if err != nil {
  4027  			return nil, trace.Wrap(err)
  4028  		}
  4029  
  4030  		out = append(out, page.Resources...)
  4031  
  4032  		if page.NextKey == "" || len(page.Resources) == 0 {
  4033  			break
  4034  		}
  4035  
  4036  		req.StartKey = page.NextKey
  4037  	}
  4038  
  4039  	return out, nil
  4040  }
  4041  
  4042  // ListResourcesClient is an interface used by GetResourcesWithFilters to abstract over implementations of
  4043  // the ListResources method.
  4044  type ListResourcesClient interface {
  4045  	ListResources(ctx context.Context, req proto.ListResourcesRequest) (*types.ListResourcesResponse, error)
  4046  }
  4047  
  4048  // GetResourcesWithFilters is a helper for getting a list of resources with optional filtering. In addition to
  4049  // iterating pages, it also correctly handles downsizing pages when LimitExceeded errors are encountered.
  4050  //
  4051  // GetAllResources or GetResourcePage should be preferred for client side operations to avoid converting
  4052  // from []types.ResourceWithLabels to concrete types.
  4053  func GetResourcesWithFilters(ctx context.Context, clt ListResourcesClient, req proto.ListResourcesRequest) ([]types.ResourceWithLabels, error) {
  4054  	// Retrieve the complete list of resources in chunks.
  4055  	var (
  4056  		resources []types.ResourceWithLabels
  4057  		startKey  string
  4058  		chunkSize = int32(defaults.DefaultChunkSize)
  4059  	)
  4060  
  4061  	for {
  4062  		resp, err := clt.ListResources(ctx, proto.ListResourcesRequest{
  4063  			Namespace:           req.Namespace,
  4064  			ResourceType:        req.ResourceType,
  4065  			StartKey:            startKey,
  4066  			Limit:               chunkSize,
  4067  			Labels:              req.Labels,
  4068  			SearchKeywords:      req.SearchKeywords,
  4069  			PredicateExpression: req.PredicateExpression,
  4070  			UseSearchAsRoles:    req.UseSearchAsRoles,
  4071  		})
  4072  		if err != nil {
  4073  			if trace.IsLimitExceeded(err) {
  4074  				// Cut chunkSize in half if gRPC max message size is exceeded.
  4075  				chunkSize = chunkSize / 2
  4076  				// This is an extremely unlikely scenario, but better to cover it anyways.
  4077  				if chunkSize == 0 {
  4078  					return nil, trace.Wrap(err, "resource is too large to retrieve")
  4079  				}
  4080  
  4081  				continue
  4082  			}
  4083  
  4084  			return nil, trace.Wrap(err)
  4085  		}
  4086  
  4087  		startKey = resp.NextKey
  4088  		resources = append(resources, resp.Resources...)
  4089  		if startKey == "" || len(resp.Resources) == 0 {
  4090  			break
  4091  		}
  4092  
  4093  	}
  4094  
  4095  	return resources, nil
  4096  }
  4097  
  4098  // GetKubernetesResourcesWithFilters is a helper for getting a list of kubernetes resources with optional filtering. In addition to
  4099  // iterating pages, it also correctly handles downsizing pages when LimitExceeded errors are encountered.
  4100  func GetKubernetesResourcesWithFilters(ctx context.Context, clt kubeproto.KubeServiceClient, req *kubeproto.ListKubernetesResourcesRequest) ([]types.ResourceWithLabels, error) {
  4101  	var (
  4102  		resources []types.ResourceWithLabels
  4103  		startKey  = req.StartKey
  4104  		// Retrieve the complete list of resources in chunks.
  4105  		chunkSize = req.Limit
  4106  	)
  4107  
  4108  	// Set the chunk size to the default if it is not set.
  4109  	if chunkSize == 0 {
  4110  		chunkSize = int32(defaults.DefaultChunkSize)
  4111  	}
  4112  
  4113  	for {
  4114  		// Reset startKey to the previous page's nextKey.
  4115  		req.StartKey = startKey
  4116  		// Set the chunk size based on the previous chunk size error.
  4117  		req.Limit = chunkSize
  4118  
  4119  		resp, err := clt.ListKubernetesResources(
  4120  			ctx,
  4121  			req,
  4122  		)
  4123  		if err != nil {
  4124  			if trace.IsLimitExceeded(err) {
  4125  				// Cut chunkSize in half if gRPC max message size is exceeded.
  4126  				chunkSize = chunkSize / 2
  4127  				// This is an extremely unlikely scenario, but better to cover it anyways.
  4128  				if chunkSize == 0 {
  4129  					return nil, trace.Wrap(err, "resource is too large to retrieve")
  4130  				}
  4131  				continue
  4132  			}
  4133  			return nil, trace.Wrap(err)
  4134  		}
  4135  
  4136  		startKey = resp.NextKey
  4137  
  4138  		resources = append(resources, types.KubeResources(resp.Resources).AsResources()...)
  4139  		if startKey == "" || len(resp.Resources) == 0 {
  4140  			break
  4141  		}
  4142  	}
  4143  	return resources, nil
  4144  }
  4145  
  4146  // GetSSHTargets gets all servers that would match an equivalent ssh dial request. Note that this method
  4147  // returns all resources directly accessible to the user *and* all resources available via 'SearchAsRoles',
  4148  // which is what we want when handling things like ambiguous host errors and resource-based access requests,
  4149  // but may result in confusing behavior if it is used outside of those contexts.
  4150  func (c *Client) GetSSHTargets(ctx context.Context, req *proto.GetSSHTargetsRequest) (*proto.GetSSHTargetsResponse, error) {
  4151  	rsp, err := c.grpc.GetSSHTargets(ctx, req)
  4152  	if err := trace.Wrap(err); !trace.IsNotImplemented(err) {
  4153  		return rsp, err
  4154  	}
  4155  
  4156  	// if we got a not implemented error, fallback to client-side filtering
  4157  	servers, err := GetAllResources[*types.ServerV2](ctx, c, &proto.ListResourcesRequest{
  4158  		ResourceType:     types.KindNode,
  4159  		UseSearchAsRoles: true,
  4160  	})
  4161  	if err != nil {
  4162  		return nil, trace.Wrap(err)
  4163  	}
  4164  
  4165  	// we only get here if we hit a NotImplementedError from GetSSHTargets, which means
  4166  	// we should be performing client-side filtering with default parameters instead.
  4167  	routeMatcher := utils.NewSSHRouteMatcher(req.Host, req.Port, false)
  4168  
  4169  	// do client-side filtering
  4170  	filtered := servers[:0]
  4171  	for _, srv := range servers {
  4172  		if !routeMatcher.RouteToServer(srv) {
  4173  			continue
  4174  		}
  4175  
  4176  		filtered = append(filtered, srv)
  4177  	}
  4178  
  4179  	return &proto.GetSSHTargetsResponse{
  4180  		Servers: filtered,
  4181  	}, nil
  4182  }
  4183  
  4184  // CreateSessionTracker creates a tracker resource for an active session.
  4185  func (c *Client) CreateSessionTracker(ctx context.Context, st types.SessionTracker) (types.SessionTracker, error) {
  4186  	v1, ok := st.(*types.SessionTrackerV1)
  4187  	if !ok {
  4188  		return nil, trace.BadParameter("invalid type %T, expected *types.SessionTrackerV1", st)
  4189  	}
  4190  
  4191  	req := &proto.CreateSessionTrackerRequest{SessionTracker: v1}
  4192  	tracker, err := c.grpc.CreateSessionTracker(ctx, req)
  4193  	if err != nil {
  4194  		return nil, trace.Wrap(err)
  4195  	}
  4196  	return tracker, nil
  4197  }
  4198  
  4199  // GetSessionTracker returns the current state of a session tracker for an active session.
  4200  func (c *Client) GetSessionTracker(ctx context.Context, sessionID string) (types.SessionTracker, error) {
  4201  	req := &proto.GetSessionTrackerRequest{SessionID: sessionID}
  4202  	resp, err := c.grpc.GetSessionTracker(ctx, req)
  4203  	if err != nil {
  4204  		return nil, trace.Wrap(err)
  4205  	}
  4206  	return resp, nil
  4207  }
  4208  
  4209  // GetActiveSessionTrackers returns a list of active session trackers.
  4210  func (c *Client) GetActiveSessionTrackers(ctx context.Context) ([]types.SessionTracker, error) {
  4211  	stream, err := c.grpc.GetActiveSessionTrackers(ctx, &emptypb.Empty{})
  4212  	if err != nil {
  4213  		return nil, trace.Wrap(err)
  4214  	}
  4215  
  4216  	var sessions []types.SessionTracker
  4217  	for {
  4218  		session, err := stream.Recv()
  4219  		if err != nil {
  4220  			if errors.Is(err, io.EOF) {
  4221  				break
  4222  			}
  4223  
  4224  			return nil, trace.Wrap(err)
  4225  		}
  4226  
  4227  		sessions = append(sessions, session)
  4228  	}
  4229  
  4230  	return sessions, nil
  4231  }
  4232  
  4233  // GetActiveSessionTrackersWithFilter returns a list of active sessions filtered by a filter.
  4234  func (c *Client) GetActiveSessionTrackersWithFilter(ctx context.Context, filter *types.SessionTrackerFilter) ([]types.SessionTracker, error) {
  4235  	stream, err := c.grpc.GetActiveSessionTrackersWithFilter(ctx, filter)
  4236  	if err != nil {
  4237  		return nil, trace.Wrap(err)
  4238  	}
  4239  
  4240  	var sessions []types.SessionTracker
  4241  	for {
  4242  		session, err := stream.Recv()
  4243  		if err != nil {
  4244  			if errors.Is(err, io.EOF) {
  4245  				break
  4246  			}
  4247  
  4248  			return nil, trace.Wrap(err)
  4249  		}
  4250  
  4251  		sessions = append(sessions, session)
  4252  	}
  4253  
  4254  	return sessions, nil
  4255  }
  4256  
  4257  // RemoveSessionTracker removes a tracker resource for an active session.
  4258  func (c *Client) RemoveSessionTracker(ctx context.Context, sessionID string) error {
  4259  	_, err := c.grpc.RemoveSessionTracker(ctx, &proto.RemoveSessionTrackerRequest{SessionID: sessionID})
  4260  	return trace.Wrap(err)
  4261  }
  4262  
  4263  // UpdateSessionTracker updates a tracker resource for an active session.
  4264  func (c *Client) UpdateSessionTracker(ctx context.Context, req *proto.UpdateSessionTrackerRequest) error {
  4265  	_, err := c.grpc.UpdateSessionTracker(ctx, req)
  4266  	return trace.Wrap(err)
  4267  }
  4268  
  4269  // MaintainSessionPresence establishes a channel used to continuously verify the presence for a session.
  4270  func (c *Client) MaintainSessionPresence(ctx context.Context) (proto.AuthService_MaintainSessionPresenceClient, error) {
  4271  	stream, err := c.grpc.MaintainSessionPresence(ctx)
  4272  	return stream, trace.Wrap(err)
  4273  }
  4274  
  4275  // GetDomainName returns local auth domain of the current auth server
  4276  func (c *Client) GetDomainName(ctx context.Context) (string, error) {
  4277  	resp, err := c.grpc.GetDomainName(ctx, &emptypb.Empty{})
  4278  	if err != nil {
  4279  		return "", trace.Wrap(err)
  4280  	}
  4281  	return resp.DomainName, nil
  4282  }
  4283  
  4284  // GetClusterCACert returns the PEM-encoded TLS certs for the local cluster. If
  4285  // the cluster has multiple TLS certs, they will all be concatenated.
  4286  func (c *Client) GetClusterCACert(ctx context.Context) (*proto.GetClusterCACertResponse, error) {
  4287  	resp, err := c.grpc.GetClusterCACert(ctx, &emptypb.Empty{})
  4288  	if err != nil {
  4289  		return nil, trace.Wrap(err)
  4290  	}
  4291  	return resp, nil
  4292  }
  4293  
  4294  // GetConnectionDiagnostic reads a connection diagnostic
  4295  func (c *Client) GetConnectionDiagnostic(ctx context.Context, name string) (types.ConnectionDiagnostic, error) {
  4296  	req := &proto.GetConnectionDiagnosticRequest{
  4297  		Name: name,
  4298  	}
  4299  	res, err := c.grpc.GetConnectionDiagnostic(ctx, req)
  4300  	return res, trace.Wrap(err)
  4301  }
  4302  
  4303  // CreateConnectionDiagnostic creates a new connection diagnostic.
  4304  func (c *Client) CreateConnectionDiagnostic(ctx context.Context, connectionDiagnostic types.ConnectionDiagnostic) error {
  4305  	connectionDiagnosticV1, ok := connectionDiagnostic.(*types.ConnectionDiagnosticV1)
  4306  	if !ok {
  4307  		return trace.BadParameter("invalid type %T", connectionDiagnostic)
  4308  	}
  4309  	_, err := c.grpc.CreateConnectionDiagnostic(ctx, connectionDiagnosticV1)
  4310  	return trace.Wrap(err)
  4311  }
  4312  
  4313  // UpdateConnectionDiagnostic updates a connection diagnostic.
  4314  func (c *Client) UpdateConnectionDiagnostic(ctx context.Context, connectionDiagnostic types.ConnectionDiagnostic) error {
  4315  	connectionDiagnosticV1, ok := connectionDiagnostic.(*types.ConnectionDiagnosticV1)
  4316  	if !ok {
  4317  		return trace.BadParameter("invalid type %T", connectionDiagnostic)
  4318  	}
  4319  	_, err := c.grpc.UpdateConnectionDiagnostic(ctx, connectionDiagnosticV1)
  4320  	return trace.Wrap(err)
  4321  }
  4322  
  4323  // AppendDiagnosticTrace adds a new trace for the given ConnectionDiagnostic.
  4324  func (c *Client) AppendDiagnosticTrace(ctx context.Context, name string, t *types.ConnectionDiagnosticTrace) (types.ConnectionDiagnostic, error) {
  4325  	req := &proto.AppendDiagnosticTraceRequest{
  4326  		Name:  name,
  4327  		Trace: t,
  4328  	}
  4329  	connectionDiagnostic, err := c.grpc.AppendDiagnosticTrace(ctx, req)
  4330  	if err != nil {
  4331  		return nil, trace.Wrap(err)
  4332  	}
  4333  
  4334  	return connectionDiagnostic, nil
  4335  }
  4336  
  4337  // GetClusterAlerts loads matching cluster alerts.
  4338  func (c *Client) GetClusterAlerts(ctx context.Context, query types.GetClusterAlertsRequest) ([]types.ClusterAlert, error) {
  4339  	rsp, err := c.grpc.GetClusterAlerts(ctx, &query)
  4340  	if err != nil {
  4341  		return nil, trace.Wrap(err)
  4342  	}
  4343  	return rsp.Alerts, nil
  4344  }
  4345  
  4346  // UpsertClusterAlert creates a cluster alert.
  4347  func (c *Client) UpsertClusterAlert(ctx context.Context, alert types.ClusterAlert) error {
  4348  	_, err := c.grpc.UpsertClusterAlert(ctx, &proto.UpsertClusterAlertRequest{
  4349  		Alert: alert,
  4350  	})
  4351  	return trace.Wrap(err)
  4352  }
  4353  
  4354  func (c *Client) ChangePassword(ctx context.Context, req *proto.ChangePasswordRequest) error {
  4355  	_, err := c.grpc.ChangePassword(ctx, req)
  4356  	return trace.Wrap(err)
  4357  }
  4358  
  4359  // SubmitUsageEvent submits an external usage event.
  4360  func (c *Client) SubmitUsageEvent(ctx context.Context, req *proto.SubmitUsageEventRequest) error {
  4361  	_, err := c.grpc.SubmitUsageEvent(ctx, req)
  4362  
  4363  	return trace.Wrap(err)
  4364  }
  4365  
  4366  // GetLicense returns the license used to start the teleport enterprise auth server
  4367  func (c *Client) GetLicense(ctx context.Context) (string, error) {
  4368  	resp, err := c.grpc.GetLicense(ctx, &proto.GetLicenseRequest{})
  4369  	if err != nil {
  4370  		return "", trace.Wrap(err)
  4371  	}
  4372  	return string(resp.License), nil
  4373  }
  4374  
  4375  // ListReleases returns a list of teleport enterprise releases
  4376  func (c *Client) ListReleases(ctx context.Context, req *proto.ListReleasesRequest) ([]*types.Release, error) {
  4377  	resp, err := c.grpc.ListReleases(ctx, req)
  4378  	if err != nil {
  4379  		return nil, trace.Wrap(err)
  4380  	}
  4381  
  4382  	return resp.Releases, nil
  4383  }
  4384  
  4385  // CreateAlertAck marks a cluster alert as acknowledged.
  4386  func (c *Client) CreateAlertAck(ctx context.Context, ack types.AlertAcknowledgement) error {
  4387  	_, err := c.grpc.CreateAlertAck(ctx, &ack)
  4388  	return trace.Wrap(err)
  4389  }
  4390  
  4391  // GetAlertAcks gets active alert acknowledgements.
  4392  func (c *Client) GetAlertAcks(ctx context.Context) ([]types.AlertAcknowledgement, error) {
  4393  	rsp, err := c.grpc.GetAlertAcks(ctx, &proto.GetAlertAcksRequest{})
  4394  	if err != nil {
  4395  		return nil, trace.Wrap(err)
  4396  	}
  4397  	return rsp.Acks, nil
  4398  }
  4399  
  4400  // ClearAlertAcks clears alert acknowledgments.
  4401  func (c *Client) ClearAlertAcks(ctx context.Context, req proto.ClearAlertAcksRequest) error {
  4402  	_, err := c.grpc.ClearAlertAcks(ctx, &req)
  4403  	return trace.Wrap(err)
  4404  }
  4405  
  4406  // ListSAMLIdPServiceProviders returns a paginated list of SAML IdP service provider resources.
  4407  func (c *Client) ListSAMLIdPServiceProviders(ctx context.Context, pageSize int, nextKey string) ([]types.SAMLIdPServiceProvider, string, error) {
  4408  	resp, err := c.grpc.ListSAMLIdPServiceProviders(ctx, &proto.ListSAMLIdPServiceProvidersRequest{
  4409  		Limit:   int32(pageSize),
  4410  		NextKey: nextKey,
  4411  	})
  4412  	if err != nil {
  4413  		return nil, "", trace.Wrap(err)
  4414  	}
  4415  	serviceProviders := make([]types.SAMLIdPServiceProvider, 0, len(resp.GetServiceProviders()))
  4416  	for _, sp := range resp.GetServiceProviders() {
  4417  		serviceProviders = append(serviceProviders, sp)
  4418  	}
  4419  	return serviceProviders, resp.GetNextKey(), nil
  4420  }
  4421  
  4422  // GetSAMLIdPServiceProvider returns the specified SAML IdP service provider resources.
  4423  func (c *Client) GetSAMLIdPServiceProvider(ctx context.Context, name string) (types.SAMLIdPServiceProvider, error) {
  4424  	sp, err := c.grpc.GetSAMLIdPServiceProvider(ctx, &proto.GetSAMLIdPServiceProviderRequest{
  4425  		Name: name,
  4426  	})
  4427  	if err != nil {
  4428  		return nil, trace.Wrap(err)
  4429  	}
  4430  	return sp, nil
  4431  }
  4432  
  4433  // CreateSAMLIdPServiceProvider creates a new SAML IdP service provider resource.
  4434  func (c *Client) CreateSAMLIdPServiceProvider(ctx context.Context, sp types.SAMLIdPServiceProvider) error {
  4435  	spV1, ok := sp.(*types.SAMLIdPServiceProviderV1)
  4436  	if !ok {
  4437  		return trace.BadParameter("unsupported SAML IdP service provider type %T", sp)
  4438  	}
  4439  
  4440  	_, err := c.grpc.CreateSAMLIdPServiceProvider(ctx, spV1)
  4441  	if err != nil {
  4442  		return trace.Wrap(err)
  4443  	}
  4444  	return nil
  4445  }
  4446  
  4447  // UpdateSAMLIdPServiceProvider updates an existing SAML IdP service provider resource.
  4448  func (c *Client) UpdateSAMLIdPServiceProvider(ctx context.Context, sp types.SAMLIdPServiceProvider) error {
  4449  	spV1, ok := sp.(*types.SAMLIdPServiceProviderV1)
  4450  	if !ok {
  4451  		return trace.BadParameter("unsupported SAML IdP service provider type %T", sp)
  4452  	}
  4453  
  4454  	_, err := c.grpc.UpdateSAMLIdPServiceProvider(ctx, spV1)
  4455  	if err != nil {
  4456  		return trace.Wrap(err)
  4457  	}
  4458  	return nil
  4459  }
  4460  
  4461  // DeleteSAMLIdPServiceProvider removes the specified SAML IdP service provider resource.
  4462  func (c *Client) DeleteSAMLIdPServiceProvider(ctx context.Context, name string) error {
  4463  	_, err := c.grpc.DeleteSAMLIdPServiceProvider(ctx, &proto.DeleteSAMLIdPServiceProviderRequest{
  4464  		Name: name,
  4465  	})
  4466  	if err != nil {
  4467  		return trace.Wrap(err)
  4468  	}
  4469  	return nil
  4470  }
  4471  
  4472  // DeleteAllSAMLIdPServiceProviders removes all SAML IdP service providers.
  4473  func (c *Client) DeleteAllSAMLIdPServiceProviders(ctx context.Context) error {
  4474  	_, err := c.grpc.DeleteAllSAMLIdPServiceProviders(ctx, &emptypb.Empty{})
  4475  	if err != nil {
  4476  		return trace.Wrap(err)
  4477  	}
  4478  	return nil
  4479  }
  4480  
  4481  // ListUserGroups returns a paginated list of SAML IdP service provider resources.
  4482  func (c *Client) ListUserGroups(ctx context.Context, pageSize int, nextKey string) ([]types.UserGroup, string, error) {
  4483  	resp, err := c.grpc.ListUserGroups(ctx, &proto.ListUserGroupsRequest{
  4484  		Limit:   int32(pageSize),
  4485  		NextKey: nextKey,
  4486  	})
  4487  	if err != nil {
  4488  		return nil, "", trace.Wrap(err)
  4489  	}
  4490  	userGroups := make([]types.UserGroup, 0, len(resp.GetUserGroups()))
  4491  	for _, ug := range resp.GetUserGroups() {
  4492  		userGroups = append(userGroups, ug)
  4493  	}
  4494  	return userGroups, resp.GetNextKey(), nil
  4495  }
  4496  
  4497  // GetUserGroup returns the specified SAML IdP service provider resources.
  4498  func (c *Client) GetUserGroup(ctx context.Context, name string) (types.UserGroup, error) {
  4499  	ug, err := c.grpc.GetUserGroup(ctx, &proto.GetUserGroupRequest{
  4500  		Name: name,
  4501  	})
  4502  	if err != nil {
  4503  		return nil, trace.Wrap(err)
  4504  	}
  4505  	return ug, nil
  4506  }
  4507  
  4508  // CreateUserGroup creates a new user group resource.
  4509  func (c *Client) CreateUserGroup(ctx context.Context, ug types.UserGroup) error {
  4510  	ugV1, ok := ug.(*types.UserGroupV1)
  4511  	if !ok {
  4512  		return trace.BadParameter("unsupported user group type %T", ug)
  4513  	}
  4514  
  4515  	_, err := c.grpc.CreateUserGroup(ctx, ugV1)
  4516  	if err != nil {
  4517  		return trace.Wrap(err)
  4518  	}
  4519  	return nil
  4520  }
  4521  
  4522  // UpdateUserGroup updates an existing user group resource.
  4523  func (c *Client) UpdateUserGroup(ctx context.Context, ug types.UserGroup) error {
  4524  	ugV1, ok := ug.(*types.UserGroupV1)
  4525  	if !ok {
  4526  		return trace.BadParameter("unsupported user group type %T", ug)
  4527  	}
  4528  
  4529  	_, err := c.grpc.UpdateUserGroup(ctx, ugV1)
  4530  	if err != nil {
  4531  		return trace.Wrap(err)
  4532  	}
  4533  	return nil
  4534  }
  4535  
  4536  // DeleteUserGroup removes the specified user group resource.
  4537  func (c *Client) DeleteUserGroup(ctx context.Context, name string) error {
  4538  	_, err := c.grpc.DeleteUserGroup(ctx, &proto.DeleteUserGroupRequest{
  4539  		Name: name,
  4540  	})
  4541  	if err != nil {
  4542  		return trace.Wrap(err)
  4543  	}
  4544  	return nil
  4545  }
  4546  
  4547  // DeleteAllUserGroups removes all user groups.
  4548  func (c *Client) DeleteAllUserGroups(ctx context.Context) error {
  4549  	_, err := c.grpc.DeleteAllUserGroups(ctx, &emptypb.Empty{})
  4550  	if err != nil {
  4551  		return trace.Wrap(err)
  4552  	}
  4553  	return nil
  4554  }
  4555  
  4556  // ExportUpgradeWindows is used to load derived upgrade window values for agents that
  4557  // need to export schedules to external upgraders.
  4558  func (c *Client) ExportUpgradeWindows(ctx context.Context, req proto.ExportUpgradeWindowsRequest) (proto.ExportUpgradeWindowsResponse, error) {
  4559  	rsp, err := c.grpc.ExportUpgradeWindows(ctx, &req)
  4560  	if err != nil {
  4561  		return proto.ExportUpgradeWindowsResponse{}, trace.Wrap(err)
  4562  	}
  4563  	return *rsp, nil
  4564  }
  4565  
  4566  // GetClusterMaintenanceConfig gets the current maintenance window config singleton.
  4567  func (c *Client) GetClusterMaintenanceConfig(ctx context.Context) (types.ClusterMaintenanceConfig, error) {
  4568  	rsp, err := c.grpc.GetClusterMaintenanceConfig(ctx, &emptypb.Empty{})
  4569  	if err != nil {
  4570  		return nil, trace.Wrap(err)
  4571  	}
  4572  	return rsp, nil
  4573  }
  4574  
  4575  // UpdateClusterMaintenanceConfig updates the current maintenance window config singleton.
  4576  func (c *Client) UpdateClusterMaintenanceConfig(ctx context.Context, cmc types.ClusterMaintenanceConfig) error {
  4577  	req, ok := cmc.(*types.ClusterMaintenanceConfigV1)
  4578  	if !ok {
  4579  		return trace.BadParameter("unexpected maintenance config type: %T", cmc)
  4580  	}
  4581  
  4582  	_, err := c.grpc.UpdateClusterMaintenanceConfig(ctx, req)
  4583  	return trace.Wrap(err)
  4584  }
  4585  
  4586  // DeleteClusterMaintenanceConfig deletes the current maintenance window config singleton.
  4587  func (c *Client) DeleteClusterMaintenanceConfig(ctx context.Context) error {
  4588  	_, err := c.grpc.DeleteClusterMaintenanceConfig(ctx, &emptypb.Empty{})
  4589  	return trace.Wrap(err)
  4590  }
  4591  
  4592  // integrationsClient returns an unadorned Integration client, using the underlying
  4593  // Auth gRPC connection.
  4594  func (c *Client) integrationsClient() integrationpb.IntegrationServiceClient {
  4595  	return integrationpb.NewIntegrationServiceClient(c.conn)
  4596  }
  4597  
  4598  // ListIntegrations returns a paginated list of Integrations.
  4599  // The response includes a nextKey which must be used to fetch the next page.
  4600  func (c *Client) ListIntegrations(ctx context.Context, pageSize int, nextKey string) ([]types.Integration, string, error) {
  4601  	resp, err := c.integrationsClient().ListIntegrations(ctx, &integrationpb.ListIntegrationsRequest{
  4602  		Limit:   int32(pageSize),
  4603  		NextKey: nextKey,
  4604  	})
  4605  	if err != nil {
  4606  		return nil, "", trace.Wrap(err)
  4607  	}
  4608  
  4609  	integrations := make([]types.Integration, 0, len(resp.GetIntegrations()))
  4610  	for _, ig := range resp.GetIntegrations() {
  4611  		integrations = append(integrations, ig)
  4612  	}
  4613  
  4614  	return integrations, resp.GetNextKey(), nil
  4615  }
  4616  
  4617  // ListAllIntegrations returns the list of all Integrations.
  4618  func (c *Client) ListAllIntegrations(ctx context.Context) ([]types.Integration, error) {
  4619  	var result []types.Integration
  4620  	var nextKey string
  4621  	for {
  4622  		integrations, nextKey, err := c.ListIntegrations(ctx, 0, nextKey)
  4623  		if err != nil {
  4624  			return nil, trace.Wrap(err)
  4625  		}
  4626  		result = append(result, integrations...)
  4627  		if nextKey == "" {
  4628  			return result, nil
  4629  		}
  4630  	}
  4631  }
  4632  
  4633  // GetIntegration returns an Integration by its name.
  4634  func (c *Client) GetIntegration(ctx context.Context, name string) (types.Integration, error) {
  4635  	ig, err := c.integrationsClient().GetIntegration(ctx, &integrationpb.GetIntegrationRequest{
  4636  		Name: name,
  4637  	})
  4638  	if err != nil {
  4639  		return nil, trace.Wrap(err)
  4640  	}
  4641  
  4642  	return ig, nil
  4643  }
  4644  
  4645  // CreateIntegration creates a new Integration.
  4646  func (c *Client) CreateIntegration(ctx context.Context, ig types.Integration) (types.Integration, error) {
  4647  	igV1, ok := ig.(*types.IntegrationV1)
  4648  	if !ok {
  4649  		return nil, trace.BadParameter("unsupported integration type %T", ig)
  4650  	}
  4651  
  4652  	ig, err := c.integrationsClient().CreateIntegration(ctx, &integrationpb.CreateIntegrationRequest{Integration: igV1})
  4653  	if err != nil {
  4654  		return nil, trace.Wrap(err)
  4655  	}
  4656  
  4657  	return ig, nil
  4658  }
  4659  
  4660  // UpdateIntegration updates an existing Integration.
  4661  func (c *Client) UpdateIntegration(ctx context.Context, ig types.Integration) (types.Integration, error) {
  4662  	igV1, ok := ig.(*types.IntegrationV1)
  4663  	if !ok {
  4664  		return nil, trace.BadParameter("unsupported integration type %T", ig)
  4665  	}
  4666  
  4667  	ig, err := c.integrationsClient().UpdateIntegration(ctx, &integrationpb.UpdateIntegrationRequest{Integration: igV1})
  4668  	if err != nil {
  4669  		return nil, trace.Wrap(err)
  4670  	}
  4671  
  4672  	return ig, nil
  4673  }
  4674  
  4675  // DeleteIntegration removes an Integration by its name.
  4676  func (c *Client) DeleteIntegration(ctx context.Context, name string) error {
  4677  	_, err := c.integrationsClient().DeleteIntegration(ctx, &integrationpb.DeleteIntegrationRequest{
  4678  		Name: name,
  4679  	})
  4680  	return trace.Wrap(err)
  4681  }
  4682  
  4683  // DeleteAllIntegrations removes all Integrations.
  4684  func (c *Client) DeleteAllIntegrations(ctx context.Context) error {
  4685  	_, err := c.integrationsClient().DeleteAllIntegrations(ctx, &integrationpb.DeleteAllIntegrationsRequest{})
  4686  	return trace.Wrap(err)
  4687  }
  4688  
  4689  // GenerateAWSOIDCToken generates a token to be used when executing an AWS OIDC Integration action.
  4690  func (c *Client) GenerateAWSOIDCToken(ctx context.Context, integration string) (string, error) {
  4691  	resp, err := c.integrationsClient().GenerateAWSOIDCToken(ctx, &integrationpb.GenerateAWSOIDCTokenRequest{
  4692  		Integration: integration,
  4693  	})
  4694  	if err != nil {
  4695  		return "", trace.Wrap(err)
  4696  	}
  4697  
  4698  	return resp.GetToken(), nil
  4699  }
  4700  
  4701  // PluginsClient returns an unadorned Plugins client, using the underlying
  4702  // Auth gRPC connection.
  4703  // Clients connecting to non-Enterprise clusters, or older Teleport versions,
  4704  // still get a plugins client when calling this method, but all RPCs will return
  4705  // "not implemented" errors (as per the default gRPC behavior).
  4706  func (c *Client) PluginsClient() pluginspb.PluginServiceClient {
  4707  	return pluginspb.NewPluginServiceClient(c.conn)
  4708  }
  4709  
  4710  // GetLoginRule retrieves a login rule described by name.
  4711  func (c *Client) GetLoginRule(ctx context.Context, name string) (*loginrulepb.LoginRule, error) {
  4712  	rule, err := c.LoginRuleClient().GetLoginRule(ctx, &loginrulepb.GetLoginRuleRequest{
  4713  		Name: name,
  4714  	})
  4715  	return rule, trace.Wrap(err)
  4716  }
  4717  
  4718  // CreateLoginRule creates a login rule if one with the same name does not
  4719  // already exist, else it returns an error.
  4720  func (c *Client) CreateLoginRule(ctx context.Context, rule *loginrulepb.LoginRule) (*loginrulepb.LoginRule, error) {
  4721  	rule, err := c.LoginRuleClient().CreateLoginRule(ctx, &loginrulepb.CreateLoginRuleRequest{
  4722  		LoginRule: rule,
  4723  	})
  4724  	return rule, trace.Wrap(err)
  4725  }
  4726  
  4727  // UpsertLoginRule creates a login rule if one with the same name does not
  4728  // already exist, else it replaces the existing login rule.
  4729  func (c *Client) UpsertLoginRule(ctx context.Context, rule *loginrulepb.LoginRule) (*loginrulepb.LoginRule, error) {
  4730  	rule, err := c.LoginRuleClient().UpsertLoginRule(ctx, &loginrulepb.UpsertLoginRuleRequest{
  4731  		LoginRule: rule,
  4732  	})
  4733  	return rule, trace.Wrap(err)
  4734  }
  4735  
  4736  // DeleteLoginRule deletes an existing login rule by name.
  4737  func (c *Client) DeleteLoginRule(ctx context.Context, name string) error {
  4738  	_, err := c.LoginRuleClient().DeleteLoginRule(ctx, &loginrulepb.DeleteLoginRuleRequest{
  4739  		Name: name,
  4740  	})
  4741  	return trace.Wrap(err)
  4742  }
  4743  
  4744  // OktaClient returns an Okta client.
  4745  // Clients connecting older Teleport versions still get an okta client when
  4746  // calling this method, but all RPCs will return "not implemented" errors (as per
  4747  // the default gRPC behavior).
  4748  func (c *Client) OktaClient() *okta.Client {
  4749  	return okta.NewClient(oktapb.NewOktaServiceClient(c.conn))
  4750  }
  4751  
  4752  func (c *Client) SCIMClient() *scim.Client {
  4753  	return scim.NewClientFromConn(c.conn)
  4754  }
  4755  
  4756  // AccessListClient returns an access list client.
  4757  // Clients connecting to  older Teleport versions, still get an access list client
  4758  // when calling this method, but all RPCs will return "not implemented" errors
  4759  // (as per the default gRPC behavior).
  4760  func (c *Client) AccessListClient() *accesslist.Client {
  4761  	return accesslist.NewClient(accesslistv1.NewAccessListServiceClient(c.conn))
  4762  }
  4763  
  4764  // AccessMonitoringRulesClient returns an Access Monitoring Rules client.
  4765  // Clients connecting to  older Teleport versions, still get an access list client
  4766  // when calling this method, but all RPCs will return "not implemented" errors
  4767  // (as per the default gRPC behavior).
  4768  func (c *Client) AccessMonitoringRulesClient() *accessmonitoringrules.Client {
  4769  	return accessmonitoringrules.NewClient(accessmonitoringrulev1.NewAccessMonitoringRulesServiceClient(c.conn))
  4770  }
  4771  
  4772  // DatabaseObjectImportRuleClient returns a client for managing database object import rules.
  4773  func (c *Client) DatabaseObjectImportRuleClient() dbobjectimportrulev1.DatabaseObjectImportRuleServiceClient {
  4774  	return dbobjectimportrulev1.NewDatabaseObjectImportRuleServiceClient(c.conn)
  4775  }
  4776  
  4777  // DatabaseObjectClient returns a client for managing database objects.
  4778  func (c *Client) DatabaseObjectClient() dbobjectv1.DatabaseObjectServiceClient {
  4779  	return dbobjectv1.NewDatabaseObjectServiceClient(c.conn)
  4780  }
  4781  
  4782  // DiscoveryConfigClient returns a DiscoveryConfig client.
  4783  // Clients connecting to older Teleport versions, still get an DiscoveryConfig client
  4784  // when calling this method, but all RPCs will return "not implemented" errors
  4785  // (as per the default gRPC behavior).
  4786  func (c *Client) DiscoveryConfigClient() *discoveryconfig.Client {
  4787  	return discoveryconfig.NewClient(discoveryconfigv1.NewDiscoveryConfigServiceClient(c.conn))
  4788  }
  4789  
  4790  // CrownJewelServiceClient returns a CrownJewel client.
  4791  // Clients connecting to older Teleport versions, still get a CrownJewel client
  4792  // when calling this method, but all RPCs will return "not implemented" errors
  4793  // (as per the default gRPC behavior).
  4794  func (c *Client) CrownJewelServiceClient() *crownjewelapi.Client {
  4795  	return crownjewel.NewClient(crownjewelv1.NewCrownJewelServiceClient(c.conn))
  4796  }
  4797  
  4798  // UserLoginStateClient returns a user login state client.
  4799  // Clients connecting to older Teleport versions, still get a user login state client
  4800  // when calling this method, but all RPCs will return "not implemented" errors
  4801  // (as per the default gRPC behavior).
  4802  func (c *Client) UserLoginStateClient() *userloginstate.Client {
  4803  	return userloginstate.NewClient(userloginstatev1.NewUserLoginStateServiceClient(c.conn))
  4804  }
  4805  
  4806  // GetCertAuthority retrieves a CA by type and domain.
  4807  func (c *Client) GetCertAuthority(ctx context.Context, id types.CertAuthID, loadKeys bool) (types.CertAuthority, error) {
  4808  	ca, err := c.TrustClient().GetCertAuthority(ctx, &trustpb.GetCertAuthorityRequest{
  4809  		Type:       string(id.Type),
  4810  		Domain:     id.DomainName,
  4811  		IncludeKey: loadKeys,
  4812  	})
  4813  
  4814  	return ca, trace.Wrap(err)
  4815  }
  4816  
  4817  // GetCertAuthorities retrieves CAs by type.
  4818  func (c *Client) GetCertAuthorities(ctx context.Context, caType types.CertAuthType, loadKeys bool) ([]types.CertAuthority, error) {
  4819  	resp, err := c.TrustClient().GetCertAuthorities(ctx, &trustpb.GetCertAuthoritiesRequest{
  4820  		Type:       string(caType),
  4821  		IncludeKey: loadKeys,
  4822  	})
  4823  	if err != nil {
  4824  		return nil, trace.Wrap(err)
  4825  	}
  4826  
  4827  	cas := make([]types.CertAuthority, 0, len(resp.CertAuthoritiesV2))
  4828  	for _, ca := range resp.CertAuthoritiesV2 {
  4829  		cas = append(cas, ca)
  4830  	}
  4831  
  4832  	return cas, nil
  4833  }
  4834  
  4835  // DeleteCertAuthority removes a CA matching the type and domain.
  4836  func (c *Client) DeleteCertAuthority(ctx context.Context, id types.CertAuthID) error {
  4837  	_, err := c.TrustClient().DeleteCertAuthority(ctx, &trustpb.DeleteCertAuthorityRequest{
  4838  		Type:   string(id.Type),
  4839  		Domain: id.DomainName,
  4840  	})
  4841  
  4842  	return trace.Wrap(err)
  4843  }
  4844  
  4845  // UpsertCertAuthority creates or updates the provided cert authority.
  4846  func (c *Client) UpsertCertAuthority(ctx context.Context, ca types.CertAuthority) (types.CertAuthority, error) {
  4847  	cav2, ok := ca.(*types.CertAuthorityV2)
  4848  	if !ok {
  4849  		return nil, trace.BadParameter("unexpected ca type %T", ca)
  4850  	}
  4851  
  4852  	out, err := c.TrustClient().UpsertCertAuthority(ctx, &trustpb.UpsertCertAuthorityRequest{
  4853  		CertAuthority: cav2,
  4854  	})
  4855  
  4856  	return out, trace.Wrap(err)
  4857  }
  4858  
  4859  // RotateCertAuthority updates or inserts new cert authority
  4860  func (c *Client) RotateCertAuthority(ctx context.Context, rr types.RotateRequest) error {
  4861  	req := &trustpb.RotateCertAuthorityRequest{
  4862  		Type:        string(rr.Type),
  4863  		TargetPhase: rr.TargetPhase,
  4864  		Mode:        rr.Mode,
  4865  	}
  4866  
  4867  	if rr.GracePeriod != nil {
  4868  		req.GracePeriod = durationpb.New(*rr.GracePeriod)
  4869  	}
  4870  
  4871  	if rr.Schedule != nil {
  4872  		req.Schedule = &trustpb.RotationSchedule{
  4873  			UpdateClients: timestamppb.New(rr.Schedule.UpdateClients),
  4874  			UpdateServers: timestamppb.New(rr.Schedule.UpdateServers),
  4875  			Standby:       timestamppb.New(rr.Schedule.Standby),
  4876  		}
  4877  	}
  4878  
  4879  	_, err := c.TrustClient().RotateCertAuthority(ctx, req)
  4880  	return trace.Wrap(err)
  4881  }
  4882  
  4883  // RotateExternalCertAuthority rotates the provided cert authority.
  4884  func (c *Client) RotateExternalCertAuthority(ctx context.Context, ca types.CertAuthority) error {
  4885  	cav2, ok := ca.(*types.CertAuthorityV2)
  4886  	if !ok {
  4887  		return trace.BadParameter("unexpected ca type %T", ca)
  4888  	}
  4889  
  4890  	_, err := c.TrustClient().RotateExternalCertAuthority(ctx, &trustpb.RotateExternalCertAuthorityRequest{
  4891  		CertAuthority: cav2,
  4892  	})
  4893  
  4894  	return trace.Wrap(err)
  4895  }
  4896  
  4897  // UpdateHeadlessAuthenticationState updates a headless authentication state.
  4898  func (c *Client) UpdateHeadlessAuthenticationState(ctx context.Context, id string, state types.HeadlessAuthenticationState, mfaResponse *proto.MFAAuthenticateResponse) error {
  4899  	_, err := c.grpc.UpdateHeadlessAuthenticationState(ctx, &proto.UpdateHeadlessAuthenticationStateRequest{
  4900  		Id:          id,
  4901  		State:       state,
  4902  		MfaResponse: mfaResponse,
  4903  	})
  4904  	if err != nil {
  4905  		return trace.Wrap(err)
  4906  	}
  4907  	return nil
  4908  }
  4909  
  4910  // GetHeadlessAuthentication retrieves a headless authentication by id.
  4911  func (c *Client) GetHeadlessAuthentication(ctx context.Context, id string) (*types.HeadlessAuthentication, error) {
  4912  	headlessAuthn, err := c.grpc.GetHeadlessAuthentication(ctx, &proto.GetHeadlessAuthenticationRequest{
  4913  		Id: id,
  4914  	})
  4915  	if err != nil {
  4916  		return nil, trace.Wrap(err)
  4917  	}
  4918  	return headlessAuthn, nil
  4919  }
  4920  
  4921  // WatchPendingHeadlessAuthentications creates a watcher for pending headless authentication for the current user.
  4922  func (c *Client) WatchPendingHeadlessAuthentications(ctx context.Context) (types.Watcher, error) {
  4923  	cancelCtx, cancel := context.WithCancel(ctx)
  4924  	stream, err := c.grpc.WatchPendingHeadlessAuthentications(cancelCtx, &emptypb.Empty{})
  4925  	if err != nil {
  4926  		cancel()
  4927  		return nil, trace.Wrap(err)
  4928  	}
  4929  	w := &streamWatcher{
  4930  		stream:  stream,
  4931  		ctx:     cancelCtx,
  4932  		cancel:  cancel,
  4933  		eventsC: make(chan types.Event),
  4934  	}
  4935  	go w.receiveEvents()
  4936  	return w, nil
  4937  }
  4938  
  4939  // CreateAssistantConversation creates a new conversation entry in the backend.
  4940  func (c *Client) CreateAssistantConversation(ctx context.Context, req *assist.CreateAssistantConversationRequest) (*assist.CreateAssistantConversationResponse, error) {
  4941  	resp, err := c.grpc.CreateAssistantConversation(ctx, req)
  4942  	if err != nil {
  4943  		return nil, trace.Wrap(err)
  4944  	}
  4945  
  4946  	return resp, nil
  4947  }
  4948  
  4949  // GetAssistantMessages retrieves assistant messages with given conversation ID.
  4950  func (c *Client) GetAssistantMessages(ctx context.Context, req *assist.GetAssistantMessagesRequest) (*assist.GetAssistantMessagesResponse, error) {
  4951  	messages, err := c.grpc.GetAssistantMessages(ctx, req)
  4952  	if err != nil {
  4953  		return nil, trace.Wrap(err)
  4954  	}
  4955  	return messages, nil
  4956  }
  4957  
  4958  // DeleteAssistantConversation deletes a conversation entry in the backend.
  4959  func (c *Client) DeleteAssistantConversation(ctx context.Context, req *assist.DeleteAssistantConversationRequest) error {
  4960  	_, err := c.grpc.DeleteAssistantConversation(ctx, req)
  4961  	if err != nil {
  4962  		return trace.Wrap(err)
  4963  	}
  4964  	return nil
  4965  }
  4966  
  4967  // IsAssistEnabled returns true if the assist is enabled or not on the auth level.
  4968  func (c *Client) IsAssistEnabled(ctx context.Context) (*assist.IsAssistEnabledResponse, error) {
  4969  	resp, err := c.grpc.IsAssistEnabled(ctx, &assist.IsAssistEnabledRequest{})
  4970  	if err != nil {
  4971  		return nil, trace.Wrap(err)
  4972  	}
  4973  	return resp, nil
  4974  }
  4975  
  4976  // GetAssistantConversations returns all conversations started by a user.
  4977  func (c *Client) GetAssistantConversations(ctx context.Context, request *assist.GetAssistantConversationsRequest) (*assist.GetAssistantConversationsResponse, error) {
  4978  	messages, err := c.grpc.GetAssistantConversations(ctx, request)
  4979  	if err != nil {
  4980  		return nil, trace.Wrap(err)
  4981  	}
  4982  	return messages, nil
  4983  }
  4984  
  4985  // CreateAssistantMessage saves a new conversation message.
  4986  func (c *Client) CreateAssistantMessage(ctx context.Context, in *assist.CreateAssistantMessageRequest) error {
  4987  	_, err := c.grpc.CreateAssistantMessage(ctx, in)
  4988  	if err != nil {
  4989  		return trace.Wrap(err)
  4990  	}
  4991  	return nil
  4992  }
  4993  
  4994  // UpdateAssistantConversationInfo updates conversation info.
  4995  func (c *Client) UpdateAssistantConversationInfo(ctx context.Context, in *assist.UpdateAssistantConversationInfoRequest) error {
  4996  	_, err := c.grpc.UpdateAssistantConversationInfo(ctx, in)
  4997  	if err != nil {
  4998  		return trace.Wrap(err)
  4999  	}
  5000  	return nil
  5001  }
  5002  
  5003  func (c *Client) GetAssistantEmbeddings(ctx context.Context, in *assist.GetAssistantEmbeddingsRequest) (*assist.GetAssistantEmbeddingsResponse, error) {
  5004  	result, err := c.EmbeddingClient().GetAssistantEmbeddings(ctx, in)
  5005  	if err != nil {
  5006  		return nil, trace.Wrap(err)
  5007  	}
  5008  	return result, nil
  5009  }
  5010  
  5011  // GetUserPreferences returns the user preferences for a given user.
  5012  func (c *Client) GetUserPreferences(ctx context.Context, in *userpreferencespb.GetUserPreferencesRequest) (*userpreferencespb.GetUserPreferencesResponse, error) {
  5013  	resp, err := c.grpc.GetUserPreferences(ctx, in)
  5014  	if err != nil {
  5015  		return nil, trace.Wrap(err)
  5016  	}
  5017  	return resp, nil
  5018  }
  5019  
  5020  // UpsertUserPreferences creates or updates user preferences for a given username.
  5021  func (c *Client) UpsertUserPreferences(ctx context.Context, in *userpreferencespb.UpsertUserPreferencesRequest) error {
  5022  	_, err := c.grpc.UpsertUserPreferences(ctx, in)
  5023  	if err != nil {
  5024  		return trace.Wrap(err)
  5025  	}
  5026  	return nil
  5027  }
  5028  
  5029  // ResourceUsageClient returns an unadorned Resource Usage service client,
  5030  // using the underlying Auth gRPC connection.
  5031  // Clients connecting to non-Enterprise clusters, or older Teleport versions,
  5032  // still get a plugins client when calling this method, but all RPCs will return
  5033  // "not implemented" errors (as per the default gRPC behavior).
  5034  func (c *Client) ResourceUsageClient() resourceusagepb.ResourceUsageServiceClient {
  5035  	return resourceusagepb.NewResourceUsageServiceClient(c.conn)
  5036  }
  5037  
  5038  // UpdateRemoteCluster updates remote cluster from the specified value.
  5039  // TODO(noah): In v17.0.0 this method should switch to call UpdateRemoteCluster
  5040  // on the presence service client.
  5041  func (c *Client) UpdateRemoteCluster(ctx context.Context, rc types.RemoteCluster) error {
  5042  	rcV3, ok := rc.(*types.RemoteClusterV3)
  5043  	if !ok {
  5044  		return trace.BadParameter("unsupported remote cluster type %T", rcV3)
  5045  	}
  5046  
  5047  	_, err := c.grpc.UpdateRemoteCluster(ctx, rcV3)
  5048  	return trace.Wrap(err)
  5049  }
  5050  
  5051  // ListRemoteClusters returns a page of remote clusters.
  5052  func (c *Client) ListRemoteClusters(ctx context.Context, pageSize int, nextToken string) ([]types.RemoteCluster, string, error) {
  5053  	res, err := c.PresenceServiceClient().ListRemoteClusters(ctx, &presencepb.ListRemoteClustersRequest{
  5054  		PageSize:  int32(pageSize),
  5055  		PageToken: nextToken,
  5056  	})
  5057  	if err != nil {
  5058  		return nil, "", trace.Wrap(err)
  5059  	}
  5060  	rcs := make([]types.RemoteCluster, 0, len(res.RemoteClusters))
  5061  	for _, rc := range res.RemoteClusters {
  5062  		rcs = append(rcs, rc)
  5063  	}
  5064  	return rcs, res.NextPageToken, nil
  5065  }
  5066  
  5067  // DeleteRemoteCluster creates remote cluster resource
  5068  func (c *Client) DeleteRemoteCluster(ctx context.Context, name string) error {
  5069  	_, err := c.PresenceServiceClient().DeleteRemoteCluster(ctx, &presencepb.DeleteRemoteClusterRequest{
  5070  		Name: name,
  5071  	})
  5072  	return trace.Wrap(err)
  5073  }
  5074  
  5075  // GetRemoteCluster returns remote cluster by name
  5076  func (c *Client) GetRemoteCluster(ctx context.Context, name string) (types.RemoteCluster, error) {
  5077  	rc, err := c.PresenceServiceClient().GetRemoteCluster(ctx, &presencepb.GetRemoteClusterRequest{
  5078  		Name: name,
  5079  	})
  5080  	return rc, trace.Wrap(err)
  5081  }