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

     1  /*
     2  Copyright 2020 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 types
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"time"
    23  
    24  	"github.com/gravitational/trace"
    25  )
    26  
    27  // WebSessionsGetter provides access to web sessions
    28  type WebSessionsGetter interface {
    29  	// WebSessions returns the web session manager
    30  	WebSessions() WebSessionInterface
    31  }
    32  
    33  // WebSessionInterface defines interface to regular web sessions
    34  type WebSessionInterface interface {
    35  	// Get returns a web session state for the given request.
    36  	Get(ctx context.Context, req GetWebSessionRequest) (WebSession, error)
    37  
    38  	// List gets all regular web sessions.
    39  	List(context.Context) ([]WebSession, error)
    40  
    41  	// Upsert updates existing or inserts a new web session.
    42  	Upsert(ctx context.Context, session WebSession) error
    43  
    44  	// Delete deletes the web session described by req.
    45  	Delete(ctx context.Context, req DeleteWebSessionRequest) error
    46  
    47  	// DeleteAll removes all web sessions.
    48  	DeleteAll(context.Context) error
    49  }
    50  
    51  // WebSession stores key and value used to authenticate with SSH
    52  // notes on behalf of user
    53  type WebSession interface {
    54  	// Resource represents common properties for all resources.
    55  	Resource
    56  	// GetShortName returns visible short name used in logging
    57  	GetShortName() string
    58  	// GetUser returns the user this session is associated with
    59  	GetUser() string
    60  	// SetUser sets user associated with this session
    61  	SetUser(string)
    62  	// GetPub is returns public certificate signed by auth server
    63  	GetPub() []byte
    64  	// GetPriv returns private OpenSSH key used to auth with SSH nodes
    65  	GetPriv() []byte
    66  	// SetPriv sets private key
    67  	SetPriv([]byte)
    68  	// GetTLSCert returns PEM encoded TLS certificate associated with session
    69  	GetTLSCert() []byte
    70  	// GetBearerToken is a special bearer token used for additional
    71  	// bearer authentication
    72  	GetBearerToken() string
    73  	// SetExpiryTime sets session expiry time
    74  	SetExpiryTime(time.Time)
    75  	// GetBearerTokenExpiryTime - absolute time when token expires
    76  	GetBearerTokenExpiryTime() time.Time
    77  	// GetExpiryTime - absolute time when web session expires
    78  	GetExpiryTime() time.Time
    79  	// GetLoginTime returns the time this user recently logged in.
    80  	GetLoginTime() time.Time
    81  	// SetLoginTime sets when this user logged in.
    82  	SetLoginTime(time.Time)
    83  	// GetIdleTimeout returns the max time a user can be inactive for this session.
    84  	GetIdleTimeout() time.Duration
    85  	// WithoutSecrets returns copy of the web session but without private keys
    86  	WithoutSecrets() WebSession
    87  	// String returns string representation of the session.
    88  	String() string
    89  	// SetConsumedAccessRequestID sets the ID of the access request from which additional roles to assume were obtained.
    90  	SetConsumedAccessRequestID(string)
    91  	// GetConsumedAccessRequestID returns the ID of the access request from which additional roles to assume were obtained.
    92  	GetConsumedAccessRequestID() string
    93  	// SetSAMLSession sets the SAML session data. Is considered secret.
    94  	SetSAMLSession(*SAMLSessionData)
    95  	// GetSAMLSession gets the SAML session data. Is considered secret.
    96  	GetSAMLSession() *SAMLSessionData
    97  	// SetDeviceWebToken sets the session's DeviceWebToken.
    98  	// The token is considered a secret.
    99  	SetDeviceWebToken(*DeviceWebToken)
   100  	// GetDeviceWebToken returns the session's DeviceWebToken, if any.
   101  	// The token is considered a secret.
   102  	GetDeviceWebToken() *DeviceWebToken
   103  	// GetHasDeviceExtensions returns the HasDeviceExtensions value.
   104  	// If true the session's TLS and SSH certificates are augmented with device
   105  	// extensions.
   106  	GetHasDeviceExtensions() bool
   107  }
   108  
   109  // NewWebSession returns new instance of the web session based on the V2 spec
   110  func NewWebSession(name string, subkind string, spec WebSessionSpecV2) (WebSession, error) {
   111  	ws := &WebSessionV2{
   112  		SubKind: subkind,
   113  		Metadata: Metadata{
   114  			Name:    name,
   115  			Expires: &spec.Expires,
   116  		},
   117  		Spec: spec,
   118  	}
   119  	if err := ws.CheckAndSetDefaults(); err != nil {
   120  		return nil, trace.Wrap(err)
   121  	}
   122  	return ws, nil
   123  }
   124  
   125  // GetKind gets resource Kind
   126  func (ws *WebSessionV2) GetKind() string {
   127  	return ws.Kind
   128  }
   129  
   130  // GetSubKind gets resource SubKind
   131  func (ws *WebSessionV2) GetSubKind() string {
   132  	return ws.SubKind
   133  }
   134  
   135  // SetSubKind sets resource SubKind
   136  func (ws *WebSessionV2) SetSubKind(subKind string) {
   137  	ws.SubKind = subKind
   138  }
   139  
   140  // GetVersion gets resource Version
   141  func (ws *WebSessionV2) GetVersion() string {
   142  	return ws.Version
   143  }
   144  
   145  // GetName gets resource Name
   146  func (ws *WebSessionV2) GetName() string {
   147  	return ws.Metadata.Name
   148  }
   149  
   150  // SetName sets resource Name
   151  func (ws *WebSessionV2) SetName(name string) {
   152  	ws.Metadata.Name = name
   153  }
   154  
   155  // Expiry returns resource Expiry
   156  func (ws *WebSessionV2) Expiry() time.Time {
   157  	return ws.Metadata.Expiry()
   158  }
   159  
   160  // SetExpiry Sets resource Expiry
   161  func (ws *WebSessionV2) SetExpiry(expiry time.Time) {
   162  	ws.Metadata.SetExpiry(expiry)
   163  }
   164  
   165  // GetMetadata gets resource Metadata
   166  func (ws *WebSessionV2) GetMetadata() Metadata {
   167  	return ws.Metadata
   168  }
   169  
   170  // GetResourceID gets ResourceID
   171  func (ws *WebSessionV2) GetResourceID() int64 {
   172  	return ws.Metadata.GetID()
   173  }
   174  
   175  // SetResourceID sets ResourceID
   176  func (ws *WebSessionV2) SetResourceID(id int64) {
   177  	ws.Metadata.SetID(id)
   178  }
   179  
   180  // GetRevision returns the revision
   181  func (ws *WebSessionV2) GetRevision() string {
   182  	return ws.Metadata.GetRevision()
   183  }
   184  
   185  // SetRevision sets the revision
   186  func (ws *WebSessionV2) SetRevision(rev string) {
   187  	ws.Metadata.SetRevision(rev)
   188  }
   189  
   190  // GetIdleTimeout returns the max idle timeout duration.
   191  func (ws *WebSessionV2) GetIdleTimeout() time.Duration {
   192  	return ws.Spec.IdleTimeout.Duration()
   193  }
   194  
   195  // WithoutSecrets returns a copy of the WebSession without secrets.
   196  func (ws *WebSessionV2) WithoutSecrets() WebSession {
   197  	cp := *ws
   198  	cp.Spec.Priv = nil
   199  	cp.Spec.SAMLSession = nil
   200  	cp.Spec.DeviceWebToken = nil
   201  	return &cp
   202  }
   203  
   204  // SetConsumedAccessRequestID sets the ID of the access request from which additional roles to assume were obtained.
   205  func (ws *WebSessionV2) SetConsumedAccessRequestID(requestID string) {
   206  	ws.Spec.ConsumedAccessRequestID = requestID
   207  }
   208  
   209  // GetConsumedAccessRequestID returns the ID of the access request from which additional roles to assume were obtained.
   210  func (ws *WebSessionV2) GetConsumedAccessRequestID() string {
   211  	return ws.Spec.ConsumedAccessRequestID
   212  }
   213  
   214  // SetSAMLSession sets the SAML session data. Is considered secret.
   215  func (ws *WebSessionV2) SetSAMLSession(samlSession *SAMLSessionData) {
   216  	ws.Spec.SAMLSession = samlSession
   217  }
   218  
   219  // GetSAMLSession gets the SAML session data. Is considered secret.
   220  func (ws *WebSessionV2) GetSAMLSession() *SAMLSessionData {
   221  	return ws.Spec.SAMLSession
   222  }
   223  
   224  // SetDeviceWebToken sets the session's DeviceWebToken.
   225  // The token is considered a secret.
   226  func (ws *WebSessionV2) SetDeviceWebToken(webToken *DeviceWebToken) {
   227  	ws.Spec.DeviceWebToken = webToken
   228  }
   229  
   230  // GetDeviceWebToken returns the session's DeviceWebToken, if any.
   231  // The token is considered a secret.
   232  func (ws *WebSessionV2) GetDeviceWebToken() *DeviceWebToken {
   233  	return ws.Spec.DeviceWebToken
   234  }
   235  
   236  // GetHasDeviceExtensions returns the HasDeviceExtensions value.
   237  // If true the session's TLS and SSH certificates are augmented with device
   238  // extensions.
   239  func (ws *WebSessionV2) GetHasDeviceExtensions() bool {
   240  	return ws.Spec.HasDeviceExtensions
   241  }
   242  
   243  // setStaticFields sets static resource header and metadata fields.
   244  func (ws *WebSessionV2) setStaticFields() {
   245  	ws.Version = V2
   246  	ws.Kind = KindWebSession
   247  }
   248  
   249  // CheckAndSetDefaults checks and set default values for any missing fields.
   250  func (ws *WebSessionV2) CheckAndSetDefaults() error {
   251  	ws.setStaticFields()
   252  	if err := ws.Metadata.CheckAndSetDefaults(); err != nil {
   253  		return trace.Wrap(err)
   254  	}
   255  	if ws.Spec.User == "" {
   256  		return trace.BadParameter("missing User")
   257  	}
   258  	return nil
   259  }
   260  
   261  // String returns string representation of the session.
   262  func (ws *WebSessionV2) String() string {
   263  	return fmt.Sprintf("WebSession(kind=%v/%v,user=%v,id=%v,expires=%v)",
   264  		ws.GetKind(), ws.GetSubKind(), ws.GetUser(), ws.GetName(), ws.GetExpiryTime())
   265  }
   266  
   267  // SetUser sets user associated with this session
   268  func (ws *WebSessionV2) SetUser(u string) {
   269  	ws.Spec.User = u
   270  }
   271  
   272  // GetUser returns the user this session is associated with
   273  func (ws *WebSessionV2) GetUser() string {
   274  	return ws.Spec.User
   275  }
   276  
   277  // GetShortName returns visible short name used in logging
   278  func (ws *WebSessionV2) GetShortName() string {
   279  	if len(ws.Metadata.Name) < 4 {
   280  		return "<undefined>"
   281  	}
   282  	return ws.Metadata.Name[:4]
   283  }
   284  
   285  // GetTLSCert returns PEM encoded TLS certificate associated with session
   286  func (ws *WebSessionV2) GetTLSCert() []byte {
   287  	return ws.Spec.TLSCert
   288  }
   289  
   290  // GetPub is returns public certificate signed by auth server
   291  func (ws *WebSessionV2) GetPub() []byte {
   292  	return ws.Spec.Pub
   293  }
   294  
   295  // GetPriv returns private OpenSSH key used to auth with SSH nodes
   296  func (ws *WebSessionV2) GetPriv() []byte {
   297  	return ws.Spec.Priv
   298  }
   299  
   300  // SetPriv sets private key
   301  func (ws *WebSessionV2) SetPriv(priv []byte) {
   302  	ws.Spec.Priv = priv
   303  }
   304  
   305  // GetBearerToken gets a special bearer token used for additional
   306  // bearer authentication
   307  func (ws *WebSessionV2) GetBearerToken() string {
   308  	return ws.Spec.BearerToken
   309  }
   310  
   311  // SetExpiryTime sets session expiry time
   312  func (ws *WebSessionV2) SetExpiryTime(tm time.Time) {
   313  	ws.Spec.Expires = tm
   314  }
   315  
   316  // GetBearerTokenExpiryTime - absolute time when token expires
   317  func (ws *WebSessionV2) GetBearerTokenExpiryTime() time.Time {
   318  	return ws.Spec.BearerTokenExpires
   319  }
   320  
   321  // GetExpiryTime - absolute time when web session expires
   322  func (ws *WebSessionV2) GetExpiryTime() time.Time {
   323  	return ws.Spec.Expires
   324  }
   325  
   326  // GetLoginTime returns the time this user recently logged in.
   327  func (ws *WebSessionV2) GetLoginTime() time.Time {
   328  	return ws.Spec.LoginTime
   329  }
   330  
   331  // SetLoginTime sets when this user logged in.
   332  func (ws *WebSessionV2) SetLoginTime(loginTime time.Time) {
   333  	ws.Spec.LoginTime = loginTime
   334  }
   335  
   336  // GetAppSessionRequest contains the parameters to request an application
   337  // web session.
   338  type GetAppSessionRequest struct {
   339  	// SessionID is the session ID of the application session itself.
   340  	SessionID string
   341  }
   342  
   343  // Check validates the request.
   344  func (r *GetAppSessionRequest) Check() error {
   345  	if r.SessionID == "" {
   346  		return trace.BadParameter("session ID missing")
   347  	}
   348  	return nil
   349  }
   350  
   351  // GetSnowflakeSessionRequest contains the parameters to request a Snowflake
   352  // web session.
   353  type GetSnowflakeSessionRequest struct {
   354  	// SessionID is the session ID of the Snowflake session itself.
   355  	SessionID string
   356  }
   357  
   358  // Check validates the request.
   359  func (r *GetSnowflakeSessionRequest) Check() error {
   360  	if r.SessionID == "" {
   361  		return trace.BadParameter("session ID missing")
   362  	}
   363  	return nil
   364  }
   365  
   366  // GetSAMLIdPSessionRequest contains the parameters to request a SAML IdP
   367  // session.
   368  type GetSAMLIdPSessionRequest struct {
   369  	// SessionID is the session ID of the SAML IdP session.
   370  	SessionID string
   371  }
   372  
   373  // Check validates the request.
   374  func (r *GetSAMLIdPSessionRequest) Check() error {
   375  	if r.SessionID == "" {
   376  		return trace.BadParameter("session ID missing")
   377  	}
   378  	return nil
   379  }
   380  
   381  // CreateSnowflakeSessionRequest contains the parameters needed to request
   382  // creating a Snowflake web session.
   383  type CreateSnowflakeSessionRequest struct {
   384  	// Username is the identity of the user requesting the session.
   385  	Username string
   386  	// SessionToken is the Snowflake server session token.
   387  	SessionToken string
   388  	// TokenTTL is the token validity period.
   389  	TokenTTL time.Duration
   390  }
   391  
   392  // CreateSAMLIdPSessionRequest contains the parameters needed to request
   393  // creating a SAML IdP session.
   394  type CreateSAMLIdPSessionRequest struct {
   395  	// SessionID is the identifier for the session.
   396  	SessionID string
   397  	// Username is the identity of the user requesting the session.
   398  	Username string `json:"username"`
   399  	// SAMLSession is the session data associated with the SAML IdP session.
   400  	SAMLSession *SAMLSessionData `json:"saml_session"`
   401  }
   402  
   403  // Check validates the request.
   404  func (r CreateSAMLIdPSessionRequest) Check() error {
   405  	if r.Username == "" {
   406  		return trace.BadParameter("username missing")
   407  	}
   408  	if r.SAMLSession == nil {
   409  		return trace.BadParameter("saml session missing")
   410  	}
   411  
   412  	return nil
   413  }
   414  
   415  // DeleteAppSessionRequest are the parameters used to request removal of
   416  // an application web session.
   417  type DeleteAppSessionRequest struct {
   418  	SessionID string `json:"session_id"`
   419  }
   420  
   421  // DeleteSnowflakeSessionRequest are the parameters used to request removal of
   422  // a Snowflake web session.
   423  type DeleteSnowflakeSessionRequest struct {
   424  	SessionID string `json:"session_id"`
   425  }
   426  
   427  // DeleteSAMLIdPSessionRequest are the parameters used to request removal of
   428  // a SAML IdP session.
   429  type DeleteSAMLIdPSessionRequest struct {
   430  	SessionID string `json:"session_id"`
   431  }
   432  
   433  // NewWebToken returns a new web token with the given expiration and spec
   434  func NewWebToken(expires time.Time, spec WebTokenSpecV3) (WebToken, error) {
   435  	r := &WebTokenV3{
   436  		Metadata: Metadata{
   437  			Name:    spec.Token,
   438  			Expires: &expires,
   439  		},
   440  		Spec: spec,
   441  	}
   442  	if err := r.CheckAndSetDefaults(); err != nil {
   443  		return nil, trace.Wrap(err)
   444  	}
   445  	return r, nil
   446  }
   447  
   448  // WebTokensGetter provides access to web tokens
   449  type WebTokensGetter interface {
   450  	// WebTokens returns the tokens manager
   451  	WebTokens() WebTokenInterface
   452  }
   453  
   454  // WebTokenInterface defines interface for managing web tokens
   455  type WebTokenInterface interface {
   456  	// Get returns a token specified by the request.
   457  	Get(ctx context.Context, req GetWebTokenRequest) (WebToken, error)
   458  
   459  	// List gets all web tokens.
   460  	List(context.Context) ([]WebToken, error)
   461  
   462  	// Upsert updates existing or inserts a new web token.
   463  	Upsert(ctx context.Context, token WebToken) error
   464  
   465  	// Delete deletes the web token described by req.
   466  	Delete(ctx context.Context, req DeleteWebTokenRequest) error
   467  
   468  	// DeleteAll removes all web tokens.
   469  	DeleteAll(context.Context) error
   470  }
   471  
   472  // WebToken is a time-limited unique token bound to a user's session
   473  type WebToken interface {
   474  	// Resource represents common properties for all resources.
   475  	Resource
   476  
   477  	// GetToken returns the token value
   478  	GetToken() string
   479  	// SetToken sets the token value
   480  	SetToken(token string)
   481  	// GetUser returns the user the token is bound to
   482  	GetUser() string
   483  	// SetUser sets the user the token is bound to
   484  	SetUser(user string)
   485  	// String returns the text representation of this token
   486  	String() string
   487  }
   488  
   489  var _ WebToken = &WebTokenV3{}
   490  
   491  // GetMetadata returns the token metadata
   492  func (r *WebTokenV3) GetMetadata() Metadata {
   493  	return r.Metadata
   494  }
   495  
   496  // GetKind returns the token resource kind
   497  func (r *WebTokenV3) GetKind() string {
   498  	return r.Kind
   499  }
   500  
   501  // GetSubKind returns the token resource subkind
   502  func (r *WebTokenV3) GetSubKind() string {
   503  	return r.SubKind
   504  }
   505  
   506  // SetSubKind sets the token resource subkind
   507  func (r *WebTokenV3) SetSubKind(subKind string) {
   508  	r.SubKind = subKind
   509  }
   510  
   511  // GetVersion returns the token resource version
   512  func (r *WebTokenV3) GetVersion() string {
   513  	return r.Version
   514  }
   515  
   516  // GetName returns the token value
   517  func (r *WebTokenV3) GetName() string {
   518  	return r.Metadata.Name
   519  }
   520  
   521  // SetName sets the token value
   522  func (r *WebTokenV3) SetName(name string) {
   523  	r.Metadata.Name = name
   524  }
   525  
   526  // GetResourceID returns the token resource ID
   527  func (r *WebTokenV3) GetResourceID() int64 {
   528  	return r.Metadata.GetID()
   529  }
   530  
   531  // SetResourceID sets the token resource ID
   532  func (r *WebTokenV3) SetResourceID(id int64) {
   533  	r.Metadata.SetID(id)
   534  }
   535  
   536  // GetRevision returns the revision
   537  func (r *WebTokenV3) GetRevision() string {
   538  	return r.Metadata.GetRevision()
   539  }
   540  
   541  // SetRevision sets the revision
   542  func (r *WebTokenV3) SetRevision(rev string) {
   543  	r.Metadata.SetRevision(rev)
   544  }
   545  
   546  // GetToken returns the token value
   547  func (r *WebTokenV3) GetToken() string {
   548  	return r.Spec.Token
   549  }
   550  
   551  // SetToken sets the token value
   552  func (r *WebTokenV3) SetToken(token string) {
   553  	r.Spec.Token = token
   554  }
   555  
   556  // GetUser returns the user this token is bound to
   557  func (r *WebTokenV3) GetUser() string {
   558  	return r.Spec.User
   559  }
   560  
   561  // SetUser sets the user this token is bound to
   562  func (r *WebTokenV3) SetUser(user string) {
   563  	r.Spec.User = user
   564  }
   565  
   566  // Expiry returns the token absolute expiration time
   567  func (r *WebTokenV3) Expiry() time.Time {
   568  	if r.Metadata.Expires == nil {
   569  		return time.Time{}
   570  	}
   571  	return *r.Metadata.Expires
   572  }
   573  
   574  // SetExpiry sets the token absolute expiration time
   575  func (r *WebTokenV3) SetExpiry(t time.Time) {
   576  	r.Metadata.Expires = &t
   577  }
   578  
   579  // setStaticFields sets static resource header and metadata fields.
   580  func (r *WebTokenV3) setStaticFields() {
   581  	r.Kind = KindWebToken
   582  	r.Version = V3
   583  }
   584  
   585  // CheckAndSetDefaults validates this token value and sets defaults
   586  func (r *WebTokenV3) CheckAndSetDefaults() error {
   587  	r.setStaticFields()
   588  	if err := r.Metadata.CheckAndSetDefaults(); err != nil {
   589  		return trace.Wrap(err)
   590  	}
   591  
   592  	if r.Spec.User == "" {
   593  		return trace.BadParameter("User required")
   594  	}
   595  	if r.Spec.Token == "" {
   596  		return trace.BadParameter("Token required")
   597  	}
   598  	return nil
   599  }
   600  
   601  // String returns string representation of the token.
   602  func (r *WebTokenV3) String() string {
   603  	return fmt.Sprintf("WebToken(kind=%v,user=%v,token=%v,expires=%v)",
   604  		r.GetKind(), r.GetUser(), r.GetToken(), r.Expiry())
   605  }
   606  
   607  // Check validates the request.
   608  func (r *GetWebSessionRequest) Check() error {
   609  	if r.User == "" {
   610  		return trace.BadParameter("user name missing")
   611  	}
   612  	if r.SessionID == "" {
   613  		return trace.BadParameter("session ID missing")
   614  	}
   615  	return nil
   616  }
   617  
   618  // Check validates the request.
   619  func (r *DeleteWebSessionRequest) Check() error {
   620  	if r.SessionID == "" {
   621  		return trace.BadParameter("session ID missing")
   622  	}
   623  	return nil
   624  }
   625  
   626  // Check validates the request.
   627  func (r *GetWebTokenRequest) Check() error {
   628  	if r.User == "" {
   629  		return trace.BadParameter("user name missing")
   630  	}
   631  	if r.Token == "" {
   632  		return trace.BadParameter("token missing")
   633  	}
   634  	return nil
   635  }
   636  
   637  // Check validates the request.
   638  func (r *DeleteWebTokenRequest) Check() error {
   639  	if r.Token == "" {
   640  		return trace.BadParameter("token missing")
   641  	}
   642  	return nil
   643  }
   644  
   645  // IntoMap makes this filter into a map.
   646  //
   647  // This filter is used with the cache watcher to make sure only sessions
   648  // for a particular user are returned.
   649  func (f *WebSessionFilter) IntoMap() map[string]string {
   650  	m := make(map[string]string)
   651  	if f.User != "" {
   652  		m[keyUser] = f.User
   653  	}
   654  	return m
   655  }
   656  
   657  // FromMap converts provided map into this filter.
   658  //
   659  // This filter is used with the cache watcher to make sure only sessions
   660  // for a particular user are returned.
   661  func (f *WebSessionFilter) FromMap(m map[string]string) error {
   662  	for key, val := range m {
   663  		switch key {
   664  		case keyUser:
   665  			f.User = val
   666  		default:
   667  			return trace.BadParameter("unknown filter key %s", key)
   668  		}
   669  	}
   670  	return nil
   671  }
   672  
   673  // Match checks if a given web session matches this filter.
   674  func (f *WebSessionFilter) Match(session WebSession) bool {
   675  	if f.User != "" && session.GetUser() != f.User {
   676  		return false
   677  	}
   678  	return true
   679  }