diff --git a/api/client/client.go b/api/client/client.go index d649fb6b80466..ea798d3ff1f18 100644 --- a/api/client/client.go +++ b/api/client/client.go @@ -83,6 +83,11 @@ func New(ctx context.Context, cfg Config) (*Client, error) { return c, nil } +// GetConnection returns GRPC connection +func (c *Client) GetConnection() *grpc.ClientConn { + return c.conn +} + // getDialer builds a grpc dialer for the client from a ContextDialer. // The ContextDialer is chosen from available options, preferring one from // credentials, then from configuration, and lastly from addresses. diff --git a/api/types/constants.go b/api/types/constants.go index c8fc3d94484bc..7b4fe5c5ff690 100644 --- a/api/types/constants.go +++ b/api/types/constants.go @@ -190,6 +190,9 @@ const ( // KindMFADevice is an MFA device for a user. KindMFADevice = "mfa_device" + // KindBilling represents access to cloud billing features + KindBilling = "billing" + // V3 is the third version of resources. V3 = "v3" diff --git a/e b/e index f8bf84cc52f15..0e18de867919f 160000 --- a/e +++ b/e @@ -1 +1 @@ -Subproject commit f8bf84cc52f159eaf2ff6a59f3626f95faeef98b +Subproject commit 0e18de867919f93284174a54ca82505fce15a4e2 diff --git a/lib/auth/apiserver.go b/lib/auth/apiserver.go index 9c847ba222339..badb6d3f8ae17 100644 --- a/lib/auth/apiserver.go +++ b/lib/auth/apiserver.go @@ -1,5 +1,5 @@ /* -Copyright 2015-2019 Gravitational, Inc. +Copyright 2015-2021 Gravitational, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -35,6 +35,7 @@ import ( "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/events" "github.com/gravitational/teleport/lib/httplib" + "github.com/gravitational/teleport/lib/plugin" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/session" "github.com/gravitational/teleport/lib/utils" @@ -46,6 +47,7 @@ import ( ) type APIConfig struct { + PluginRegistry plugin.Registry AuthServer *Server SessionService session.Service AuditLog events.IAuditLog @@ -80,7 +82,7 @@ type APIServer struct { } // NewAPIServer returns a new instance of APIServer HTTP handler -func NewAPIServer(config *APIConfig) http.Handler { +func NewAPIServer(config *APIConfig) (http.Handler, error) { srv := APIServer{ APIConfig: *config, Clock: clockwork.NewRealClock(), @@ -246,15 +248,17 @@ func NewAPIServer(config *APIConfig) http.Handler { srv.GET("/:version/events", srv.withAuth(srv.searchEvents)) srv.GET("/:version/events/session", srv.withAuth(srv.searchSessionEvents)) - if plugin := GetPlugin(); plugin != nil { - plugin.AddHandlers(&srv) + if config.PluginRegistry != nil { + if err := config.PluginRegistry.RegisterAuthWebHandlers(&srv); err != nil { + return nil, trace.Wrap(err) + } } return httplib.RewritePaths(&srv.Router, httplib.Rewrite("/v1/nodes", "/v1/namespaces/default/nodes"), httplib.Rewrite("/v1/sessions", "/v1/namespaces/default/sessions"), httplib.Rewrite("/v1/sessions/([^/]+)/(.*)", "/v1/namespaces/default/sessions/$1/$2"), - ) + ), nil } // HandlerWithAuthFunc is http handler with passed auth context diff --git a/lib/auth/grpcserver.go b/lib/auth/grpcserver.go index 5df896c8f8393..ac45672df3095 100644 --- a/lib/auth/grpcserver.go +++ b/lib/auth/grpcserver.go @@ -1,5 +1,5 @@ /* -Copyright 2018-2020 Gravitational, Inc. +Copyright 2018-2021 Gravitational, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -57,6 +57,15 @@ type GRPCServer struct { server *grpc.Server } +// GetServer returns an instance of grpc server +func (g *GRPCServer) GetServer() (*grpc.Server, error) { + if g.server == nil { + return nil, trace.BadParameter("grpc server has not been initialized") + } + + return g.server, nil +} + // EmitAuditEvent emits audit event func (g *GRPCServer) EmitAuditEvent(ctx context.Context, req *events.OneOf) (*empty.Empty, error) { auth, err := g.authenticate(ctx) diff --git a/lib/auth/middleware.go b/lib/auth/middleware.go index c15c9b691000f..511909f3b732c 100644 --- a/lib/auth/middleware.go +++ b/lib/auth/middleware.go @@ -1,5 +1,5 @@ /* -Copyright 2017-2020 Gravitational, Inc. +Copyright 2017-2021 Gravitational, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -126,7 +126,13 @@ func NewTLSServer(cfg TLSServerConfig) (*TLSServer, error) { AcceptedUsage: cfg.AcceptedUsage, Limiter: limiter, } - authMiddleware.Wrap(NewAPIServer(&cfg.APIConfig)) + + apiServer, err := NewAPIServer(&cfg.APIConfig) + if err != nil { + return nil, trace.Wrap(err) + } + + authMiddleware.Wrap(apiServer) // Wrap sets the next middleware in chain to the authMiddleware limiter.WrapHandle(authMiddleware) // force client auth if given @@ -163,6 +169,12 @@ func NewTLSServer(cfg TLSServerConfig) (*TLSServer, error) { return nil, trace.Wrap(err) } + if cfg.PluginRegistry != nil { + if err := cfg.PluginRegistry.RegisterAuthServices(server.grpcServer); err != nil { + return nil, trace.Wrap(err) + } + } + return server, nil } diff --git a/lib/auth/plugin.go b/lib/auth/plugin.go deleted file mode 100644 index b2d460dda5cf8..0000000000000 --- a/lib/auth/plugin.go +++ /dev/null @@ -1,44 +0,0 @@ -/* -Copyright 2017 Gravitational, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package auth - -import ( - "sync" -) - -var pluginMutex = &sync.Mutex{} -var plugin Plugin - -// GetPlugin returns auth API server plugin that allows injecting handlers -func GetPlugin() Plugin { - pluginMutex.Lock() - defer pluginMutex.Unlock() - return plugin -} - -// SetPlugin sets plugin for the auth API server -func SetPlugin(p Plugin) { - pluginMutex.Lock() - defer pluginMutex.Unlock() - plugin = p -} - -// Plugin is auth API server extension setter -type Plugin interface { - // AddHandlers adds handlers to the auth API server - AddHandlers(srv *APIServer) -} diff --git a/lib/httplib/httpheaders.go b/lib/httplib/httpheaders.go index f5dfc41afe65f..4b82d93cb1e60 100644 --- a/lib/httplib/httpheaders.go +++ b/lib/httplib/httpheaders.go @@ -63,7 +63,8 @@ func SetIndexHTMLHeaders(h http.Header) { // Set content policy flags var cspValue = strings.Join([]string{ - "script-src 'self'", + // enterprise version uses stripe.com to update billing information + "script-src 'self' https://js.stripe.com", // 'unsafe-inline' needed for reactjs inline styles "style-src 'self' 'unsafe-inline'", "object-src 'none'", diff --git a/lib/plugin/registry.go b/lib/plugin/registry.go new file mode 100644 index 0000000000000..9d8090cdd8457 --- /dev/null +++ b/lib/plugin/registry.go @@ -0,0 +1,108 @@ +/* +Copyright 2015-2021 Gravitational, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package plugin + +import "github.com/gravitational/trace" + +// Plugin describes interfaces of the teleport core plugin +type Plugin interface { + // GetName returns plugin name + GetName() string + // RegisterProxyWebHandlers registers new methods with the ProxyWebHandler + RegisterProxyWebHandlers(handler interface{}) error + // RegisterAuthWebHandlers registers new methods with the Auth Web Handler + RegisterAuthWebHandlers(service interface{}) error + // RegisterAuthServices registers new services on the AuthServer + RegisterAuthServices(server interface{}) error +} + +// Registry is the plugin registry +type Registry interface { + // Add adds plugin to the registry + Add(plugin Plugin) error + // RegisterProxyWebHandlers registers Teleport Proxy web handlers + RegisterProxyWebHandlers(hander interface{}) error + // RegisterAuthWebHandlers registers Teleport Auth web handlers + RegisterAuthWebHandlers(handler interface{}) error + // RegisterAuthServices registerse Teleport AuthServer services + RegisterAuthServices(server interface{}) error +} + +// NewRegistry creates an instance of the Registry +func NewRegistry() Registry { + return ®istry{ + plugins: make(map[string]Plugin), + } +} + +type registry struct { + plugins map[string]Plugin +} + +// Add adds plugin to the plugin registry +func (r *registry) Add(p Plugin) error { + if p == nil { + return trace.BadParameter("missing plugin") + } + + name := p.GetName() + if name == "" { + return trace.BadParameter("missing plugin name") + } + + _, exists := r.plugins[name] + if exists { + return trace.AlreadyExists("plugin %v already exists", name) + } + + r.plugins[name] = p + + return nil +} + +// RegisterProxyWebHandlers registers Teleport Proxy web handlers +func (r *registry) RegisterProxyWebHandlers(hander interface{}) error { + for _, p := range r.plugins { + if err := p.RegisterProxyWebHandlers(hander); err != nil { + return trace.Wrap(err, "plugin %v failed to register", p.GetName()) + } + } + + return nil +} + +// RegisterAuthWebHandlers registers Teleport Auth web handlers +func (r *registry) RegisterAuthWebHandlers(handler interface{}) error { + for _, p := range r.plugins { + if err := p.RegisterAuthWebHandlers(handler); err != nil { + return trace.Wrap(err, "plugin %v failed to register", p.GetName()) + } + } + + return nil +} + +// RegisterAuthServices registerse Teleport AuthServer services +func (r *registry) RegisterAuthServices(server interface{}) error { + for _, p := range r.plugins { + if err := p.RegisterAuthServices(server); err != nil { + return trace.Wrap(err, "plugin %v failed to register", p.GetName()) + } + } + + return nil +} diff --git a/lib/service/cfg.go b/lib/service/cfg.go index 662f91f07f739..f38f41d1414e4 100644 --- a/lib/service/cfg.go +++ b/lib/service/cfg.go @@ -1,5 +1,5 @@ /* -Copyright 2015-2020 Gravitational, Inc. +Copyright 2015-2021 Gravitational, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -38,6 +38,7 @@ import ( "github.com/gravitational/teleport/lib/events" "github.com/gravitational/teleport/lib/limiter" "github.com/gravitational/teleport/lib/pam" + "github.com/gravitational/teleport/lib/plugin" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/sshca" "github.com/gravitational/teleport/lib/tlsca" @@ -200,6 +201,9 @@ type Config struct { // Log optionally specifies the logger Log utils.Logger + + // PluginRegistry allows adding enterprise logic to Teleport services + PluginRegistry plugin.Registry } // ApplyToken assigns a given token to all internal services but only if token diff --git a/lib/service/db.go b/lib/service/db.go index c81183518f6d6..541d592f87b56 100644 --- a/lib/service/db.go +++ b/lib/service/db.go @@ -187,7 +187,7 @@ func (process *TeleportProcess) initDatabaseService() (retErr error) { }() // Execute this when the process running database proxy service exits. - process.onExit("db.stop", func(payload interface{}) { + process.OnExit("db.stop", func(payload interface{}) { log.Info("Shutting down.") if dbService != nil { warnOnErr(dbService.Close(), process.log) diff --git a/lib/service/kubernetes.go b/lib/service/kubernetes.go index 2e8baaa0e6c77..744e30cf270e1 100644 --- a/lib/service/kubernetes.go +++ b/lib/service/kubernetes.go @@ -265,7 +265,7 @@ func (process *TeleportProcess) initKubernetesService(log *logrus.Entry, conn *C }) // Cleanup, when process is exiting. - process.onExit("kube.shutdown", func(payload interface{}) { + process.OnExit("kube.shutdown", func(payload interface{}) { if asyncEmitter != nil { warnOnErr(asyncEmitter.Close(), log) } diff --git a/lib/service/service.go b/lib/service/service.go index 4176ba474e7da..8f9e3e7001b7b 100644 --- a/lib/service/service.go +++ b/lib/service/service.go @@ -1,5 +1,5 @@ /* -Copyright 2015-2020 Gravitational, Inc. +Copyright 2015-2021 Gravitational, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -69,6 +69,7 @@ import ( "github.com/gravitational/teleport/lib/limiter" "github.com/gravitational/teleport/lib/modules" "github.com/gravitational/teleport/lib/multiplexer" + "github.com/gravitational/teleport/lib/plugin" "github.com/gravitational/teleport/lib/reversetunnel" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/session" @@ -241,6 +242,9 @@ type TeleportProcess struct { Supervisor Config *Config + // PluginsRegistry handles plugin registrations with Teleport services + PluginRegistry plugin.Registry + // localAuth has local auth server listed in case if this process // has started with auth server role enabled localAuth *auth.Server @@ -627,7 +631,12 @@ func NewTeleport(cfg *Config) (*TeleportProcess, error) { cfg.Clock = clockwork.NewRealClock() } + if cfg.PluginRegistry == nil { + cfg.PluginRegistry = plugin.NewRegistry() + } + process := &TeleportProcess{ + PluginRegistry: cfg.PluginRegistry, Clock: cfg.Clock, Supervisor: supervisor, Config: cfg, @@ -1180,6 +1189,7 @@ func (process *TeleportProcess) initAuthService() error { SessionService: sessionService, Authorizer: authorizer, AuditLog: process.auditLog, + PluginRegistry: process.PluginRegistry, Emitter: checkingEmitter, MetadataGetter: uploadHandler, } @@ -1271,7 +1281,7 @@ func (process *TeleportProcess) initAuthService() error { } // External integrations rely on this event: process.BroadcastEvent(Event{Name: AuthIdentityEvent, Payload: connector}) - process.onExit("auth.broadcast", func(payload interface{}) { + process.OnExit("auth.broadcast", func(payload interface{}) { connector.Close() }) return nil @@ -1354,7 +1364,7 @@ func (process *TeleportProcess) initAuthService() error { } process.RegisterFunc("auth.heartbeat", heartbeat.Run) // execute this when process is asked to exit: - process.onExit("auth.shutdown", func(payload interface{}) { + process.OnExit("auth.shutdown", func(payload interface{}) { // The listeners have to be closed here, because if shutdown // was called before the start of the http server, // the http server would have not started tracking the listeners @@ -1390,10 +1400,10 @@ func payloadContext(payload interface{}, log logrus.FieldLogger) context.Context return context.TODO() } -// onExit allows individual services to register a callback function which will be +// OnExit allows individual services to register a callback function which will be // called when Teleport Process is asked to exit. Usually services terminate themselves // when the callback is called -func (process *TeleportProcess) onExit(serviceName string, callback func(interface{})) { +func (process *TeleportProcess) OnExit(serviceName string, callback func(interface{})) { process.RegisterFunc(serviceName, func() error { eventC := make(chan Event) process.WaitForEvent(context.TODO(), TeleportExitEvent, eventC) @@ -1810,7 +1820,7 @@ func (process *TeleportProcess) initSSH() error { }) // Execute this when process is asked to exit. - process.onExit("ssh.shutdown", func(payload interface{}) { + process.OnExit("ssh.shutdown", func(payload interface{}) { if payload == nil { log.Infof("Shutting down immediately.") if s != nil { @@ -1851,7 +1861,7 @@ func (process *TeleportProcess) registerWithAuthServer(role teleport.Role, event if err != nil { return trace.Wrap(err) } - process.onExit(fmt.Sprintf("auth.client.%v", serviceName), func(interface{}) { + process.OnExit(fmt.Sprintf("auth.client.%v", serviceName), func(interface{}) { process.log.Debugf("Closed client for %v.", role) err := connector.Client.Close() if err != nil { @@ -1923,7 +1933,7 @@ func (process *TeleportProcess) initUploaderService(accessPoint auth.AccessPoint return nil }) - process.onExit("uploader.shutdown", func(payload interface{}) { + process.OnExit("uploader.shutdown", func(payload interface{}) { log.Infof("Shutting down.") warnOnErr(uploader.Stop(), log) log.Infof("Exited.") @@ -1949,7 +1959,7 @@ func (process *TeleportProcess) initUploaderService(accessPoint auth.AccessPoint return nil }) - process.onExit("fileuploader.shutdown", func(payload interface{}) { + process.OnExit("fileuploader.shutdown", func(payload interface{}) { log.Infof("File uploader is shutting down.") warnOnErr(fileUploader.Close(), log) log.Infof("File uploader has shut down.") @@ -2048,7 +2058,7 @@ func (process *TeleportProcess) initDiagnosticService() error { return nil }) - process.onExit("diagnostic.shutdown", func(payload interface{}) { + process.OnExit("diagnostic.shutdown", func(payload interface{}) { if payload == nil { log.Infof("Shutting down immediately.") warnOnErr(server.Close(), log) @@ -2501,20 +2511,21 @@ func (process *TeleportProcess) initProxyEndpoint(conn *Connector) error { } webHandler, err = web.NewHandler( web.Config{ - Proxy: tsrv, - AuthServers: cfg.AuthServers[0], - DomainName: cfg.Hostname, - ProxyClient: conn.Client, - ProxySSHAddr: proxySSHAddr, - ProxyWebAddr: cfg.Proxy.WebAddr, - ProxySettings: proxySettings, - CipherSuites: cfg.CipherSuites, - FIPS: cfg.FIPS, - AccessPoint: accessPoint, - Emitter: streamEmitter, - HostUUID: process.Config.HostUUID, - Context: process.ExitContext(), - StaticFS: fs, + Proxy: tsrv, + AuthServers: cfg.AuthServers[0], + DomainName: cfg.Hostname, + ProxyClient: conn.Client, + ProxySSHAddr: proxySSHAddr, + ProxyWebAddr: cfg.Proxy.WebAddr, + ProxySettings: proxySettings, + CipherSuites: cfg.CipherSuites, + FIPS: cfg.FIPS, + AccessPoint: accessPoint, + Emitter: streamEmitter, + PluginRegistry: process.PluginRegistry, + HostUUID: process.Config.HostUUID, + Context: process.ExitContext(), + StaticFS: fs, }) if err != nil { return trace.Wrap(err) @@ -2756,7 +2767,7 @@ func (process *TeleportProcess) initProxyEndpoint(conn *Connector) error { } // execute this when process is asked to exit: - process.onExit("proxy.shutdown", func(payload interface{}) { + process.OnExit("proxy.shutdown", func(payload interface{}) { rcWatcher.Close() defer listeners.Close() // Need to shut down this listener first, because @@ -3045,7 +3056,7 @@ func (process *TeleportProcess) initApps() { }) // Execute this when process is asked to exit. - process.onExit("apps.stop", func(payload interface{}) { + process.OnExit("apps.stop", func(payload interface{}) { log.Infof("Shutting down.") if appServer != nil { warnOnErr(appServer.Close(), log) @@ -3260,7 +3271,7 @@ func (process *TeleportProcess) initDebugApp() { process.BroadcastEvent(Event{Name: DebugAppReady, Payload: server}) return nil }) - process.onExit("debug.app.shutdown", func(payload interface{}) { + process.OnExit("debug.app.shutdown", func(payload interface{}) { if server != nil { server.Close() } diff --git a/lib/services/types.go b/lib/services/types.go index fd6bbbb7979cb..37a36c02bdd6c 100644 --- a/lib/services/types.go +++ b/lib/services/types.go @@ -484,6 +484,7 @@ const ( KindClusterAuthPreference = types.KindClusterAuthPreference MetaNameClusterAuthPreference = types.MetaNameClusterAuthPreference KindClusterConfig = types.KindClusterConfig + KindBilling = types.KindBilling KindSemaphore = types.KindSemaphore MetaNameClusterConfig = types.MetaNameClusterConfig KindClusterName = types.KindClusterName diff --git a/lib/web/apiserver.go b/lib/web/apiserver.go index 079a56389053b..6376d45906df4 100644 --- a/lib/web/apiserver.go +++ b/lib/web/apiserver.go @@ -46,6 +46,7 @@ import ( "github.com/gravitational/teleport/lib/httplib" "github.com/gravitational/teleport/lib/httplib/csrf" "github.com/gravitational/teleport/lib/jwt" + "github.com/gravitational/teleport/lib/plugin" "github.com/gravitational/teleport/lib/reversetunnel" "github.com/gravitational/teleport/lib/secret" "github.com/gravitational/teleport/lib/services" @@ -104,6 +105,8 @@ func SetClock(clock clockwork.Clock) HandlerOption { // Config represents web handler configuration parameters type Config struct { + // PluginRegistry handles plugin registration + PluginRegistry plugin.Registry // Proxy is a reverse tunnel proxy that handles connections // to local cluster or remote clusters using unified interface Proxy reversetunnel.Tunnel @@ -423,9 +426,11 @@ func NewHandler(cfg Config, opts ...HandlerOption) (*RewritingHandler, error) { }) h.NotFound = routingHandler - plugin := GetPlugin() - if plugin != nil { - plugin.AddHandlers(h) + + if cfg.PluginRegistry != nil { + if err := cfg.PluginRegistry.RegisterProxyWebHandlers(h); err != nil { + return nil, trace.Wrap(err) + } } // Create application specific handler. This handler handles sessions and diff --git a/lib/web/plugin.go b/lib/web/plugin.go deleted file mode 100644 index 7b768ac8e9621..0000000000000 --- a/lib/web/plugin.go +++ /dev/null @@ -1,45 +0,0 @@ -/* -Copyright 2017 Gravitational, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package web - -import ( - "sync" -) - -var pluginMutex = &sync.Mutex{} -var plugin Plugin - -// GetPlugin returns web API plugin that -func GetPlugin() Plugin { - pluginMutex.Lock() - defer pluginMutex.Unlock() - return plugin -} - -// SetPlugin sets plugin for the web handler -func SetPlugin(p Plugin) { - pluginMutex.Lock() - defer pluginMutex.Unlock() - plugin = p -} - -// Plugin is API Server extension setter -// if set, it will add handler methods during web handler initialization -type Plugin interface { - // AddHandlers adds handlers to the web API handler - AddHandlers(h *Handler) -} diff --git a/lib/web/sessions.go b/lib/web/sessions.go index 1638298594d10..5676bc9f52294 100644 --- a/lib/web/sessions.go +++ b/lib/web/sessions.go @@ -47,6 +47,7 @@ import ( "github.com/jonboulle/clockwork" "github.com/sirupsen/logrus" + "google.golang.org/grpc" ) // SessionContext is a context associated with a user's @@ -56,7 +57,7 @@ import ( type SessionContext struct { log logrus.FieldLogger user string - clt auth.ClientI + clt *auth.Client parent *sessionCache // resources is persistent resource store this context is bound to. // The store maintains a list of resources between session renewals @@ -121,6 +122,11 @@ func (c *SessionContext) GetClient() (auth.ClientI, error) { return c.clt, nil } +// GetClientConnection returns a connection to Auth Service +func (c *SessionContext) GetClientConnection() *grpc.ClientConn { + return c.clt.GetConnection() +} + // GetUserClient will return an auth.ClientI with the role of the user at // the requested site. If the site is local a client with the users local role // is returned. If the site is remote a client with the users remote role is @@ -737,6 +743,7 @@ func (s *sessionCache) newSessionContextFromSession(session services.WebSession) if err != nil { return nil, trace.Wrap(err) } + ctx := &SessionContext{ clt: userClient, remoteClt: make(map[string]auth.ClientI), @@ -757,6 +764,7 @@ func (s *sessionCache) newSessionContextFromSession(session services.WebSession) // close our extra context and return ctx.Close() } + return ctx, nil } diff --git a/lib/web/ui/usercontext.go b/lib/web/ui/usercontext.go index 1c9d7d339ef01..431823d291ac4 100644 --- a/lib/web/ui/usercontext.go +++ b/lib/web/ui/usercontext.go @@ -56,12 +56,14 @@ type userACL struct { Tokens access `json:"tokens"` // Nodes defines access to nodes. Nodes access `json:"nodes"` - // AppServers defines access to application servers. + // AppServers defines access to application servers AppServers access `json:"appServers"` // SSH defines access to servers SSHLogins []string `json:"sshLogins"` - // AccessRequests defines access to access requests. + // AccessRequests defines access to access requests AccessRequests access `json:"accessRequests"` + // Billing defines access to billing information + Billing access `json:"billing"` } type authType string @@ -71,7 +73,7 @@ const ( authSSO authType = "sso" ) -// UserContext describes a users settings to various resources. +// UserContext describes user settings and access to various resources. type UserContext struct { // AuthType is auth method of this user. AuthType authType `json:"authType"` @@ -168,6 +170,7 @@ func NewUserContext(user services.User, userRoles services.RoleSet) (*UserContex nodeAccess := newAccess(userRoles, ctx, services.KindNode) appServerAccess := newAccess(userRoles, ctx, services.KindAppServer) requestAccess := newAccess(userRoles, ctx, services.KindAccessRequest) + billingAccess := newAccess(userRoles, ctx, services.KindBilling) logins := getLogins(userRoles) accessStrategy := getAccessStrategy(userRoles) @@ -184,6 +187,7 @@ func NewUserContext(user services.User, userRoles services.RoleSet) (*UserContex Users: userAccess, Tokens: tokenAccess, Nodes: nodeAccess, + Billing: billingAccess, } // local user