From bd07d7be20b7b4d46c770f1b59693052a79e7fc7 Mon Sep 17 00:00:00 2001 From: Brian Joerger Date: Fri, 18 Jun 2021 12:57:29 -0700 Subject: [PATCH] CheckAndSetDefaults sets all defaults. (#6846) --- api/types/access_request.go | 59 +++--- api/types/authentication.go | 50 +++-- api/types/authority.go | 42 ++-- api/types/clusterconfig.go | 35 ++-- api/types/clustername.go | 30 ++- api/types/databaseserver.go | 31 +-- api/types/github.go | 27 +-- api/types/license.go | 27 ++- api/types/namespace.go | 31 ++- api/types/networking.go | 28 ++- api/types/oidc.go | 50 ++--- api/types/plugin_data.go | 16 +- api/types/presence.go | 6 +- api/types/provisioning.go | 23 +-- api/types/remotecluster.go | 25 +-- api/types/resetpasswordtoken.go | 25 +-- api/types/resetpasswordtokensecrets.go | 19 +- api/types/role.go | 24 ++- api/types/saml.go | 25 ++- api/types/semaphore.go | 21 +- api/types/server.go | 36 +++- api/types/session.go | 55 +++--- api/types/sessionrecording.go | 23 +-- api/types/statictokens.go | 36 ++-- api/types/trustedcluster.go | 26 +-- api/types/tunnel.go | 52 ++--- api/types/tunnelconn.go | 48 ++--- api/types/user.go | 47 ++--- e | 2 +- integration/app_integration_test.go | 4 +- integration/db_integration_test.go | 4 +- integration/helpers.go | 40 ++-- integration/integration_test.go | 150 +++++++-------- integration/kube_integration_test.go | 16 +- integration/port_forwarding_test.go | 2 +- lib/auth/auth.go | 12 +- lib/auth/auth_test.go | 15 +- lib/auth/grpcserver_test.go | 4 +- lib/auth/helpers.go | 2 +- lib/auth/init.go | 2 +- lib/auth/init_test.go | 10 +- lib/auth/oidc_test.go | 3 +- lib/auth/resetpasswordtoken.go | 6 +- lib/auth/saml_test.go | 16 +- lib/auth/sessions.go | 5 +- lib/auth/trustedcluster.go | 5 +- lib/auth/trustedcluster_test.go | 2 +- lib/cache/cache_test.go | 15 +- lib/config/configuration.go | 16 +- lib/config/fileconf.go | 12 +- lib/kube/proxy/server_test.go | 3 +- lib/reversetunnel/rc_manager_test.go | 56 +++--- lib/reversetunnel/srv_test.go | 37 ++-- lib/service/cfg.go | 4 +- lib/service/db.go | 8 +- lib/services/access_request.go | 7 +- lib/services/authentication.go | 3 + lib/services/authority.go | 9 +- lib/services/authority_test.go | 14 +- lib/services/clusterconfig.go | 22 +-- lib/services/clustername.go | 7 +- lib/services/databaseserver.go | 4 +- lib/services/github.go | 7 +- lib/services/github_test.go | 7 +- lib/services/license.go | 7 +- lib/services/local/configuration.go | 2 +- lib/services/local/presence_test.go | 3 +- lib/services/local/resource.go | 3 - lib/services/local/users.go | 3 - lib/services/namespace.go | 4 + lib/services/networking.go | 3 - lib/services/oidc.go | 7 +- lib/services/oidc_test.go | 6 +- lib/services/plugin_data.go | 7 +- lib/services/provisioning.go | 7 +- lib/services/remotecluster.go | 7 +- lib/services/resetpasswordtoken.go | 3 + lib/services/resetpasswordtokensecrets.go | 3 + lib/services/resource.go | 4 + lib/services/role.go | 221 +++++++++------------- lib/services/role_test.go | 74 ++++++-- lib/services/saml.go | 7 +- lib/services/semaphore.go | 8 +- lib/services/server.go | 4 +- lib/services/session.go | 7 +- lib/services/statictokens.go | 24 +-- lib/services/suite/suite.go | 10 +- lib/services/trustedcluster.go | 12 +- lib/services/tunnel.go | 7 +- lib/services/tunnelconn.go | 7 +- lib/services/user.go | 7 +- lib/srv/db/access_test.go | 18 +- lib/srv/db/ha_test.go | 6 +- lib/srv/regular/sshserver_test.go | 5 +- lib/web/apiserver.go | 5 +- lib/web/apiserver_test.go | 11 +- lib/web/resources_test.go | 6 +- lib/web/sessions.go | 9 +- tool/tctl/common/auth_command_test.go | 3 +- tool/tsh/tsh_test.go | 4 +- 100 files changed, 1037 insertions(+), 935 deletions(-) diff --git a/api/types/access_request.go b/api/types/access_request.go index 22df49ad6f2..0e099d72de7 100644 --- a/api/types/access_request.go +++ b/api/types/access_request.go @@ -95,15 +95,12 @@ type AccessRequest interface { // NewAccessRequest assembled an AccessRequest resource. func NewAccessRequest(name string, user string, roles ...string) (AccessRequest, error) { req := AccessRequestV3{ - Kind: KindAccessRequest, - Version: V3, Metadata: Metadata{ Name: name, }, Spec: AccessRequestSpecV3{ User: user, Roles: roles, - State: RequestState_PENDING, }, } if err := req.CheckAndSetDefaults(); err != nil { @@ -262,47 +259,23 @@ func (r *AccessRequestV3) SetSuggestedReviewers(reviewers []string) { r.Spec.SuggestedReviewers = reviewers } +// setStaticFields sets static resource header and metadata fields. +func (r *AccessRequestV3) setStaticFields() { + r.Kind = KindAccessRequest + r.Version = V3 +} + // CheckAndSetDefaults validates set values and sets default values func (r *AccessRequestV3) CheckAndSetDefaults() error { + r.setStaticFields() if err := r.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if r.Version == "" { - r.Version = V3 - } - if r.GetState().IsNone() { - if err := r.SetState(RequestState_PENDING); err != nil { - return trace.Wrap(err) - } + + if r.Spec.State.IsNone() { + r.Spec.State = RequestState_PENDING } - // dedupe and sort roles to simplify comparing role lists - r.Spec.Roles = utils.Deduplicate(r.Spec.Roles) - sort.Strings(r.Spec.Roles) - - if err := r.Check(); err != nil { - return trace.Wrap(err) - } - return nil -} - -// Check validates AccessRequest values -func (r *AccessRequestV3) Check() error { - if r.Kind == "" { - return trace.BadParameter("access request kind not set") - } - if r.Version == "" { - return trace.BadParameter("access request version not set") - } - if r.GetName() == "" { - return trace.BadParameter("access request id not set") - } - if r.GetUser() == "" { - return trace.BadParameter("access request user name not set") - } - if len(r.GetRoles()) < 1 { - return trace.BadParameter("access request does not specify any roles") - } if r.GetState().IsPending() { if r.GetResolveReason() != "" { return trace.BadParameter("pending requests cannot include resolve reason") @@ -311,6 +284,18 @@ func (r *AccessRequestV3) Check() error { return trace.BadParameter("pending requests cannot include resolve annotations") } } + + if r.GetUser() == "" { + return trace.BadParameter("access request user name not set") + } + if len(r.GetRoles()) < 1 { + return trace.BadParameter("access request does not specify any roles") + } + + // dedupe and sort roles to simplify comparing role lists + r.Spec.Roles = utils.Deduplicate(r.Spec.Roles) + sort.Strings(r.Spec.Roles) + return nil } diff --git a/api/types/authentication.go b/api/types/authentication.go index 4fb534d8e02..285f2dde719 100644 --- a/api/types/authentication.go +++ b/api/types/authentication.go @@ -22,7 +22,6 @@ import ( "time" "github.com/gravitational/teleport/api/constants" - "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/utils/tlsutils" "github.com/gogo/protobuf/jsonpb" @@ -93,21 +92,16 @@ func NewAuthPreferenceFromConfigFile(spec AuthPreferenceSpecV2) (AuthPreference, // NewAuthPreferenceWithLabels is a convenience method to create // AuthPreferenceV2 with a specific map of labels. func newAuthPreferenceWithLabels(spec AuthPreferenceSpecV2, labels map[string]string) (AuthPreference, error) { - pref := AuthPreferenceV2{ - Kind: KindClusterAuthPreference, - Version: V2, + pref := &AuthPreferenceV2{ Metadata: Metadata{ - Name: MetaNameClusterAuthPreference, - Namespace: defaults.Namespace, - Labels: labels, + Labels: labels, }, Spec: spec, } - if err := pref.CheckAndSetDefaults(); err != nil { return nil, trace.Wrap(err) } - return &pref, nil + return pref, nil } // DefaultAuthPreference returns the default authentication preferences. @@ -254,23 +248,20 @@ func (c *AuthPreferenceV2) SetAllowLocalAuth(b bool) { c.Spec.AllowLocalAuth = NewBoolOption(b) } +// setStaticFields sets static resource header and metadata fields. +func (c *AuthPreferenceV2) setStaticFields() { + c.Kind = KindClusterAuthPreference + c.Version = V2 + c.Metadata.Name = MetaNameClusterAuthPreference +} + // CheckAndSetDefaults verifies the constraints for AuthPreference. func (c *AuthPreferenceV2) CheckAndSetDefaults() error { - // make sure we have defaults for all metadata fields - err := c.Metadata.CheckAndSetDefaults() - if err != nil { + c.setStaticFields() + if err := c.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if c.Version == "" { - c.Version = V2 - } - // Make sure origin value is always set. - if c.Origin() == "" { - c.SetOrigin(OriginDynamic) - } - - // if nothing is passed in, set defaults if c.Spec.Type == "" { c.Spec.Type = constants.Local } @@ -283,6 +274,9 @@ func (c *AuthPreferenceV2) CheckAndSetDefaults() error { if c.Spec.DisconnectExpiredCert == nil { c.Spec.DisconnectExpiredCert = NewBoolOption(false) } + if c.Origin() == "" { + c.SetOrigin(OriginDynamic) + } // make sure type makes sense switch c.Spec.Type { @@ -332,7 +326,6 @@ func (u *U2F) Check() error { // the Device field in the returned MFADevice. func NewMFADevice(name, id string, addedAt time.Time) *MFADevice { return &MFADevice{ - Kind: KindMFADevice, Metadata: Metadata{ Name: name, }, @@ -342,18 +335,19 @@ func NewMFADevice(name, id string, addedAt time.Time) *MFADevice { } } +// setStaticFields sets static resource header and metadata fields. +func (d *MFADevice) setStaticFields() { + d.Kind = KindMFADevice + d.Version = V1 +} + // CheckAndSetDefaults validates MFADevice fields and populates empty fields // with default values. func (d *MFADevice) CheckAndSetDefaults() error { + d.setStaticFields() if err := d.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if d.Kind == "" { - return trace.BadParameter("MFADevice missing Kind field") - } - if d.Version == "" { - d.Version = V1 - } if d.Id == "" { return trace.BadParameter("MFADevice missing ID field") } diff --git a/api/types/authority.go b/api/types/authority.go index f247bc6b22c..23978263899 100644 --- a/api/types/authority.go +++ b/api/types/authority.go @@ -21,7 +21,6 @@ import ( "time" "github.com/gravitational/teleport/api/constants" - "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/utils" "github.com/gravitational/trace" @@ -80,17 +79,12 @@ type CertAuthority interface { } // NewCertAuthority returns new cert authority -func NewCertAuthority(spec CertAuthoritySpecV2) CertAuthority { - return &CertAuthorityV2{ - Kind: KindCertAuthority, - Version: V2, - SubKind: string(spec.Type), - Metadata: Metadata{ - Name: spec.ClusterName, - Namespace: defaults.Namespace, - }, - Spec: spec, +func NewCertAuthority(spec CertAuthoritySpecV2) (CertAuthority, error) { + ca := &CertAuthorityV2{Spec: spec} + if err := ca.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) } + return ca, nil } // GetVersion returns resource version @@ -344,17 +338,30 @@ func (ca *CertAuthorityV2) GetTrustedJWTKeyPairs() []*JWTKeyPair { return kps } +// setStaticFields sets static resource header and metadata fields. +func (ca *CertAuthorityV2) setStaticFields() { + ca.Kind = KindCertAuthority + ca.Version = V2 + // ca.Metadata.Name and ca.Spec.ClusterName should always be equal. + if ca.Metadata.Name == "" { + ca.Metadata.Name = ca.Spec.ClusterName + } else { + ca.Spec.ClusterName = ca.Metadata.Name + } +} + // CheckAndSetDefaults checks and set default values for any missing fields. func (ca *CertAuthorityV2) CheckAndSetDefaults() error { - err := ca.Metadata.CheckAndSetDefaults() - if err != nil { + ca.setStaticFields() + if err := ca.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if ca.Version == "" { - ca.Version = V2 + + if ca.SubKind == "" { + ca.SubKind = string(ca.Spec.Type) } - if err = ca.ID().Check(); err != nil { + if err := ca.ID().Check(); err != nil { return trace.Wrap(err) } @@ -370,10 +377,11 @@ func (ca *CertAuthorityV2) CheckAndSetDefaults() error { switch ca.GetType() { case UserCA, HostCA, JWTSigner: - return nil default: return trace.BadParameter("invalid CA type %q", ca.GetType()) } + + return nil } const ( diff --git a/api/types/clusterconfig.go b/api/types/clusterconfig.go index 51d8a53655f..15489202c2b 100644 --- a/api/types/clusterconfig.go +++ b/api/types/clusterconfig.go @@ -20,8 +20,6 @@ import ( "fmt" "time" - "github.com/gravitational/teleport/api/defaults" - "github.com/gravitational/trace" ) @@ -83,20 +81,18 @@ type ClusterConfig interface { // NewClusterConfig is a convenience wrapper to create a ClusterConfig resource. func NewClusterConfig(spec ClusterConfigSpecV3) (ClusterConfig, error) { - cc := ClusterConfigV3{ - Kind: KindClusterConfig, - Version: V3, - Metadata: Metadata{ - Name: MetaNameClusterConfig, - Namespace: defaults.Namespace, - }, - Spec: spec, - } + cc := &ClusterConfigV3{Spec: spec} if err := cc.CheckAndSetDefaults(); err != nil { return nil, trace.Wrap(err) } + return cc, nil +} - return &cc, nil +// DefaultClusterConfig is used as the default cluster configuration when +// one is not specified (record at node). +func DefaultClusterConfig() ClusterConfig { + config, _ := NewClusterConfig(ClusterConfigSpecV3{}) + return config } // GetVersion returns resource version @@ -154,16 +150,19 @@ func (c *ClusterConfigV3) GetMetadata() Metadata { return c.Metadata } +// setStaticFields sets static resource header and metadata fields. +func (c *ClusterConfigV3) setStaticFields() { + c.Kind = KindClusterConfig + c.Version = V3 + c.Metadata.Name = MetaNameClusterConfig +} + // CheckAndSetDefaults checks validity of all parameters and sets defaults. func (c *ClusterConfigV3) CheckAndSetDefaults() error { - // make sure we have defaults for all metadata fields - err := c.Metadata.CheckAndSetDefaults() - if err != nil { + c.setStaticFields() + if err := c.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if c.Version == "" { - c.Version = V3 - } return nil } diff --git a/api/types/clustername.go b/api/types/clustername.go index ea371144bad..b81abd5cc4f 100644 --- a/api/types/clustername.go +++ b/api/types/clustername.go @@ -20,8 +20,6 @@ import ( "fmt" "time" - "github.com/gravitational/teleport/api/defaults" - "github.com/gravitational/trace" ) @@ -44,20 +42,11 @@ type ClusterName interface { // NewClusterName is a convenience wrapper to create a ClusterName resource. func NewClusterName(spec ClusterNameSpecV2) (ClusterName, error) { - cn := ClusterNameV2{ - Kind: KindClusterName, - Version: V2, - Metadata: Metadata{ - Name: MetaNameClusterName, - Namespace: defaults.Namespace, - }, - Spec: spec, - } + cn := &ClusterNameV2{Spec: spec} if err := cn.CheckAndSetDefaults(); err != nil { return nil, trace.Wrap(err) } - - return &cn, nil + return cn, nil } // GetVersion returns resource version @@ -135,16 +124,19 @@ func (c *ClusterNameV2) GetClusterID() string { return c.Spec.ClusterID } +// setStaticFields sets static resource header and metadata fields. +func (c *ClusterNameV2) setStaticFields() { + c.Kind = KindClusterName + c.Version = V2 + c.Metadata.Name = MetaNameClusterName +} + // CheckAndSetDefaults checks validity of all parameters and sets defaults. func (c *ClusterNameV2) CheckAndSetDefaults() error { - // make sure we have defaults for all metadata fields - err := c.Metadata.CheckAndSetDefaults() - if err != nil { + c.setStaticFields() + if err := c.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if c.Version == "" { - c.Version = V2 - } if c.Spec.ClusterName == "" { return trace.BadParameter("cluster name is required") diff --git a/api/types/databaseserver.go b/api/types/databaseserver.go index a3e249ae26c..d9dc397da21 100644 --- a/api/types/databaseserver.go +++ b/api/types/databaseserver.go @@ -20,8 +20,6 @@ import ( "fmt" "time" - "github.com/gravitational/teleport/api/defaults" - "github.com/gogo/protobuf/proto" "github.com/gravitational/trace" ) @@ -83,17 +81,18 @@ type DatabaseServer interface { } // NewDatabaseServerV3 creates a new database server instance. -func NewDatabaseServerV3(name string, labels map[string]string, spec DatabaseServerSpecV3) *DatabaseServerV3 { - return &DatabaseServerV3{ - Kind: KindDatabaseServer, - Version: V3, +func NewDatabaseServerV3(name string, labels map[string]string, spec DatabaseServerSpecV3) (*DatabaseServerV3, error) { + s := &DatabaseServerV3{ Metadata: Metadata{ - Name: name, - Namespace: defaults.Namespace, - Labels: labels, + Name: name, + Labels: labels, }, Spec: spec, } + if err := s.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + return s, nil } // GetVersion returns the database server resource version. @@ -284,17 +283,19 @@ func (s *DatabaseServerV3) String() string { s.GetName(), s.GetType(), s.GetTeleportVersion(), s.GetStaticLabels(), s.Spec.HostID) } +// setStaticFields sets static resource header and metadata fields. +func (s *DatabaseServerV3) setStaticFields() { + s.Kind = KindDatabaseServer + s.Version = V3 +} + // CheckAndSetDefaults checks and sets default values for any missing fields. func (s *DatabaseServerV3) CheckAndSetDefaults() error { + s.setStaticFields() if err := s.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if s.Version == "" { - s.Version = V3 - } - if s.Kind == "" { - return trace.BadParameter("database server %q kind is empty", s.GetName()) - } + for key := range s.Spec.DynamicLabels { if !IsValidLabelKey(key) { return trace.BadParameter("database server %q invalid label key: %q", s.GetName(), key) diff --git a/api/types/github.go b/api/types/github.go index 4421d7b0a49..218db2267ce 100644 --- a/api/types/github.go +++ b/api/types/github.go @@ -19,7 +19,6 @@ package types import ( "time" - "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/utils" "github.com/gravitational/trace" @@ -57,16 +56,17 @@ type GithubConnector interface { } // NewGithubConnector creates a new Github connector from name and spec -func NewGithubConnector(name string, spec GithubConnectorSpecV3) GithubConnector { - return &GithubConnectorV3{ - Kind: KindGithubConnector, - Version: V3, +func NewGithubConnector(name string, spec GithubConnectorSpecV3) (GithubConnector, error) { + c := &GithubConnectorV3{ Metadata: Metadata{ - Name: name, - Namespace: defaults.Namespace, + Name: name, }, Spec: spec, } + if err := c.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + return c, nil } // GithubClaims represents Github user information obtained during OAuth2 flow @@ -147,17 +147,18 @@ func (c *GithubConnectorV3) WithoutSecrets() Resource { return &c2 } +// setStaticFields sets static resource header and metadata fields. +func (c *GithubConnectorV3) setStaticFields() { + c.Kind = KindGithubConnector + c.Version = V3 +} + // CheckAndSetDefaults verifies the connector is valid and sets some defaults func (c *GithubConnectorV3) CheckAndSetDefaults() error { + c.setStaticFields() if err := c.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if c.Version == "" { - c.Version = V3 - } - if c.Kind == "" { - c.Kind = KindGithubConnector - } return nil } diff --git a/api/types/license.go b/api/types/license.go index 168a5d56f19..accb16b3d44 100644 --- a/api/types/license.go +++ b/api/types/license.go @@ -21,7 +21,7 @@ import ( "strings" "time" - "github.com/gravitational/teleport/api/defaults" + "github.com/gravitational/trace" ) // License defines teleport License Information @@ -75,15 +75,16 @@ type License interface { // NewLicense is a convenience method to to create LicenseV3. func NewLicense(name string, spec LicenseSpecV3) (License, error) { - return &LicenseV3{ - Kind: KindLicense, - Version: V3, + l := &LicenseV3{ Metadata: Metadata{ - Name: name, - Namespace: defaults.Namespace, + Name: name, }, Spec: spec, - }, nil + } + if err := l.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + return l, nil } // LicenseV3 represents License resource version V3 @@ -190,9 +191,19 @@ func (c *LicenseV3) SetReportsUsage(reports Bool) { c.Spec.ReportsUsage = reports } +// setStaticFields sets static resource header and metadata fields. +func (c *LicenseV3) setStaticFields() { + c.Kind = KindLicense + c.Version = V3 +} + // CheckAndSetDefaults verifies the constraints for License. func (c *LicenseV3) CheckAndSetDefaults() error { - return c.Metadata.CheckAndSetDefaults() + c.setStaticFields() + if err := c.Metadata.CheckAndSetDefaults(); err != nil { + return trace.Wrap(err) + } + return nil } // GetAWSProductID returns product ID that limits usage to AWS instance diff --git a/api/types/namespace.go b/api/types/namespace.go index be7a2055113..2b5860fab5b 100644 --- a/api/types/namespace.go +++ b/api/types/namespace.go @@ -20,30 +20,43 @@ import ( "regexp" "time" + "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/trace" ) // NewNamespace returns new namespace -func NewNamespace(name string) Namespace { - return Namespace{ - Kind: KindNamespace, - Version: V2, +func NewNamespace(name string) (Namespace, error) { + n := Namespace{ Metadata: Metadata{ Name: name, }, } + if err := n.CheckAndSetDefaults(); err != nil { + return Namespace{}, trace.Wrap(err) + } + return n, nil +} + +// DefaultNamespace returns the default namespace. +func DefaultNamespace() Namespace { + namespace, _ := NewNamespace(defaults.Namespace) + return namespace +} + +// setStaticFields sets static resource header and metadata fields. +func (n *Namespace) setStaticFields() { + n.Kind = KindNamespace + n.Version = V2 } // CheckAndSetDefaults checks validity of all parameters and sets defaults func (n *Namespace) CheckAndSetDefaults() error { + n.setStaticFields() if err := n.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if n.Version == "" { - n.Version = V1 - } - isValid := IsValidNamespace(n.Metadata.Name) - if !isValid { + + if !IsValidNamespace(n.Metadata.Name) { return trace.BadParameter("namespace %q is invalid", n.Metadata.Name) } diff --git a/api/types/networking.go b/api/types/networking.go index 2c0480a8e21..87fd53cefea 100644 --- a/api/types/networking.go +++ b/api/types/networking.go @@ -77,21 +77,16 @@ func DefaultClusterNetworkingConfig() ClusterNetworkingConfig { // newClusterNetworkingConfigWithLabels is a convenience method to create // ClusterNetworkingConfigV2 with a specific map of labels. func newClusterNetworkingConfigWithLabels(spec ClusterNetworkingConfigSpecV2, labels map[string]string) (ClusterNetworkingConfig, error) { - netConfig := &ClusterNetworkingConfigV2{ - Kind: KindClusterNetworkingConfig, - Version: V2, + c := &ClusterNetworkingConfigV2{ Metadata: Metadata{ - Name: MetaNameClusterNetworkingConfig, - Namespace: defaults.Namespace, - Labels: labels, + Labels: labels, }, Spec: spec, } - - if err := netConfig.CheckAndSetDefaults(); err != nil { + if err := c.CheckAndSetDefaults(); err != nil { return nil, trace.Wrap(err) } - return netConfig, nil + return c, nil } // GetVersion returns resource version. @@ -201,16 +196,19 @@ func (c *ClusterNetworkingConfigV2) SetSessionControlTimeout(d time.Duration) { c.Spec.SessionControlTimeout = Duration(d) } +// setStaticFields sets static resource header and metadata fields. +func (c *ClusterNetworkingConfigV2) setStaticFields() { + c.Kind = KindClusterNetworkingConfig + c.Version = V2 + c.Metadata.Name = MetaNameClusterNetworkingConfig +} + // CheckAndSetDefaults verifies the constraints for ClusterNetworkingConfig. func (c *ClusterNetworkingConfigV2) CheckAndSetDefaults() error { - // Make sure we have defaults for all metadata fields. - err := c.Metadata.CheckAndSetDefaults() - if err != nil { + c.setStaticFields() + if err := c.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if c.Version == "" { - c.Version = V2 - } // Make sure origin value is always set. if c.Origin() == "" { diff --git a/api/types/oidc.go b/api/types/oidc.go index 6f7ff7acbbe..f8c2d9ba8c4 100644 --- a/api/types/oidc.go +++ b/api/types/oidc.go @@ -20,7 +20,6 @@ import ( "time" "github.com/gravitational/teleport/api/constants" - "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/utils" "github.com/gravitational/trace" @@ -57,8 +56,6 @@ type OIDCConnector interface { // GetTraitMappings converts gets all claim mappings in the // generic trait mapping format. GetTraitMappings() TraitMappingSet - // Check checks OIDC connector for errors - Check() error // SetClientSecret sets client secret to some value SetClientSecret(secret string) // SetClientID sets id for authentication client (in our case it's our Auth server) @@ -94,16 +91,17 @@ type OIDCConnector interface { } // NewOIDCConnector returns a new OIDCConnector based off a name and OIDCConnectorSpecV2. -func NewOIDCConnector(name string, spec OIDCConnectorSpecV2) OIDCConnector { - return &OIDCConnectorV2{ - Kind: KindOIDCConnector, - Version: V2, +func NewOIDCConnector(name string, spec OIDCConnectorSpecV2) (OIDCConnector, error) { + o := &OIDCConnectorV2{ Metadata: Metadata{ - Name: name, - Namespace: defaults.Namespace, + Name: name, }, Spec: spec, } + if err := o.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + return o, nil } // SetPrompt sets OIDC prompt value @@ -336,11 +334,19 @@ func (o *OIDCConnectorV2) GetTraitMappings() TraitMappingSet { return TraitMappingSet(tms) } -// Check returns nil if all parameters are great, err otherwise -func (o *OIDCConnectorV2) Check() error { - if o.Metadata.Name == "" { - return trace.BadParameter("ID: missing connector name") +// setStaticFields sets static resource header and metadata fields. +func (o *OIDCConnectorV2) setStaticFields() { + o.Kind = KindOIDCConnector + o.Version = V2 +} + +// CheckAndSetDefaults checks and set default values for any missing fields. +func (o *OIDCConnectorV2) CheckAndSetDefaults() error { + o.setStaticFields() + if err := o.Metadata.CheckAndSetDefaults(); err != nil { + return trace.Wrap(err) } + if o.Metadata.Name == constants.Local { return trace.BadParameter("ID: invalid connector name, %v is a reserved name", constants.Local) } @@ -357,21 +363,3 @@ func (o *OIDCConnectorV2) Check() error { return nil } - -// CheckAndSetDefaults checks and set default values for any missing fields. -func (o *OIDCConnectorV2) CheckAndSetDefaults() error { - err := o.Metadata.CheckAndSetDefaults() - if err != nil { - return trace.Wrap(err) - } - if o.Version == "" { - o.Version = V2 - } - - err = o.Check() - if err != nil { - return trace.Wrap(err) - } - - return nil -} diff --git a/api/types/plugin_data.go b/api/types/plugin_data.go index 305342546b2..3c843fb81c4 100644 --- a/api/types/plugin_data.go +++ b/api/types/plugin_data.go @@ -42,10 +42,6 @@ type PluginData interface { // name of an access request). func NewPluginData(resourceName string, resourceKind string) (PluginData, error) { data := PluginDataV3{ - Kind: KindPluginData, - Version: V3, - // If additional resource kinds become supported, make - // this a parameter. SubKind: resourceKind, Metadata: Metadata{ Name: resourceName, @@ -119,17 +115,23 @@ func (r *PluginDataV3) String() string { return fmt.Sprintf("PluginData(kind=%s,resource=%s,entries=%d)", r.GetSubKind(), r.GetName(), len(r.Spec.Entries)) } +// setStaticFields sets static resource header and metadata fields. +func (r *PluginDataV3) setStaticFields() { + r.Kind = KindPluginData + r.Version = V3 +} + // CheckAndSetDefaults checks and sets default values for PluginData. func (r *PluginDataV3) CheckAndSetDefaults() error { + r.setStaticFields() if err := r.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if r.Version == "" { - r.Version = V3 - } + if r.SubKind == "" { return trace.BadParameter("plugin data missing subkind") } + return nil } diff --git a/api/types/presence.go b/api/types/presence.go index 7150b6c4bae..df7822e19cf 100644 --- a/api/types/presence.go +++ b/api/types/presence.go @@ -64,12 +64,12 @@ func (s *KeepAlive) GetType() string { // CheckAndSetDefaults validates this KeepAlive value and sets default values func (s *KeepAlive) CheckAndSetDefaults() error { - if s.IsEmpty() { - return trace.BadParameter("invalid keep alive, missing lease ID and resource name") - } if s.Namespace == "" { s.Namespace = defaults.Namespace } + if s.IsEmpty() { + return trace.BadParameter("invalid keep alive, missing lease ID and resource name") + } return nil } diff --git a/api/types/provisioning.go b/api/types/provisioning.go index 69c19b9edf7..2855aaf9d45 100644 --- a/api/types/provisioning.go +++ b/api/types/provisioning.go @@ -45,12 +45,9 @@ type ProvisionToken interface { // NewProvisionToken returns a new instance of provision token resource func NewProvisionToken(token string, roles SystemRoles, expires time.Time) (ProvisionToken, error) { t := &ProvisionTokenV2{ - Kind: KindToken, - Version: V2, Metadata: Metadata{ - Name: token, - Expires: &expires, - Namespace: defaults.Namespace, + Name: token, + Expires: &expires, }, Spec: ProvisionTokenSpecV2{ Roles: roles, @@ -72,22 +69,26 @@ func MustCreateProvisionToken(token string, roles SystemRoles, expires time.Time return t } +// setStaticFields sets static resource header and metadata fields. +func (p *ProvisionTokenV2) setStaticFields() { + p.Kind = KindToken + p.Version = V2 +} + // CheckAndSetDefaults checks and set default values for any missing fields. func (p *ProvisionTokenV2) CheckAndSetDefaults() error { - p.Kind = KindToken - err := p.Metadata.CheckAndSetDefaults() - if err != nil { + p.setStaticFields() + if err := p.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if p.Version == "" { - p.Version = V2 - } + if len(p.Spec.Roles) == 0 { return trace.BadParameter("provisioning token is missing roles") } if err := SystemRoles(p.Spec.Roles).Check(); err != nil { return trace.Wrap(err) } + return nil } diff --git a/api/types/remotecluster.go b/api/types/remotecluster.go index b5354ca5338..c50027d062f 100644 --- a/api/types/remotecluster.go +++ b/api/types/remotecluster.go @@ -21,8 +21,6 @@ import ( "time" "github.com/gravitational/trace" - - "github.com/gravitational/teleport/api/defaults" ) // RemoteCluster represents a remote cluster that has connected via reverse tunnel @@ -46,14 +44,15 @@ type RemoteCluster interface { // NewRemoteCluster is a convenience way to create a RemoteCluster resource. func NewRemoteCluster(name string) (RemoteCluster, error) { - return &RemoteClusterV3{ - Kind: KindRemoteCluster, - Version: V3, + c := &RemoteClusterV3{ Metadata: Metadata{ - Name: name, - Namespace: defaults.Namespace, + Name: name, }, - }, nil + } + if err := c.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + return c, nil } // GetVersion returns resource version @@ -86,14 +85,18 @@ func (c *RemoteClusterV3) SetResourceID(id int64) { c.Metadata.ID = id } +// setStaticFields sets static resource header and metadata fields. +func (c *RemoteClusterV3) setStaticFields() { + c.Kind = KindRemoteCluster + c.Version = V3 +} + // CheckAndSetDefaults checks and sets default values func (c *RemoteClusterV3) CheckAndSetDefaults() error { + c.setStaticFields() if err := c.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if c.Version == "" { - c.Version = V3 - } return nil } diff --git a/api/types/resetpasswordtoken.go b/api/types/resetpasswordtoken.go index f7c633abec8..d7b8077637c 100644 --- a/api/types/resetpasswordtoken.go +++ b/api/types/resetpasswordtoken.go @@ -21,8 +21,6 @@ import ( "time" "github.com/gravitational/trace" - - "github.com/gravitational/teleport/api/defaults" ) // ResetPasswordToken represents a temporary token used to reset passwords @@ -44,15 +42,16 @@ type ResetPasswordToken interface { } // NewResetPasswordToken creates an instance of ResetPasswordToken. -func NewResetPasswordToken(tokenID string) ResetPasswordToken { - return &ResetPasswordTokenV3{ - Kind: KindResetPasswordToken, - Version: V3, +func NewResetPasswordToken(tokenID string) (ResetPasswordToken, error) { + u := &ResetPasswordTokenV3{ Metadata: Metadata{ - Name: tokenID, - Namespace: defaults.Namespace, + Name: tokenID, }, } + if err := u.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + return u, nil } // GetName returns Name @@ -140,14 +139,18 @@ func (u *ResetPasswordTokenV3) SetSubKind(s string) { u.SubKind = s } +// setStaticFields sets static resource header and metadata fields. +func (u *ResetPasswordTokenV3) setStaticFields() { + u.Kind = KindResetPasswordToken + u.Version = V3 +} + // CheckAndSetDefaults checks and set default values for any missing fields. func (u ResetPasswordTokenV3) CheckAndSetDefaults() error { + u.setStaticFields() if err := u.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if u.Version == "" { - u.Version = V3 - } return nil } diff --git a/api/types/resetpasswordtokensecrets.go b/api/types/resetpasswordtokensecrets.go index 951edd4f37c..16ee9ed2ba5 100644 --- a/api/types/resetpasswordtokensecrets.go +++ b/api/types/resetpasswordtokensecrets.go @@ -44,18 +44,13 @@ type ResetPasswordTokenSecrets interface { // NewResetPasswordTokenSecrets creates an instance of ResetPasswordTokenSecrets. func NewResetPasswordTokenSecrets(tokenID string) (ResetPasswordTokenSecrets, error) { secrets := ResetPasswordTokenSecretsV3{ - Kind: KindResetPasswordTokenSecrets, - Version: V3, Metadata: Metadata{ Name: tokenID, }, } - - err := secrets.CheckAndSetDefaults() - if err != nil { - return &ResetPasswordTokenSecretsV3{}, trace.Wrap(err) + if err := secrets.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) } - return &secrets, nil } @@ -144,14 +139,18 @@ func (u *ResetPasswordTokenSecretsV3) SetSubKind(s string) { u.SubKind = s } +// setStaticFields sets static resource header and metadata fields. +func (u *ResetPasswordTokenSecretsV3) setStaticFields() { + u.Kind = KindResetPasswordTokenSecrets + u.Version = V3 +} + // CheckAndSetDefaults checks and set default values for any missing fields. func (u ResetPasswordTokenSecretsV3) CheckAndSetDefaults() error { + u.setStaticFields() if err := u.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if u.Version == "" { - u.Version = V3 - } return nil } diff --git a/api/types/role.go b/api/types/role.go index 46ac487cb81..951a3bab678 100644 --- a/api/types/role.go +++ b/api/types/role.go @@ -121,18 +121,14 @@ type Role interface { // NewRole constructs new standard role func NewRole(name string, spec RoleSpecV4) (Role, error) { role := RoleV4{ - Kind: KindRole, - Version: V3, Metadata: Metadata{ - Name: name, - Namespace: defaults.Namespace, + Name: name, }, Spec: spec, } if err := role.CheckAndSetDefaults(); err != nil { return nil, trace.Wrap(err) } - return &role, nil } @@ -488,15 +484,23 @@ func (r *RoleV4) SetRules(rct RoleConditionType, in []Rule) { } } +// setStaticFields sets static resource header and metadata fields. +func (r *RoleV4) setStaticFields() { + r.Kind = KindRole + // TODO(Joerger/nklaassen) Role should default to V4 + // but shouldn't overwrite V3. For now, this does the + // opposite due to an internal reliance on V3 defaults. + if r.Version != V4 { + r.Version = V3 + } +} + // CheckAndSetDefaults checks validity of all parameters and sets defaults func (r *RoleV4) CheckAndSetDefaults() error { - err := r.Metadata.CheckAndSetDefaults() - if err != nil { + r.setStaticFields() + if err := r.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if r.Version == "" { - r.Version = V3 - } // Make sure all fields have defaults. if r.Spec.Options.CertificateFormat == "" { diff --git a/api/types/saml.go b/api/types/saml.go index f001ad401ae..62c109a7524 100644 --- a/api/types/saml.go +++ b/api/types/saml.go @@ -20,7 +20,6 @@ import ( "time" "github.com/gravitational/teleport/api/constants" - "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/utils" "github.com/gravitational/trace" @@ -90,16 +89,17 @@ type SAMLConnector interface { } // NewSAMLConnector returns a new SAMLConnector based off a name and SAMLConnectorSpecV2. -func NewSAMLConnector(name string, spec SAMLConnectorSpecV2) SAMLConnector { - return &SAMLConnectorV2{ - Kind: KindSAMLConnector, - Version: V2, +func NewSAMLConnector(name string, spec SAMLConnectorSpecV2) (SAMLConnector, error) { + o := &SAMLConnectorV2{ Metadata: Metadata{ - Name: name, - Namespace: defaults.Namespace, + Name: name, }, Spec: spec, } + if err := o.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + return o, nil } // GetVersion returns resource version @@ -325,14 +325,19 @@ func (o *SAMLConnectorV2) SetEncryptionKeyPair(k *AsymmetricKeyPair) { o.Spec.EncryptionKeyPair = k } +// setStaticFields sets static resource header and metadata fields. +func (o *SAMLConnectorV2) setStaticFields() { + o.Kind = KindSAMLConnector + o.Version = V2 +} + // CheckAndSetDefaults checks and sets default values func (o *SAMLConnectorV2) CheckAndSetDefaults() error { + o.setStaticFields() if err := o.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if o.Version == "" { - o.Version = V2 - } + if o.Metadata.Name == constants.Local { return trace.BadParameter("ID: invalid connector name, %v is a reserved name", constants.Local) } diff --git a/api/types/semaphore.go b/api/types/semaphore.go index 05c232a5549..4e2148df860 100644 --- a/api/types/semaphore.go +++ b/api/types/semaphore.go @@ -22,7 +22,6 @@ import ( "time" "github.com/gravitational/teleport/api/constants" - "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/trace" ) @@ -56,12 +55,9 @@ type Semaphore interface { // these acquire parameters. func (s *AcquireSemaphoreRequest) ConfigureSemaphore() (Semaphore, error) { sem := SemaphoreV3{ - Kind: KindSemaphore, SubKind: s.SemaphoreKind, - Version: V3, Metadata: Metadata{ - Name: s.SemaphoreName, - Namespace: defaults.Namespace, + Name: s.SemaphoreName, }, } sem.SetExpiry(s.Expires) @@ -271,16 +267,19 @@ func (c *SemaphoreV3) String() string { c.SubKind, c.Metadata.Name, c.leaseCount()) } +// setStaticFields sets static resource header and metadata fields. +func (c *SemaphoreV3) setStaticFields() { + c.Kind = KindSemaphore + c.Version = V3 +} + // CheckAndSetDefaults checks validity of all parameters and sets defaults. func (c *SemaphoreV3) CheckAndSetDefaults() error { - // make sure we have defaults for all metadata fields - err := c.Metadata.CheckAndSetDefaults() - if err != nil { + c.setStaticFields() + if err := c.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if c.Version == "" { - c.Version = V3 - } + // While theoretically there are scenarios with non-expiring semaphores // however the flow don't need them right now, and they add a lot of edge // cases, so the code does not support them. diff --git a/api/types/server.go b/api/types/server.go index 926bbabff56..fa29c891fc0 100644 --- a/api/types/server.go +++ b/api/types/server.go @@ -86,6 +86,28 @@ type Server interface { DeepCopy() Server } +// NewServer creates an instance of Server. +func NewServer(name, kind string, spec ServerSpecV2) (Server, error) { + return NewServerWithLabels(name, kind, spec, map[string]string{}) +} + +// NewServerWithLabels is a convenience method to create +// ServerV2 with a specific map of labels. +func NewServerWithLabels(name, kind string, spec ServerSpecV2, labels map[string]string) (Server, error) { + server := &ServerV2{ + Kind: kind, + Metadata: Metadata{ + Name: name, + Labels: labels, + }, + Spec: spec, + } + if err := server.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + return server, nil +} + // GetVersion returns resource version func (s *ServerV2) GetVersion() string { return s.Version @@ -295,18 +317,20 @@ func LabelsAsString(static map[string]string, dynamic map[string]CommandLabelV2) return strings.Join(labels, ",") } +// setStaticFields sets static resource header and metadata fields. +func (s *ServerV2) setStaticFields() { + s.Version = V2 +} + // CheckAndSetDefaults checks and set default values for any missing fields. func (s *ServerV2) CheckAndSetDefaults() error { // TODO(awly): default s.Metadata.Expiry if not set (use // defaults.ServerAnnounceTTL). - - err := s.Metadata.CheckAndSetDefaults() - if err != nil { + s.setStaticFields() + if err := s.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if s.Version == "" { - s.Version = V2 - } + if s.Kind == "" { return trace.BadParameter("server Kind is empty") } diff --git a/api/types/session.go b/api/types/session.go index 7cc6083e9b9..f88a3a20c20 100644 --- a/api/types/session.go +++ b/api/types/session.go @@ -89,18 +89,19 @@ type WebSession interface { } // NewWebSession returns new instance of the web session based on the V2 spec -func NewWebSession(name string, kind string, subkind string, spec WebSessionSpecV2) WebSession { - return &WebSessionV2{ - Kind: kind, +func NewWebSession(name string, subkind string, spec WebSessionSpecV2) (WebSession, error) { + ws := &WebSessionV2{ SubKind: subkind, - Version: V2, Metadata: Metadata{ - Name: name, - Namespace: defaults.Namespace, - Expires: &spec.Expires, + Name: name, + Expires: &spec.Expires, }, Spec: spec, } + if err := ws.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + return ws, nil } // GetKind gets resource Kind @@ -164,15 +165,19 @@ func (ws *WebSessionV2) WithoutSecrets() WebSession { return ws } +// setStaticFields sets static resource header and metadata fields. +func (ws *WebSessionV2) setStaticFields() { + ws.Version = V2 + ws.Kind = KindWebSession +} + // CheckAndSetDefaults checks and set default values for any missing fields. func (ws *WebSessionV2) CheckAndSetDefaults() error { - err := ws.Metadata.CheckAndSetDefaults() - if err != nil { + ws.setStaticFields() + if err := ws.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if ws.Version == "" { - ws.Version = V2 - } + if ws.Spec.User == "" { return trace.BadParameter("missing User") } @@ -302,17 +307,18 @@ type DeleteAppSessionRequest struct { } // NewWebToken returns a new web token with the given expiration and spec -func NewWebToken(expires time.Time, spec WebTokenSpecV3) WebToken { - return &WebTokenV3{ - Kind: KindWebToken, - Version: V3, +func NewWebToken(expires time.Time, spec WebTokenSpecV3) (WebToken, error) { + r := &WebTokenV3{ Metadata: Metadata{ - Name: spec.Token, - Namespace: defaults.Namespace, - Expires: &expires, + Name: spec.Token, + Expires: &expires, }, Spec: spec, } + if err := r.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + return r, nil } // WebTokensGetter provides access to web tokens @@ -436,14 +442,19 @@ func (r *WebTokenV3) SetExpiry(t time.Time) { r.Metadata.Expires = &t } +// setStaticFields sets static resource header and metadata fields. +func (r *WebTokenV3) setStaticFields() { + r.Kind = KindWebToken + r.Version = V3 +} + // CheckAndSetDefaults validates this token value and sets defaults func (r *WebTokenV3) CheckAndSetDefaults() error { + r.setStaticFields() if err := r.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if r.Version == "" { - r.Version = V3 - } + if r.Spec.User == "" { return trace.BadParameter("User required") } diff --git a/api/types/sessionrecording.go b/api/types/sessionrecording.go index 65543b8a7ee..0270977dff3 100644 --- a/api/types/sessionrecording.go +++ b/api/types/sessionrecording.go @@ -20,7 +20,6 @@ import ( "strings" "time" - "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/utils" "github.com/gravitational/trace" @@ -64,16 +63,11 @@ func DefaultSessionRecordingConfig() SessionRecordingConfig { // SessionRecordingConfigV2 with a specific map of labels. func newSessionRecordingConfigWithLabels(spec SessionRecordingConfigSpecV2, labels map[string]string) (SessionRecordingConfig, error) { recConfig := &SessionRecordingConfigV2{ - Kind: KindSessionRecordingConfig, - Version: V2, Metadata: Metadata{ - Name: MetaNameSessionRecordingConfig, - Namespace: defaults.Namespace, - Labels: labels, + Labels: labels, }, Spec: spec, } - if err := recConfig.CheckAndSetDefaults(); err != nil { return nil, trace.Wrap(err) } @@ -165,16 +159,19 @@ func (c *SessionRecordingConfigV2) SetProxyChecksHostKeys(t bool) { c.Spec.ProxyChecksHostKeys = NewBoolOption(t) } +// setStaticFields sets static resource header and metadata fields. +func (c *SessionRecordingConfigV2) setStaticFields() { + c.Kind = KindSessionRecordingConfig + c.Version = V2 + c.Metadata.Name = MetaNameSessionRecordingConfig +} + // CheckAndSetDefaults verifies the constraints for SessionRecordingConfig. func (c *SessionRecordingConfigV2) CheckAndSetDefaults() error { - // Make sure we have defaults for all metadata fields. - err := c.Metadata.CheckAndSetDefaults() - if err != nil { + c.setStaticFields() + if err := c.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if c.Version == "" { - c.Version = V2 - } // Make sure origin value is always set. if c.Origin() == "" { diff --git a/api/types/statictokens.go b/api/types/statictokens.go index c005b5f96c3..7ed5a7278ef 100644 --- a/api/types/statictokens.go +++ b/api/types/statictokens.go @@ -20,8 +20,6 @@ import ( "fmt" "time" - "github.com/gravitational/teleport/api/defaults" - "github.com/gravitational/trace" ) @@ -39,20 +37,18 @@ type StaticTokens interface { // NewStaticTokens is a convenience wrapper to create a StaticTokens resource. func NewStaticTokens(spec StaticTokensSpecV2) (StaticTokens, error) { - st := StaticTokensV2{ - Kind: KindStaticTokens, - Version: V2, - Metadata: Metadata{ - Name: MetaNameStaticTokens, - Namespace: defaults.Namespace, - }, - Spec: spec, - } + st := &StaticTokensV2{Spec: spec} if err := st.CheckAndSetDefaults(); err != nil { return nil, trace.Wrap(err) } + return st, nil +} - return &st, nil +// DefaultStaticTokens is used to get the default static tokens (empty list) +// when nothing is specified in file configuration. +func DefaultStaticTokens() StaticTokens { + token, _ := NewStaticTokens(StaticTokensSpecV2{}) + return token } // GetVersion returns resource version @@ -120,17 +116,19 @@ func (c *StaticTokensV2) GetStaticTokens() []ProvisionToken { return ProvisionTokensFromV1(c.Spec.StaticTokens) } +// setStaticFields sets static resource header and metadata fields. +func (c *StaticTokensV2) setStaticFields() { + c.Kind = KindStaticTokens + c.Version = V2 + c.Metadata.Name = MetaNameStaticTokens +} + // CheckAndSetDefaults checks validity of all parameters and sets defaults. func (c *StaticTokensV2) CheckAndSetDefaults() error { - // make sure we have defaults for all metadata fields - err := c.Metadata.CheckAndSetDefaults() - if err != nil { + c.setStaticFields() + if err := c.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if c.Version == "" { - c.Version = V2 - } - return nil } diff --git a/api/types/trustedcluster.go b/api/types/trustedcluster.go index c4151552afd..29bfa6b73cb 100644 --- a/api/types/trustedcluster.go +++ b/api/types/trustedcluster.go @@ -22,7 +22,6 @@ import ( "github.com/google/go-cmp/cmp" - "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/utils" "github.com/gravitational/trace" @@ -68,26 +67,31 @@ type TrustedCluster interface { // NewTrustedCluster is a convenience way to create a TrustedCluster resource. func NewTrustedCluster(name string, spec TrustedClusterSpecV2) (TrustedCluster, error) { - return &TrustedClusterV2{ - Kind: KindTrustedCluster, - Version: V2, + c := &TrustedClusterV2{ Metadata: Metadata{ - Name: name, - Namespace: defaults.Namespace, + Name: name, }, Spec: spec, - }, nil + } + if err := c.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + return c, nil +} + +// setStaticFields sets static resource header and metadata fields. +func (c *TrustedClusterV2) setStaticFields() { + c.Kind = KindTrustedCluster + c.Version = V2 } // CheckAndSetDefaults checks validity of all parameters and sets defaults func (c *TrustedClusterV2) CheckAndSetDefaults() error { - // make sure we have defaults for all fields + c.setStaticFields() if err := c.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if c.Version == "" { - c.Version = V2 - } + // This is to force users to migrate if len(c.Spec.Roles) != 0 && len(c.Spec.RoleMap) != 0 { return trace.BadParameter("should set either 'roles' or 'role_map', not both") diff --git a/api/types/tunnel.go b/api/types/tunnel.go index bcb09287a49..e1893486c70 100644 --- a/api/types/tunnel.go +++ b/api/types/tunnel.go @@ -20,8 +20,6 @@ import ( "strings" "time" - "github.com/gravitational/teleport/api/defaults" - "github.com/gravitational/trace" ) @@ -41,24 +39,23 @@ type ReverseTunnel interface { SetType(TunnelType) // GetDialAddrs returns list of dial addresses for this cluster GetDialAddrs() []string - // Check checks tunnel for errors - Check() error } // NewReverseTunnel returns new version of reverse tunnel -func NewReverseTunnel(clusterName string, dialAddrs []string) ReverseTunnel { - return &ReverseTunnelV2{ - Kind: KindReverseTunnel, - Version: V2, +func NewReverseTunnel(clusterName string, dialAddrs []string) (ReverseTunnel, error) { + r := &ReverseTunnelV2{ Metadata: Metadata{ - Name: clusterName, - Namespace: defaults.Namespace, + Name: clusterName, }, Spec: ReverseTunnelSpecV2{ ClusterName: clusterName, DialAddrs: dialAddrs, }, } + if err := r.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + return r, nil } // GetVersion returns resource version @@ -116,19 +113,24 @@ func (r *ReverseTunnelV2) SetName(e string) { r.Metadata.Name = e } +// setStaticFields sets static resource header and metadata fields. +func (r *ReverseTunnelV2) setStaticFields() { + r.Kind = KindReverseTunnel + r.Version = V2 +} + // CheckAndSetDefaults checks and sets defaults func (r *ReverseTunnelV2) CheckAndSetDefaults() error { - err := r.Metadata.CheckAndSetDefaults() - if err != nil { + r.setStaticFields() + if err := r.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if r.Version == "" { - r.Version = V2 - } - err = r.Check() - if err != nil { - return trace.Wrap(err) + if strings.TrimSpace(r.Spec.ClusterName) == "" { + return trace.BadParameter("reverse tunnel validation error: empty cluster name") + } + if len(r.Spec.DialAddrs) == 0 { + return trace.BadParameter("invalid dial address for reverse tunnel '%v'", r.Spec.ClusterName) } return nil @@ -161,17 +163,3 @@ func (r *ReverseTunnelV2) SetType(tt TunnelType) { func (r *ReverseTunnelV2) GetDialAddrs() []string { return r.Spec.DialAddrs } - -// Check returns nil if all parameters are good, error otherwise -func (r *ReverseTunnelV2) Check() error { - if r.Version == "" { - return trace.BadParameter("missing reverse tunnel version") - } - if strings.TrimSpace(r.Spec.ClusterName) == "" { - return trace.BadParameter("Reverse tunnel validation error: empty cluster name") - } - if len(r.Spec.DialAddrs) == 0 { - return trace.BadParameter("Invalid dial address for reverse tunnel '%v'", r.Spec.ClusterName) - } - return nil -} diff --git a/api/types/tunnelconn.go b/api/types/tunnelconn.go index dc2075235d5..0de0daece87 100644 --- a/api/types/tunnelconn.go +++ b/api/types/tunnelconn.go @@ -44,8 +44,6 @@ type TunnelConnection interface { GetType() TunnelType // SetType sets the type of ReverseTunnel. SetType(TunnelType) - // Check checks tunnel for errors - Check() error // String returns user friendly representation of this connection String() string // Clone returns a copy of this tunnel connection @@ -55,12 +53,9 @@ type TunnelConnection interface { // NewTunnelConnection returns new connection from V2 spec func NewTunnelConnection(name string, spec TunnelConnectionSpecV2) (TunnelConnection, error) { conn := &TunnelConnectionV2{ - Kind: KindTunnelConnection, SubKind: spec.ClusterName, - Version: V2, Metadata: Metadata{ - Name: name, - Namespace: defaults.Namespace, + Name: name, }, Spec: spec, } @@ -142,18 +137,16 @@ func (r *TunnelConnectionV2) V2() *TunnelConnectionV2 { return r } +// setStaticFields sets static resource header and metadata fields. +func (r *TunnelConnectionV2) setStaticFields() { + r.Kind = KindTunnelConnection + r.Version = V2 +} + // CheckAndSetDefaults checks and sets default values func (r *TunnelConnectionV2) CheckAndSetDefaults() error { - err := r.Metadata.CheckAndSetDefaults() - if err != nil { - return trace.Wrap(err) - } - if r.Version == "" { - r.Version = V2 - } - - err = r.Check() - if err != nil { + r.setStaticFields() + if err := r.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } @@ -169,6 +162,13 @@ func (r *TunnelConnectionV2) CheckAndSetDefaults() error { r.SetExpiry(from.UTC().Add(defaults.ServerAnnounceTTL)) } + if strings.TrimSpace(r.Spec.ClusterName) == "" { + return trace.BadParameter("empty cluster name") + } + if len(r.Spec.ProxyName) == 0 { + return trace.BadParameter("missing parameter proxy name") + } + return nil } @@ -204,19 +204,3 @@ func (r *TunnelConnectionV2) GetType() TunnelType { func (r *TunnelConnectionV2) SetType(tt TunnelType) { r.Spec.Type = tt } - -// Check returns nil if all parameters are good, error otherwise -func (r *TunnelConnectionV2) Check() error { - if r.Version == "" { - return trace.BadParameter("missing version") - } - if strings.TrimSpace(r.Spec.ClusterName) == "" { - return trace.BadParameter("empty cluster name") - } - - if len(r.Spec.ProxyName) == 0 { - return trace.BadParameter("missing parameter proxy name") - } - - return nil -} diff --git a/api/types/user.go b/api/types/user.go index 9e2f216f573..a564527f054 100644 --- a/api/types/user.go +++ b/api/types/user.go @@ -20,7 +20,6 @@ import ( "fmt" "time" - "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/utils" "github.com/gravitational/trace" @@ -58,8 +57,6 @@ type User interface { GetCreatedBy() CreatedBy // SetCreatedBy sets created by information SetCreatedBy(CreatedBy) - // Check checks basic user parameters for errors - Check() error // GetTraits gets the trait map for this user used to populate role variables. GetTraits() map[string][]string // GetTraits sets the trait map for this user used to populate role variables. @@ -69,11 +66,8 @@ type User interface { // NewUser creates new empty user func NewUser(name string) (User, error) { u := &UserV2{ - Kind: KindUser, - Version: V2, Metadata: Metadata{ - Name: name, - Namespace: defaults.Namespace, + Name: name, }, } if err := u.CheckAndSetDefaults(); err != nil { @@ -163,19 +157,23 @@ func (u *UserV2) SetTraits(traits map[string][]string) { u.Spec.Traits = traits } +// setStaticFields sets static resource header and metadata fields. +func (u *UserV2) setStaticFields() { + u.Kind = KindUser + u.Version = V2 +} + // CheckAndSetDefaults checks and set default values for any missing fields. func (u *UserV2) CheckAndSetDefaults() error { - err := u.Metadata.CheckAndSetDefaults() - if err != nil { + u.setStaticFields() + if err := u.Metadata.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if u.Version == "" { - u.Version = V2 - } - err = u.Check() - if err != nil { - return trace.Wrap(err) + for _, id := range u.Spec.OIDCIdentities { + if err := id.Check(); err != nil { + return trace.Wrap(err) + } } return nil @@ -261,25 +259,6 @@ func (u *UserV2) SetLocked(until time.Time, reason string) { u.Spec.Status.LockedMessage = reason } -// Check checks validity of all parameters -func (u *UserV2) Check() error { - if u.Kind == "" { - return trace.BadParameter("user kind is not set") - } - if u.Version == "" { - return trace.BadParameter("user version is not set") - } - if u.Metadata.Name == "" { - return trace.BadParameter("user name cannot be empty") - } - for _, id := range u.Spec.OIDCIdentities { - if err := id.Check(); err != nil { - return trace.Wrap(err) - } - } - return nil -} - // IsEmpty returns true if there's no info about who created this user func (c CreatedBy) IsEmpty() bool { return c.User.Name == "" diff --git a/e b/e index c77947fa5d5..e1d2a06454d 160000 --- a/e +++ b/e @@ -1 +1 @@ -Subproject commit c77947fa5d5b0ab0a8ad7a4b83ef1bacd2b458ec +Subproject commit e1d2a06454d5f00554defeb38d23b439bad11181 diff --git a/integration/app_integration_test.go b/integration/app_integration_test.go index 6b35113332a..41b0402ce56 100644 --- a/integration/app_integration_test.go +++ b/integration/app_integration_test.go @@ -747,9 +747,9 @@ func setupWithOptions(t *testing.T, opts appTestOptions) *pack { lcConf.SSH.Enabled = false lcConf.Apps.Enabled = false - err = p.leafCluster.CreateEx(p.rootCluster.Secrets.AsSlice(), lcConf) + err = p.leafCluster.CreateEx(t, p.rootCluster.Secrets.AsSlice(), lcConf) require.NoError(t, err) - err = p.rootCluster.CreateEx(p.leafCluster.Secrets.AsSlice(), rcConf) + err = p.rootCluster.CreateEx(t, p.leafCluster.Secrets.AsSlice(), rcConf) require.NoError(t, err) err = p.leafCluster.Start() diff --git a/integration/db_integration_test.go b/integration/db_integration_test.go index 8baaca12ecb..1875e09e3be 100644 --- a/integration/db_integration_test.go +++ b/integration/db_integration_test.go @@ -402,9 +402,9 @@ func setupDatabaseTest(t *testing.T, options ...testOptionFunc) *databasePack { lcConf.Clock = p.clock // Establish trust b/w root and leaf. - err = p.root.cluster.CreateEx(p.leaf.cluster.Secrets.AsSlice(), rcConf) + err = p.root.cluster.CreateEx(t, p.leaf.cluster.Secrets.AsSlice(), rcConf) require.NoError(t, err) - err = p.leaf.cluster.CreateEx(p.root.cluster.Secrets.AsSlice(), lcConf) + err = p.leaf.cluster.CreateEx(t, p.root.cluster.Secrets.AsSlice(), lcConf) require.NoError(t, err) // Start both clusters. diff --git a/integration/helpers.go b/integration/helpers.go index 6c16ef66fc7..94cd1526bee 100644 --- a/integration/helpers.go +++ b/integration/helpers.go @@ -34,6 +34,7 @@ import ( "strconv" "strings" "sync" + "testing" "time" "golang.org/x/crypto/ssh" @@ -57,6 +58,7 @@ import ( "github.com/gravitational/teleport/lib/teleagent" "github.com/gravitational/teleport/lib/tlsca" "github.com/gravitational/teleport/lib/utils" + "github.com/stretchr/testify/require" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" @@ -254,9 +256,9 @@ func NewInstance(cfg InstanceConfig) *TeleInstance { } // GetRoles returns a list of roles to initiate for this secret -func (s *InstanceSecrets) GetRoles() []types.Role { +func (s *InstanceSecrets) GetRoles(t *testing.T) []types.Role { var roles []types.Role - for _, ca := range s.GetCAs() { + for _, ca := range s.GetCAs(t) { if ca.GetType() != types.UserCA { continue } @@ -270,8 +272,8 @@ func (s *InstanceSecrets) GetRoles() []types.Role { // GetCAs return an array of CAs stored by the secrets object. In i // case we always return hard-coded userCA + hostCA (and they share keys // for simplicity) -func (s *InstanceSecrets) GetCAs() []types.CertAuthority { - hostCA := types.NewCertAuthority(types.CertAuthoritySpecV2{ +func (s *InstanceSecrets) GetCAs(t *testing.T) []types.CertAuthority { + hostCA, err := types.NewCertAuthority(types.CertAuthoritySpecV2{ Type: types.HostCA, ClusterName: s.SiteName, ActiveKeys: types.CAKeySet{ @@ -289,8 +291,9 @@ func (s *InstanceSecrets) GetCAs() []types.CertAuthority { Roles: []string{}, SigningAlg: types.CertAuthoritySpecV2_RSA_SHA2_512, }) + require.NoError(t, err) - userCA := types.NewCertAuthority(types.CertAuthoritySpecV2{ + userCA, err := types.NewCertAuthority(types.CertAuthoritySpecV2{ Type: types.UserCA, ClusterName: s.SiteName, ActiveKeys: types.CAKeySet{ @@ -308,6 +311,7 @@ func (s *InstanceSecrets) GetCAs() []types.CertAuthority { Roles: []string{services.RoleNameForCertAuthority(s.SiteName)}, SigningAlg: types.CertAuthoritySpecV2_RSA_SHA2_512, }) + require.NoError(t, err) return []types.CertAuthority{hostCA, userCA} } @@ -399,14 +403,14 @@ func (i *TeleInstance) GetSiteAPI(siteName string) auth.ClientI { // Create creates a new instance of Teleport which trusts a lsit of other clusters (other // instances) -func (i *TeleInstance) Create(trustedSecrets []*InstanceSecrets, enableSSH bool, console io.Writer) error { +func (i *TeleInstance) Create(t *testing.T, trustedSecrets []*InstanceSecrets, enableSSH bool, console io.Writer) error { tconf := service.MakeDefaultConfig() tconf.SSH.Enabled = enableSSH tconf.Console = console tconf.Log = i.log tconf.Proxy.DisableWebService = true tconf.Proxy.DisableWebInterface = true - return i.CreateEx(trustedSecrets, tconf) + return i.CreateEx(t, trustedSecrets, tconf) } // UserCreds holds user client credentials @@ -513,7 +517,7 @@ func GenerateUserCreds(req UserCredsRequest) (*UserCreds, error) { } // GenerateConfig generates instance config -func (i *TeleInstance) GenerateConfig(trustedSecrets []*InstanceSecrets, tconf *service.Config) (*service.Config, error) { +func (i *TeleInstance) GenerateConfig(t *testing.T, trustedSecrets []*InstanceSecrets, tconf *service.Config) (*service.Config, error) { var err error dataDir, err := ioutil.TempDir("", "cluster-"+i.Secrets.SiteName) if err != nil { @@ -551,16 +555,18 @@ func (i *TeleInstance) GenerateConfig(trustedSecrets []*InstanceSecrets, tconf * if err != nil { return nil, trace.Wrap(err) } - tconf.Auth.Authorities = append(tconf.Auth.Authorities, i.Secrets.GetCAs()...) + tconf.Auth.Authorities = append(tconf.Auth.Authorities, i.Secrets.GetCAs(t)...) tconf.Identities = append(tconf.Identities, i.Secrets.GetIdentity()) for _, trusted := range trustedSecrets { - tconf.Auth.Authorities = append(tconf.Auth.Authorities, trusted.GetCAs()...) - tconf.Auth.Roles = append(tconf.Auth.Roles, trusted.GetRoles()...) + tconf.Auth.Authorities = append(tconf.Auth.Authorities, trusted.GetCAs(t)...) + tconf.Auth.Roles = append(tconf.Auth.Roles, trusted.GetRoles(t)...) tconf.Identities = append(tconf.Identities, trusted.GetIdentity()) if trusted.ListenAddr != "" { - tconf.ReverseTunnels = []types.ReverseTunnel{ - types.NewReverseTunnel(trusted.SiteName, []string{trusted.ListenAddr}), + rt, err := types.NewReverseTunnel(trusted.SiteName, []string{trusted.ListenAddr}) + if err != nil { + return nil, trace.Wrap(err) } + tconf.ReverseTunnels = []types.ReverseTunnel{rt} } } tconf.Proxy.ReverseTunnelListenAddr.Addr = i.Secrets.ListenAddr @@ -616,9 +622,9 @@ func (i *TeleInstance) GenerateConfig(trustedSecrets []*InstanceSecrets, tconf * // // Unlike Create() it allows for greater customization because it accepts // a full Teleport config structure -func (i *TeleInstance) CreateEx(trustedSecrets []*InstanceSecrets, tconf *service.Config) error { +func (i *TeleInstance) CreateEx(t *testing.T, trustedSecrets []*InstanceSecrets, tconf *service.Config) error { ctx := context.TODO() - tconf, err := i.GenerateConfig(trustedSecrets, tconf) + tconf, err := i.GenerateConfig(t, trustedSecrets, tconf) if err != nil { return trace.Wrap(err) } @@ -1214,7 +1220,7 @@ func (i *TeleInstance) NewUnauthenticatedClient(cfg ClientConfig) (tc *client.Te // NewClient returns a fully configured and pre-authenticated client // (pre-authenticated with server CAs and signed session key) -func (i *TeleInstance) NewClient(cfg ClientConfig) (*client.TeleportClient, error) { +func (i *TeleInstance) NewClient(t *testing.T, cfg ClientConfig) (*client.TeleportClient, error) { tc, err := i.NewUnauthenticatedClient(cfg) if err != nil { return nil, trace.Wrap(err) @@ -1234,7 +1240,7 @@ func (i *TeleInstance) NewClient(cfg ClientConfig) (*client.TeleportClient, erro } // tell the client to trust given CAs (from secrets). this is the // equivalent of 'known hosts' in openssh - cas := i.Secrets.GetCAs() + cas := i.Secrets.GetCAs(t) for i := range cas { err = tc.AddTrustedCA(cas[i]) if err != nil { diff --git a/integration/integration_test.go b/integration/integration_test.go index 1bb4c646713..d2168501408 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -152,7 +152,7 @@ func (s *integrationTestSuite) newTeleportWithConfig(t *testing.T, logins []stri } // create a new teleport instance with passed in configuration - if err := teleport.CreateEx(instanceSecrets, teleportConfig); err != nil { + if err := teleport.CreateEx(t, instanceSecrets, teleportConfig); err != nil { t.Fatalf("Unexpected response from CreateEx: %v", trace.DebugReport(err)) } if err := teleport.Start(); err != nil { @@ -331,7 +331,7 @@ func testAuditOn(t *testing.T, suite *integrationTestSuite) { endC := make(chan error) myTerm := NewTerminal(250) go func() { - cl, err := teleport.NewClient(ClientConfig{ + cl, err := teleport.NewClient(t, ClientConfig{ Login: suite.me.Username, Cluster: Site, Host: Host, @@ -582,7 +582,7 @@ func testInteroperability(t *testing.T, suite *integrationTestSuite) { for _, tt := range tests { t.Run("", func(t *testing.T) { // create new teleport client - cl, err := teleport.NewClient(ClientConfig{Login: suite.me.Username, Cluster: Site, Host: Host, Port: teleport.GetPortSSHInt()}) + cl, err := teleport.NewClient(t, ClientConfig{Login: suite.me.Username, Cluster: Site, Host: Host, Port: teleport.GetPortSSHInt()}) require.NoError(t, err) // hook up stdin and stdout to a buffer for reading and writing @@ -644,7 +644,7 @@ func (s *integrationTestSuite) newUnstartedTeleport(t *testing.T, logins []strin for _, login := range logins { teleport.AddUser(login, []string{login}) } - require.NoError(t, teleport.Create(nil, enableSSH, nil)) + require.NoError(t, teleport.Create(t, nil, enableSSH, nil)) return teleport } @@ -777,14 +777,14 @@ func testUUIDBasedProxy(t *testing.T, suite *integrationTestSuite) { require.NoError(t, err) // attempting to run a command by hostname should generate NodeIsAmbiguous error. - _, err = runCommand(teleportSvr, []string{"echo", "Hello there!"}, ClientConfig{Login: suite.me.Username, Cluster: Site, Host: Host}, 1) + _, err = runCommand(t, teleportSvr, []string{"echo", "Hello there!"}, ClientConfig{Login: suite.me.Username, Cluster: Site, Host: Host}, 1) require.Error(t, err) if !strings.Contains(err.Error(), teleport.NodeIsAmbiguous) { require.FailNowf(t, "Expected %s, got %s", teleport.NodeIsAmbiguous, err.Error()) } // attempting to run a command by uuid should succeed. - _, err = runCommand(teleportSvr, []string{"echo", "Hello there!"}, ClientConfig{Login: suite.me.Username, Cluster: Site, Host: uuid1}, 1) + _, err = runCommand(t, teleportSvr, []string{"echo", "Hello there!"}, ClientConfig{Login: suite.me.Username, Cluster: Site, Host: uuid1}, 1) require.NoError(t, err) } @@ -855,7 +855,7 @@ func testCustomReverseTunnel(t *testing.T, suite *integrationTestSuite) { instanceConfig.MultiplexProxy = true main := NewInstance(instanceConfig) - require.NoError(t, main.CreateEx(nil, conf)) + require.NoError(t, main.CreateEx(t, nil, conf)) require.NoError(t, main.Start()) defer main.StopAll() @@ -889,7 +889,7 @@ func verifySessionJoin(t *testing.T, username string, teleport *TeleInstance) { // PersonA: SSH into the server, wait one second, then type some commands on stdin: sessionA := make(chan error) openSession := func() { - cl, err := teleport.NewClient(ClientConfig{Login: username, Cluster: Site, Host: Host}) + cl, err := teleport.NewClient(t, ClientConfig{Login: username, Cluster: Site, Host: Host}) if err != nil { sessionA <- trace.Wrap(err) return @@ -913,7 +913,7 @@ func verifySessionJoin(t *testing.T, username string, teleport *TeleInstance) { } sessionID := string(sessions[0].ID) - cl, err := teleport.NewClient(ClientConfig{Login: username, Cluster: Site, Host: Host}) + cl, err := teleport.NewClient(t, ClientConfig{Login: username, Cluster: Site, Host: Host}) if err != nil { sessionB <- trace.Wrap(err) return @@ -975,7 +975,7 @@ func testShutdown(t *testing.T, suite *integrationTestSuite) { // PersonA: SSH into the server, wait one second, then type some commands on stdin: openSession := func() { - cl, err := teleport.NewClient(ClientConfig{Login: suite.me.Username, Cluster: Site, Host: Host, Port: teleport.GetPortSSHInt()}) + cl, err := teleport.NewClient(t, ClientConfig{Login: suite.me.Username, Cluster: Site, Host: Host, Port: teleport.GetPortSSHInt()}) require.NoError(t, err) cl.Stdout = person cl.Stdin = person @@ -1184,7 +1184,7 @@ func runDisconnectTest(t *testing.T, suite *integrationTestSuite, tc disconnectT cfg.Proxy.Enabled = true cfg.SSH.Enabled = true - require.NoError(t, teleport.CreateEx(nil, cfg)) + require.NoError(t, teleport.CreateEx(t, nil, cfg)) require.NoError(t, teleport.Start()) defer teleport.StopAll() @@ -1205,7 +1205,7 @@ func runDisconnectTest(t *testing.T, suite *integrationTestSuite, tc disconnectT openSession := func() { defer cancel() - cl, err := teleport.NewClient(ClientConfig{Login: username, Cluster: Site, Host: Host, Port: teleport.GetPortSSHInt()}) + cl, err := teleport.NewClient(t, ClientConfig{Login: username, Cluster: Site, Host: Host, Port: teleport.GetPortSSHInt()}) require.NoError(t, err) cl.Stdout = person cl.Stdin = person @@ -1286,7 +1286,7 @@ func testEnvironmentVariables(t *testing.T, suite *integrationTestSuite) { cmd := []string{"printenv", testKey} // make sure sessions set run command - tc, err := teleport.NewClient(ClientConfig{Login: suite.me.Username, Cluster: Site, Host: Host, Port: teleport.GetPortSSHInt()}) + tc, err := teleport.NewClient(t, ClientConfig{Login: suite.me.Username, Cluster: Site, Host: Host, Port: teleport.GetPortSSHInt()}) require.NoError(t, err) tc.Env = map[string]string{testKey: testVal} @@ -1311,7 +1311,7 @@ func testInvalidLogins(t *testing.T, suite *integrationTestSuite) { cmd := []string{"echo", "success"} // try the wrong site: - tc, err := teleport.NewClient(ClientConfig{Login: suite.me.Username, Cluster: "wrong-site", Host: Host, Port: teleport.GetPortSSHInt()}) + tc, err := teleport.NewClient(t, ClientConfig{Login: suite.me.Username, Cluster: "wrong-site", Host: Host, Port: teleport.GetPortSSHInt()}) require.NoError(t, err) err = tc.SSH(context.TODO(), cmd, false) require.Regexp(t, "cluster wrong-site not found", err.Error()) @@ -1401,9 +1401,9 @@ func twoClustersTunnel(t *testing.T, suite *integrationTestSuite, now time.Time, bcfg.Proxy.DisableWebInterface = true bcfg.SSH.Enabled = false - require.NoError(t, b.CreateEx(a.Secrets.AsSlice(), bcfg)) + require.NoError(t, b.CreateEx(t, a.Secrets.AsSlice(), bcfg)) defer b.StopAll() - require.NoError(t, a.CreateEx(b.Secrets.AsSlice(), acfg)) + require.NoError(t, a.CreateEx(t, b.Secrets.AsSlice(), acfg)) defer a.StopAll() require.NoError(t, b.Start()) @@ -1429,7 +1429,7 @@ func twoClustersTunnel(t *testing.T, suite *integrationTestSuite, now time.Time, cmd := []string{"echo", "hello world"} // directly: - tc, err := a.NewClient(ClientConfig{ + tc, err := a.NewClient(t, ClientConfig{ Login: username, Cluster: a.Secrets.SiteName, Host: Host, @@ -1466,7 +1466,7 @@ func twoClustersTunnel(t *testing.T, suite *integrationTestSuite, now time.Time, waitForActiveTunnelConnections(t, b.Tunnel, a.Secrets.SiteName, 1) // via tunnel b->a: - tc, err = b.NewClient(ClientConfig{ + tc, err = b.NewClient(t, ClientConfig{ Login: username, Cluster: a.Secrets.SiteName, Host: Host, @@ -1566,9 +1566,9 @@ func testTwoClustersProxy(t *testing.T, suite *integrationTestSuite) { a.AddUser(username, []string{username}) b.AddUser(username, []string{username}) - require.NoError(t, b.Create(a.Secrets.AsSlice(), false, nil)) + require.NoError(t, b.Create(t, a.Secrets.AsSlice(), false, nil)) defer b.StopAll() - require.NoError(t, a.Create(b.Secrets.AsSlice(), true, nil)) + require.NoError(t, a.Create(t, b.Secrets.AsSlice(), true, nil)) defer a.StopAll() require.NoError(t, b.Start()) @@ -1603,8 +1603,8 @@ func testHA(t *testing.T, suite *integrationTestSuite) { a.AddUser(username, []string{username}) b.AddUser(username, []string{username}) - require.NoError(t, b.Create(a.Secrets.AsSlice(), true, nil)) - require.NoError(t, a.Create(b.Secrets.AsSlice(), true, nil)) + require.NoError(t, b.Create(t, a.Secrets.AsSlice(), true, nil)) + require.NoError(t, a.Create(t, b.Secrets.AsSlice(), true, nil)) require.NoError(t, b.Start()) require.NoError(t, a.Start()) @@ -1621,7 +1621,7 @@ func testHA(t *testing.T, suite *integrationTestSuite) { } cmd := []string{"echo", "hello world"} - tc, err := b.NewClient(ClientConfig{ + tc, err := b.NewClient(t, ClientConfig{ Login: username, Cluster: "cluster-a", Host: Loopback, @@ -1699,12 +1699,12 @@ func testMapRoles(t *testing.T, suite *integrationTestSuite) { // for role mapping test we turn on Web API on the main cluster // as it's used - makeConfig := func(enableSSH bool) ([]*InstanceSecrets, *service.Config) { + makeConfig := func(enableSSH bool) (*testing.T, []*InstanceSecrets, *service.Config) { tconf := suite.defaultServiceConfig() tconf.SSH.Enabled = enableSSH tconf.Proxy.DisableWebService = false tconf.Proxy.DisableWebInterface = true - return nil, tconf + return t, nil, tconf } lib.SetInsecureDevMode(true) defer lib.SetInsecureDevMode(false) @@ -1773,7 +1773,7 @@ func testMapRoles(t *testing.T, suite *integrationTestSuite) { require.Len(t, nodes, 2) cmd := []string{"echo", "hello world"} - tc, err := main.NewClient(ClientConfig{Login: username, Cluster: clusterAux, Host: Loopback, Port: sshPort}) + tc, err := main.NewClient(t, ClientConfig{Login: username, Cluster: clusterAux, Host: Loopback, Port: sshPort}) require.NoError(t, err) output := &bytes.Buffer{} tc.Stdout = output @@ -2024,12 +2024,12 @@ func trustedClusters(t *testing.T, suite *integrationTestSuite, test trustedClus // for role mapping test we turn on Web API on the main cluster // as it's used - makeConfig := func(enableSSH bool) ([]*InstanceSecrets, *service.Config) { + makeConfig := func(enableSSH bool) (*testing.T, []*InstanceSecrets, *service.Config) { tconf := suite.defaultServiceConfig() tconf.Proxy.DisableWebService = false tconf.Proxy.DisableWebInterface = true tconf.SSH.Enabled = enableSSH - return nil, tconf + return t, nil, tconf } lib.SetInsecureDevMode(true) defer lib.SetInsecureDevMode(false) @@ -2115,7 +2115,7 @@ func trustedClusters(t *testing.T, suite *integrationTestSuite, test trustedClus // tell the client to trust aux cluster CAs (from secrets). this is the // equivalent of 'known hosts' in openssh - auxCAS := aux.Secrets.GetCAs() + auxCAS := aux.Secrets.GetCAs(t) for i := range auxCAS { err = tc.AddTrustedCA(auxCAS[i]) require.NoError(t, err) @@ -2232,12 +2232,12 @@ func testTrustedTunnelNode(t *testing.T, suite *integrationTestSuite) { // for role mapping test we turn on Web API on the main cluster // as it's used - makeConfig := func(enableSSH bool) ([]*InstanceSecrets, *service.Config) { + makeConfig := func(enableSSH bool) (*testing.T, []*InstanceSecrets, *service.Config) { tconf := suite.defaultServiceConfig() tconf.Proxy.DisableWebService = false tconf.Proxy.DisableWebInterface = true tconf.SSH.Enabled = enableSSH - return nil, tconf + return t, nil, tconf } lib.SetInsecureDevMode(true) defer lib.SetInsecureDevMode(false) @@ -2315,7 +2315,7 @@ func testTrustedTunnelNode(t *testing.T, suite *integrationTestSuite) { // Try and connect to a node in the Aux cluster from the Main cluster using // direct dialing. - tc, err := main.NewClient(ClientConfig{ + tc, err := main.NewClient(t, ClientConfig{ Login: username, Cluster: clusterAux, Host: Loopback, @@ -2337,7 +2337,7 @@ func testTrustedTunnelNode(t *testing.T, suite *integrationTestSuite) { // Try and connect to a node in the Aux cluster from the Main cluster using // tunnel dialing. - tunnelClient, err := main.NewClient(ClientConfig{ + tunnelClient, err := main.NewClient(t, ClientConfig{ Login: username, Cluster: clusterAux, Host: tunnelNodeHostname, @@ -2383,13 +2383,13 @@ func testDiscoveryRecovers(t *testing.T, suite *integrationTestSuite) { remote.AddUser(username, []string{username}) main.AddUser(username, []string{username}) - require.NoError(t, main.Create(remote.Secrets.AsSlice(), false, nil)) + require.NoError(t, main.Create(t, remote.Secrets.AsSlice(), false, nil)) mainSecrets := main.Secrets // switch listen address of the main cluster to load balancer mainProxyAddr := *utils.MustParseAddr(mainSecrets.ListenAddr) lb.AddBackend(mainProxyAddr) mainSecrets.ListenAddr = frontend.String() - require.NoError(t, remote.Create(mainSecrets.AsSlice(), true, nil)) + require.NoError(t, remote.Create(t, mainSecrets.AsSlice(), true, nil)) require.NoError(t, main.Start()) require.NoError(t, remote.Start()) @@ -2448,7 +2448,7 @@ func testDiscoveryRecovers(t *testing.T, suite *integrationTestSuite) { Port: remote.GetPortSSHInt(), Proxy: conf, } - output, err := runCommand(main, []string{"echo", "hello world"}, clientConf, 10) + output, err := runCommand(t, main, []string{"echo", "hello world"}, clientConf, 10) if shouldFail { require.Error(t, err) } else { @@ -2516,13 +2516,13 @@ func testDiscovery(t *testing.T, suite *integrationTestSuite) { remote.AddUser(username, []string{username}) main.AddUser(username, []string{username}) - require.NoError(t, main.Create(remote.Secrets.AsSlice(), false, nil)) + require.NoError(t, main.Create(t, remote.Secrets.AsSlice(), false, nil)) mainSecrets := main.Secrets // switch listen address of the main cluster to load balancer mainProxyAddr := *utils.MustParseAddr(mainSecrets.ListenAddr) lb.AddBackend(mainProxyAddr) mainSecrets.ListenAddr = frontend.String() - require.NoError(t, remote.Create(mainSecrets.AsSlice(), true, nil)) + require.NoError(t, remote.Create(t, mainSecrets.AsSlice(), true, nil)) require.NoError(t, main.Start()) require.NoError(t, remote.Start()) @@ -2561,7 +2561,7 @@ func testDiscovery(t *testing.T, suite *integrationTestSuite) { Host: Loopback, Port: remote.GetPortSSHInt(), } - output, err := runCommand(main, []string{"echo", "hello world"}, cfg, 1) + output, err := runCommand(t, main, []string{"echo", "hello world"}, cfg, 1) require.NoError(t, err) require.Equal(t, "hello world\n", output) @@ -2576,7 +2576,7 @@ func testDiscovery(t *testing.T, suite *integrationTestSuite) { Port: remote.GetPortSSHInt(), Proxy: &proxyConfig, } - output, err = runCommand(main, []string{"echo", "hello world"}, cfgProxy, 10) + output, err = runCommand(t, main, []string{"echo", "hello world"}, cfgProxy, 10) require.NoError(t, err) require.Equal(t, "hello world\n", output) @@ -2585,11 +2585,11 @@ func testDiscovery(t *testing.T, suite *integrationTestSuite) { waitForActiveTunnelConnections(t, secondProxy, "cluster-remote", 1) // Requests going via main proxy should fail. - _, err = runCommand(main, []string{"echo", "hello world"}, cfg, 1) + _, err = runCommand(t, main, []string{"echo", "hello world"}, cfg, 1) require.Error(t, err) // Requests going via second proxy should succeed. - output, err = runCommand(main, []string{"echo", "hello world"}, cfgProxy, 1) + output, err = runCommand(t, main, []string{"echo", "hello world"}, cfgProxy, 1) require.NoError(t, err) require.Equal(t, "hello world\n", output) @@ -2604,7 +2604,7 @@ func testDiscovery(t *testing.T, suite *integrationTestSuite) { waitForActiveTunnelConnections(t, secondProxy, "cluster-remote", 1) // Requests going via main proxy should succeed. - output, err = runCommand(main, []string{"echo", "hello world"}, cfg, 40) + output, err = runCommand(t, main, []string{"echo", "hello world"}, cfg, 40) require.NoError(t, err) require.Equal(t, "hello world\n", output) @@ -2710,7 +2710,7 @@ func testDiscoveryNode(t *testing.T, suite *integrationTestSuite) { Cluster: Site, Host: "cluster-main-node", } - output, err := runCommand(main, []string{"echo", "hello world"}, cfg, 1) + output, err := runCommand(t, main, []string{"echo", "hello world"}, cfg, 1) require.NoError(t, err) require.Equal(t, "hello world\n", output) @@ -2725,7 +2725,7 @@ func testDiscoveryNode(t *testing.T, suite *integrationTestSuite) { Proxy: &proxyConfig, } - output, err = runCommand(main, []string{"echo", "hello world"}, cfgProxy, 10) + output, err = runCommand(t, main, []string{"echo", "hello world"}, cfgProxy, 10) require.NoError(t, err) require.Equal(t, "hello world\n", output) @@ -2735,10 +2735,10 @@ func testDiscoveryNode(t *testing.T, suite *integrationTestSuite) { // Requests going via main proxy will succeed. Requests going via second // proxy will fail. - output, err = runCommand(main, []string{"echo", "hello world"}, cfg, 1) + output, err = runCommand(t, main, []string{"echo", "hello world"}, cfg, 1) require.NoError(t, err) require.Equal(t, "hello world\n", output) - _, err = runCommand(main, []string{"echo", "hello world"}, cfgProxy, 1) + _, err = runCommand(t, main, []string{"echo", "hello world"}, cfgProxy, 1) require.Error(t, err) // Add second proxy to LB, both should have a connection. @@ -2747,10 +2747,10 @@ func testDiscoveryNode(t *testing.T, suite *integrationTestSuite) { waitForActiveTunnelConnections(t, proxyTunnel, Site, 1) // Requests going via both proxies will succeed. - output, err = runCommand(main, []string{"echo", "hello world"}, cfg, 1) + output, err = runCommand(t, main, []string{"echo", "hello world"}, cfg, 1) require.NoError(t, err) require.Equal(t, "hello world\n", output) - output, err = runCommand(main, []string{"echo", "hello world"}, cfgProxy, 40) + output, err = runCommand(t, main, []string{"echo", "hello world"}, cfgProxy, 40) require.NoError(t, err) require.Equal(t, "hello world\n", output) @@ -3121,7 +3121,7 @@ func testProxyHostKeyCheck(t *testing.T, suite *integrationTestSuite) { Port: nodePort, ForwardAgent: true, } - _, err = runCommand(teleport, []string{"echo hello"}, clientConfig, 1) + _, err = runCommand(t, teleport, []string{"echo hello"}, clientConfig, 1) // check if we were able to exec the command or not if tt.outError { @@ -3176,7 +3176,7 @@ func testAuditOff(t *testing.T, suite *integrationTestSuite) { myTerm := NewTerminal(250) go func() { - cl, err := teleport.NewClient(ClientConfig{ + cl, err := teleport.NewClient(t, ClientConfig{ Login: suite.me.Username, Cluster: Site, Host: Host, @@ -3352,7 +3352,7 @@ func testPAM(t *testing.T, suite *integrationTestSuite) { // Create an interactive session and write something to the terminal. ctx, cancel := context.WithCancel(context.Background()) go func() { - cl, err := teleport.NewClient(ClientConfig{ + cl, err := teleport.NewClient(t, ClientConfig{ Login: suite.me.Username, Cluster: Site, Host: Host, @@ -3407,7 +3407,7 @@ func testRotateSuccess(t *testing.T, suite *integrationTestSuite) { } tconf := suite.rotationConfig(true) - config, err := teleport.GenerateConfig(nil, tconf) + config, err := teleport.GenerateConfig(t, nil, tconf) require.NoError(t, err) serviceC := make(chan *service.TeleportProcess, 20) @@ -3557,7 +3557,7 @@ func testRotateRollback(t *testing.T, s *integrationTestSuite) { for _, login := range logins { teleport.AddUser(login, []string{login}) } - config, err := teleport.GenerateConfig(nil, tconf) + config, err := teleport.GenerateConfig(t, nil, tconf) require.NoError(t, err) serviceC := make(chan *service.TeleportProcess, 20) @@ -3686,7 +3686,7 @@ func testRotateTrustedClusters(t *testing.T, suite *integrationTestSuite) { for _, login := range logins { main.AddUser(login, []string{login}) } - config, err := main.GenerateConfig(nil, tconf) + config, err := main.GenerateConfig(t, nil, tconf) require.NoError(t, err) serviceC := make(chan *service.TeleportProcess, 20) @@ -3717,7 +3717,7 @@ func testRotateTrustedClusters(t *testing.T, suite *integrationTestSuite) { require.NoError(t, err) // create auxiliary cluster and setup trust - require.NoError(t, aux.CreateEx(nil, suite.rotationConfig(false))) + require.NoError(t, aux.CreateEx(t, nil, suite.rotationConfig(false))) // auxiliary cluster has a role aux-devs // connect aux cluster to main cluster @@ -3895,7 +3895,7 @@ func testRotateChangeSigningAlg(t *testing.T, suite *integrationTestSuite) { for _, login := range logins { teleport.AddUser(login, []string{login}) } - config, err := teleport.GenerateConfig(nil, tconf) + config, err := teleport.GenerateConfig(t, nil, tconf) require.NoError(t, err) serviceC := make(chan *service.TeleportProcess, 20) @@ -4151,7 +4151,7 @@ func testWindowChange(t *testing.T, suite *integrationTestSuite) { // openSession will open a new session on a server. openSession := func() { - cl, err := teleport.NewClient(ClientConfig{ + cl, err := teleport.NewClient(t, ClientConfig{ Login: suite.me.Username, Cluster: Site, Host: Host, @@ -4175,7 +4175,7 @@ func testWindowChange(t *testing.T, suite *integrationTestSuite) { require.NoError(t, err) sessionID := string(sessions[0].ID) - cl, err := teleport.NewClient(ClientConfig{ + cl, err := teleport.NewClient(t, ClientConfig{ Login: suite.me.Username, Cluster: Site, Host: Host, @@ -4479,7 +4479,7 @@ func testCmdLabels(t *testing.T, suite *integrationTestSuite) { Labels: tt.labels, } - output, err := runCommand(teleport, tt.command, cfg, 1) + output, err := runCommand(t, teleport, tt.command, cfg, 1) require.NoError(t, err) require.Equal(t, tt.expect, output) }) @@ -4509,7 +4509,7 @@ func testDataTransfer(t *testing.T, suite *integrationTestSuite) { // Write 1 MB to stdout. command := []string{"dd", "if=/dev/zero", "bs=1024", "count=1024"} - output, err := runCommand(main, command, clientConfig, 1) + output, err := runCommand(t, main, command, clientConfig, 1) require.NoError(t, err) // Make sure exactly 1 MB was written to output. @@ -4611,7 +4611,7 @@ func testBPFInteractive(t *testing.T, suite *integrationTestSuite) { doneContext, doneCancel := context.WithCancel(context.Background()) func() { - client, err := main.NewClient(ClientConfig{ + client, err := main.NewClient(t, ClientConfig{ Login: suite.me.Username, Cluster: Site, Host: Host, @@ -4742,7 +4742,7 @@ func testBPFExec(t *testing.T, suite *integrationTestSuite) { } // Run exec command. - _, err = runCommand(main, []string{lsPath}, clientConfig, 1) + _, err = runCommand(t, main, []string{lsPath}, clientConfig, 1) require.NoError(t, err) // Enhanced events should show up for session recorded at the node but not @@ -4816,7 +4816,7 @@ func testBPFSessionDifferentiation(t *testing.T, suite *integrationTestSuite) { // Open a terminal and type "ls" into both and exit. writeTerm := func(term *Terminal) { - client, err := main.NewClient(ClientConfig{ + client, err := main.NewClient(t, ClientConfig{ Login: suite.me.Username, Cluster: Site, Host: Host, @@ -4920,7 +4920,7 @@ func testExecEvents(t *testing.T, suite *integrationTestSuite) { Port: main.GetPortSSHInt(), Interactive: tt.isInteractive, } - _, err := runCommand(main, []string{lsPath}, clientConfig, 1) + _, err := runCommand(t, main, []string{lsPath}, clientConfig, 1) require.NoError(t, err) // Make sure the exec event was emitted to the audit log. @@ -5032,7 +5032,7 @@ func testSessionStartContainsAccessRequest(t *testing.T, suite *integrationTestS clientReissueParams := client.ReissueParams{ AccessRequests: []string{accessRequestID}, } - err = runCommandWithCertReissue(main, []string{lsPath}, clientReissueParams, client.CertCacheDrop, clientConfig) + err = runCommandWithCertReissue(t, main, []string{lsPath}, clientReissueParams, client.CertCacheDrop, clientConfig) require.NoError(t, err) // Get session start event @@ -5146,8 +5146,8 @@ func eventsInLog(path string, eventName string) ([]events.EventFields, error) { } // runCommandWithCertReissue runs an SSH command and generates certificates for the user -func runCommandWithCertReissue(instance *TeleInstance, cmd []string, reissueParams client.ReissueParams, cachePolicy client.CertCachePolicy, cfg ClientConfig) error { - tc, err := instance.NewClient(cfg) +func runCommandWithCertReissue(t *testing.T, instance *TeleInstance, cmd []string, reissueParams client.ReissueParams, cachePolicy client.CertCachePolicy, cfg ClientConfig) error { + tc, err := instance.NewClient(t, cfg) if err != nil { return trace.Wrap(err) } @@ -5171,8 +5171,8 @@ func runCommandWithCertReissue(instance *TeleInstance, cmd []string, reissuePara // connected to proxy of the passed in instance, runs the command, and returns // the result. If multiple attempts are requested, a 250 millisecond delay is // added between them before giving up. -func runCommand(instance *TeleInstance, cmd []string, cfg ClientConfig, attempts int) (string, error) { - tc, err := instance.NewClient(cfg) +func runCommand(t *testing.T, instance *TeleInstance, cmd []string, cfg ClientConfig, attempts int) (string, error) { + tc, err := instance.NewClient(t, cfg) if err != nil { return "", trace.Wrap(err) } @@ -5327,7 +5327,7 @@ func TestWebProxyInsecure(t *testing.T) { // DisableTLS flag should turn off TLS termination and multiplexing. rcConf.Proxy.DisableTLS = true - err = rc.CreateEx(nil, rcConf) + err = rc.CreateEx(t, nil, rcConf) require.NoError(t, err) err = rc.Start() @@ -5411,9 +5411,9 @@ func TestTraitsPropagation(t *testing.T) { lc.AddUserWithRole(me.Username, role) // Establish trust b/w root and leaf. - err = rc.CreateEx(lc.Secrets.AsSlice(), rcConf) + err = rc.CreateEx(t, lc.Secrets.AsSlice(), rcConf) require.NoError(t, err) - err = lc.CreateEx(rc.Secrets.AsSlice(), lcConf) + err = lc.CreateEx(t, rc.Secrets.AsSlice(), lcConf) require.NoError(t, err) // Start both clusters. @@ -5438,7 +5438,7 @@ func TestTraitsPropagation(t *testing.T) { require.NoError(t, err) // Run command in root. - outputRoot, err := runCommand(rc, []string{"echo", "hello root"}, ClientConfig{ + outputRoot, err := runCommand(t, rc, []string{"echo", "hello root"}, ClientConfig{ Login: me.Username, Cluster: "root.example.com", Host: Loopback, @@ -5448,7 +5448,7 @@ func TestTraitsPropagation(t *testing.T) { require.Equal(t, "hello root", strings.TrimSpace(outputRoot)) // Run command in leaf. - outputLeaf, err := runCommand(rc, []string{"echo", "hello leaf"}, ClientConfig{ + outputLeaf, err := runCommand(t, rc, []string{"echo", "hello leaf"}, ClientConfig{ Login: me.Username, Cluster: "leaf.example.com", Host: Loopback, diff --git a/integration/kube_integration_test.go b/integration/kube_integration_test.go index 6fb24b6d1d1..bb12b857f7c 100644 --- a/integration/kube_integration_test.go +++ b/integration/kube_integration_test.go @@ -192,7 +192,7 @@ func testKubeExec(t *testing.T, suite *KubeSuite) { require.NoError(t, err) teleport.AddUserWithRole(username, role) - err = teleport.CreateEx(nil, tconf) + err = teleport.CreateEx(t, nil, tconf) require.NoError(t, err) err = teleport.Start() @@ -366,7 +366,7 @@ func testKubeDeny(t *testing.T, suite *KubeSuite) { require.NoError(t, err) teleport.AddUserWithRole(username, role) - err = teleport.CreateEx(nil, tconf) + err = teleport.CreateEx(t, nil, tconf) require.NoError(t, err) err = teleport.Start() @@ -413,7 +413,7 @@ func testKubePortForward(t *testing.T, suite *KubeSuite) { require.NoError(t, err) teleport.AddUserWithRole(username, role) - err = teleport.CreateEx(nil, tconf) + err = teleport.CreateEx(t, nil, tconf) require.NoError(t, err) err = teleport.Start() @@ -526,10 +526,10 @@ func testKubeTrustedClustersClientCert(t *testing.T, suite *KubeSuite) { defer lib.SetInsecureDevMode(false) mainConf.Proxy.Kube.Enabled = true - err = main.CreateEx(nil, mainConf) + err = main.CreateEx(t, nil, mainConf) require.NoError(t, err) - err = aux.CreateEx(nil, auxConf) + err = aux.CreateEx(t, nil, auxConf) require.NoError(t, err) // auxiliary cluster has a role aux-kube @@ -784,10 +784,10 @@ func testKubeTrustedClustersSNI(t *testing.T, suite *KubeSuite) { // ClusterOverride forces connection to be routed // to cluster aux mainConf.Proxy.Kube.ClusterOverride = clusterAux - err = main.CreateEx(nil, mainConf) + err = main.CreateEx(t, nil, mainConf) require.NoError(t, err) - err = aux.CreateEx(nil, auxConf) + err = aux.CreateEx(t, nil, auxConf) require.NoError(t, err) // auxiliary cluster has a role aux-kube @@ -1045,7 +1045,7 @@ func runKubeDisconnectTest(t *testing.T, suite *KubeSuite, tc disconnectTestCase require.NoError(t, err) teleport.AddUserWithRole(username, role) - err = teleport.CreateEx(nil, tconf) + err = teleport.CreateEx(t, nil, tconf) require.NoError(t, err) err = teleport.Start() diff --git a/integration/port_forwarding_test.go b/integration/port_forwarding_test.go index a391258e09d..34a558f5cec 100644 --- a/integration/port_forwarding_test.go +++ b/integration/port_forwarding_test.go @@ -125,7 +125,7 @@ func testPortForwarding(t *testing.T, suite *integrationTestSuite) { require.NoError(t, err) nodeSSHPort := teleport.GetPortSSHInt() - cl, err := teleport.NewClient(ClientConfig{ + cl, err := teleport.NewClient(t, ClientConfig{ Login: suite.me.Username, Cluster: Site, Host: Host, diff --git a/lib/auth/auth.go b/lib/auth/auth.go index 50b414bdf76..19db268ba70 100644 --- a/lib/auth/auth.go +++ b/lib/auth/auth.go @@ -1746,7 +1746,12 @@ func (a *Server) NewWebSession(req types.NewWebSessionRequest) (types.WebSession LoginTime: req.LoginTime, } UserLoginCount.Inc() - return types.NewWebSession(token, types.KindWebSession, types.KindWebSession, sessionSpec), nil + + sess, err := types.NewWebSession(token, types.KindWebSession, sessionSpec) + if err != nil { + return nil, trace.Wrap(err) + } + return sess, nil } // GetWebSessionInfo returns the web session specified with sessionID for the given user. @@ -2450,10 +2455,13 @@ func (a *Server) upsertWebSession(ctx context.Context, user string, session type if err := a.WebSessions().Upsert(ctx, session); err != nil { return trace.Wrap(err) } - token := types.NewWebToken(session.GetBearerTokenExpiryTime(), types.WebTokenSpecV3{ + token, err := types.NewWebToken(session.GetBearerTokenExpiryTime(), types.WebTokenSpecV3{ User: session.GetUser(), Token: session.GetBearerToken(), }) + if err != nil { + return trace.Wrap(err) + } if err := a.WebTokens().Upsert(ctx, token); err != nil { return trace.Wrap(err) } diff --git a/lib/auth/auth_test.go b/lib/auth/auth_test.go index 49faee7f31c..41864095b43 100644 --- a/lib/auth/auth_test.go +++ b/lib/auth/auth_test.go @@ -127,7 +127,7 @@ func (s *AuthSuite) SetUpTest(c *C) { err = s.a.SetSessionRecordingConfig(ctx, types.DefaultSessionRecordingConfig()) c.Assert(err, IsNil) - err = s.a.SetClusterConfig(services.DefaultClusterConfig()) + err = s.a.SetClusterConfig(types.DefaultClusterConfig()) c.Assert(err, IsNil) s.mockEmitter = &events.MockEmitter{} @@ -975,8 +975,9 @@ func (s *AuthSuite) TestTrustedClusterCRUDEventEmitted(c *C) { func (s *AuthSuite) TestGithubConnectorCRUDEventsEmitted(c *C) { ctx := context.Background() // test github create event - github := types.NewGithubConnector("test", types.GithubConnectorSpecV3{}) - err := s.a.upsertGithubConnector(ctx, github) + github, err := types.NewGithubConnector("test", types.GithubConnectorSpecV3{}) + c.Assert(err, IsNil) + err = s.a.upsertGithubConnector(ctx, github) c.Assert(err, IsNil) c.Assert(s.mockEmitter.LastEvent().GetType(), DeepEquals, events.GithubConnectorCreatedEvent) s.mockEmitter.Reset() @@ -996,8 +997,9 @@ func (s *AuthSuite) TestGithubConnectorCRUDEventsEmitted(c *C) { func (s *AuthSuite) TestOIDCConnectorCRUDEventsEmitted(c *C) { ctx := context.Background() // test oidc create event - oidc := types.NewOIDCConnector("test", types.OIDCConnectorSpecV2{ClientID: "a"}) - err := s.a.UpsertOIDCConnector(ctx, oidc) + oidc, err := types.NewOIDCConnector("test", types.OIDCConnectorSpecV2{ClientID: "a"}) + c.Assert(err, IsNil) + err = s.a.UpsertOIDCConnector(ctx, oidc) c.Assert(err, IsNil) c.Assert(s.mockEmitter.LastEvent().GetType(), DeepEquals, events.OIDCConnectorCreatedEvent) s.mockEmitter.Reset() @@ -1033,12 +1035,13 @@ func (s *AuthSuite) TestSAMLConnectorCRUDEventsEmitted(c *C) { c.Assert(err, IsNil) // test saml create - saml := types.NewSAMLConnector("test", types.SAMLConnectorSpecV2{ + saml, err := types.NewSAMLConnector("test", types.SAMLConnectorSpecV2{ AssertionConsumerService: "a", Issuer: "b", SSO: "c", Cert: string(certBytes), }) + c.Assert(err, IsNil) err = s.a.UpsertSAMLConnector(ctx, saml) c.Assert(err, IsNil) diff --git a/lib/auth/grpcserver_test.go b/lib/auth/grpcserver_test.go index 68320cb8c27..f3a94244d3d 100644 --- a/lib/auth/grpcserver_test.go +++ b/lib/auth/grpcserver_test.go @@ -584,12 +584,14 @@ func TestGenerateUserSingleUseCert(t *testing.T) { err = srv.Auth().UpsertKubeService(ctx, k8sSrv) require.NoError(t, err) // Register a database. - db := types.NewDatabaseServerV3("db-a", nil, types.DatabaseServerSpecV3{ + db, err := types.NewDatabaseServerV3("db-a", nil, types.DatabaseServerSpecV3{ Protocol: "postgres", URI: "localhost", Hostname: "localhost", HostID: "localhost", }) + require.NoError(t, err) + _, err = srv.Auth().UpsertDatabaseServer(ctx, db) require.NoError(t, err) diff --git a/lib/auth/helpers.go b/lib/auth/helpers.go index ba2eac3f3a5..d045f960ccd 100644 --- a/lib/auth/helpers.go +++ b/lib/auth/helpers.go @@ -255,7 +255,7 @@ func NewTestAuthServer(cfg TestAuthServerConfig) (*TestAuthServer, error) { return nil, trace.Wrap(err) } - err = srv.AuthServer.SetClusterConfig(services.DefaultClusterConfig()) + err = srv.AuthServer.SetClusterConfig(types.DefaultClusterConfig()) if err != nil { return nil, trace.Wrap(err) } diff --git a/lib/auth/init.go b/lib/auth/init.go index 34711a7040f..f4afbb30f47 100644 --- a/lib/auth/init.go +++ b/lib/auth/init.go @@ -299,7 +299,7 @@ func Init(cfg InitConfig, opts ...ServerOption) (*Server, error) { log.Infof("Updating cluster configuration: %v.", cfg.StaticTokens) // always create the default namespace - err = asrv.UpsertNamespace(types.NewNamespace(apidefaults.Namespace)) + err = asrv.UpsertNamespace(types.DefaultNamespace()) if err != nil { return nil, trace.Wrap(err) } diff --git a/lib/auth/init_test.go b/lib/auth/init_test.go index 861b9a1650e..996ddd3ef2d 100644 --- a/lib/auth/init_test.go +++ b/lib/auth/init_test.go @@ -770,7 +770,7 @@ func TestMigrateOSS(t *testing.T) { err := as.CreateRole(services.NewAdminRole()) require.NoError(t, err) - connector := types.NewGithubConnector("github", types.GithubConnectorSpecV3{ + connector, err := types.NewGithubConnector("github", types.GithubConnectorSpecV3{ ClientID: "aaa", ClientSecret: "bbb", RedirectURL: "https://localhost:3080/v1/webapi/github/callback", @@ -791,6 +791,7 @@ func TestMigrateOSS(t *testing.T) { }, }, }) + require.NoError(t, err) err = as.CreateGithubConnector(connector) require.NoError(t, err) @@ -876,12 +877,12 @@ func setupConfig(t *testing.T) InitConfig { NodeName: "foo", Backend: bk, Authority: testauthority.New(), - ClusterConfig: services.DefaultClusterConfig(), ClusterAuditConfig: types.DefaultClusterAuditConfig(), + ClusterConfig: types.DefaultClusterConfig(), ClusterNetworkingConfig: types.DefaultClusterNetworkingConfig(), SessionRecordingConfig: types.DefaultSessionRecordingConfig(), ClusterName: clusterName, - StaticTokens: services.DefaultStaticTokens(), + StaticTokens: types.DefaultStaticTokens(), AuthPreference: types.DefaultAuthPreference(), SkipPeriodicOperations: true, } @@ -940,7 +941,8 @@ func TestMigrateCertAuthorities(t *testing.T) { }, } { t.Run(fmt.Sprintf("create %v CA", spec.Type), func(t *testing.T) { - ca := types.NewCertAuthority(spec) + ca, err := types.NewCertAuthority(spec) + require.NoError(t, err) // Do NOT use services.MarshalCertAuthority to keep all fields as-is. enc, err := utils.FastMarshal(ca) require.NoError(t, err) diff --git a/lib/auth/oidc_test.go b/lib/auth/oidc_test.go index 684e574cbda..013109103c4 100644 --- a/lib/auth/oidc_test.go +++ b/lib/auth/oidc_test.go @@ -99,11 +99,12 @@ func (s *OIDCSuite) TestUserInfo(c *check.C) { defer idp.Close() // Create OIDC connector and client. - connector := types.NewOIDCConnector("test-connector", types.OIDCConnectorSpecV2{ + connector, err := types.NewOIDCConnector("test-connector", types.OIDCConnectorSpecV2{ IssuerURL: idp.s.URL, ClientID: "00000000000000000000000000000000", ClientSecret: "0000000000000000000000000000000000000000000000000000000000000000", }) + c.Assert(err, check.IsNil) oidcClient, err := s.a.getOrCreateOIDCClient(connector) c.Assert(err, check.IsNil) diff --git a/lib/auth/resetpasswordtoken.go b/lib/auth/resetpasswordtoken.go index dca9e8ff427..9a1c294b694 100644 --- a/lib/auth/resetpasswordtoken.go +++ b/lib/auth/resetpasswordtoken.go @@ -303,7 +303,11 @@ func (s *Server) newResetPasswordToken(req CreateResetPasswordTokenRequest) (typ return nil, trace.Wrap(err) } - token := types.NewResetPasswordToken(tokenID) + token, err := types.NewResetPasswordToken(tokenID) + if err != nil { + return nil, trace.Wrap(err) + } + token.SetExpiry(s.clock.Now().UTC().Add(req.TTL)) token.SetUser(req.Name) token.SetCreated(s.clock.Now().UTC()) diff --git a/lib/auth/saml_test.go b/lib/auth/saml_test.go index 03664e5ae82..0700b6b3bb6 100644 --- a/lib/auth/saml_test.go +++ b/lib/auth/saml_test.go @@ -113,14 +113,15 @@ func TestEncryptedSAML(t *testing.T) { PrivateKey: fixtures.EncryptionKeyPEM, } - connector := types.NewSAMLConnector("spongebob", types.SAMLConnectorSpecV2{ - Cert: signingKeypair.Cert, + connector, err := types.NewSAMLConnector("spongebob", types.SAMLConnectorSpecV2{ + Cert: signingKeypair.Cert, + Issuer: "http://idp.example.com/metadata.php", + SSO: "nil", + AssertionConsumerService: "http://sp.example.com/demo1/index.php?acs", + EntityDescriptor: EntityDescriptor, }) + require.NoError(t, err) - connector.SetEntityDescriptor(EntityDescriptor) - connector.SetIssuer("http://idp.example.com/metadata.php") - connector.SetSSO("nil") - connector.SetAssertionConsumerService("http://sp.example.com/demo1/index.php?acs") connector.SetSigningKeyPair(signingKeypair) connector.SetEncryptionKeyPair(encryptionKeypair) @@ -187,7 +188,7 @@ func TestPingSAMLWorkaround(t *testing.T) { PrivateKey: fixtures.EncryptionKeyPEM, } - connector := types.NewSAMLConnector("ping", types.SAMLConnectorSpecV2{ + connector, err := types.NewSAMLConnector("ping", types.SAMLConnectorSpecV2{ AssertionConsumerService: "https://proxy.example.com:3080/v1/webapi/saml/acs", Provider: "ping", Display: "Ping", @@ -198,6 +199,7 @@ func TestPingSAMLWorkaround(t *testing.T) { SigningKeyPair: signingKeypair, EncryptionKeyPair: encryptionKeypair, }) + require.NoError(t, err) err = a.UpsertSAMLConnector(context.Background(), connector) require.NoError(t, err) diff --git a/lib/auth/sessions.go b/lib/auth/sessions.go index 45ff076dc3f..4719bfe4386 100644 --- a/lib/auth/sessions.go +++ b/lib/auth/sessions.go @@ -87,13 +87,16 @@ func (s *Server) CreateAppSession(ctx context.Context, req types.CreateAppSessio if err != nil { return nil, trace.Wrap(err) } - session := types.NewWebSession(sessionID, types.KindWebSession, types.KindAppSession, types.WebSessionSpecV2{ + session, err := types.NewWebSession(sessionID, types.KindAppSession, types.WebSessionSpecV2{ User: req.Username, Priv: privateKey, Pub: certs.ssh, TLSCert: certs.tls, Expires: s.clock.Now().Add(ttl), }) + if err != nil { + return nil, trace.Wrap(err) + } if err = s.Identity.UpsertAppSession(ctx, session); err != nil { return nil, trace.Wrap(err) } diff --git a/lib/auth/trustedcluster.go b/lib/auth/trustedcluster.go index e9750034d06..6713b41636b 100644 --- a/lib/auth/trustedcluster.go +++ b/lib/auth/trustedcluster.go @@ -703,9 +703,12 @@ func (a *Server) deactivateCertAuthority(t types.TrustedCluster) error { // createReverseTunnel will create a services.ReverseTunnel givenin the // services.TrustedCluster resource. func (a *Server) createReverseTunnel(t types.TrustedCluster) error { - reverseTunnel := types.NewReverseTunnel( + reverseTunnel, err := types.NewReverseTunnel( t.GetName(), []string{t.GetReverseTunnelAddress()}, ) + if err != nil { + return trace.Wrap(err) + } return trace.Wrap(a.UpsertReverseTunnel(reverseTunnel)) } diff --git a/lib/auth/trustedcluster_test.go b/lib/auth/trustedcluster_test.go index f7853aa9211..2b66080b3b8 100644 --- a/lib/auth/trustedcluster_test.go +++ b/lib/auth/trustedcluster_test.go @@ -112,7 +112,7 @@ func newTestAuthServer(ctx context.Context, t *testing.T, name ...string) *Serve require.NoError(t, a.SetClusterNetworkingConfig(ctx, types.DefaultClusterNetworkingConfig())) require.NoError(t, a.SetSessionRecordingConfig(ctx, types.DefaultSessionRecordingConfig())) require.NoError(t, a.SetAuthPreference(ctx, types.DefaultAuthPreference())) - require.NoError(t, a.SetClusterConfig(services.DefaultClusterConfig())) + require.NoError(t, a.SetClusterConfig(types.DefaultClusterConfig())) return a } diff --git a/lib/cache/cache_test.go b/lib/cache/cache_test.go index ea85ecd0c08..bf1f0e4bb4a 100644 --- a/lib/cache/cache_test.go +++ b/lib/cache/cache_test.go @@ -918,7 +918,7 @@ func (s *CacheSuite) TestClusterConfig(c *check.C) { c.Fatalf("timeout waiting for event") } - err = p.clusterConfigS.SetClusterConfig(services.DefaultClusterConfig()) + err = p.clusterConfigS.SetClusterConfig(types.DefaultClusterConfig()) c.Assert(err, check.IsNil) clusterConfig, err := p.clusterConfigS.GetClusterConfig() @@ -948,9 +948,10 @@ func (s *CacheSuite) TestNamespaces(c *check.C) { p := s.newPackForProxy(c) defer p.Close() - v := types.NewNamespace("universe") + v, err := types.NewNamespace("universe") + c.Assert(err, check.IsNil) ns := &v - err := p.presenceS.UpsertNamespace(*ns) + err = p.presenceS.UpsertNamespace(*ns) c.Assert(err, check.IsNil) ns, err = p.presenceS.GetNamespace(ns.GetName()) @@ -1136,10 +1137,10 @@ func (s *CacheSuite) TestReverseTunnels(c *check.C) { p := s.newPackForProxy(c) defer p.Close() - tunnel := types.NewReverseTunnel("example.com", []string{"example.com:2023"}) + tunnel, err := types.NewReverseTunnel("example.com", []string{"example.com:2023"}) + c.Assert(err, check.IsNil) c.Assert(p.presenceS.UpsertReverseTunnel(tunnel), check.IsNil) - var err error tunnel, err = p.presenceS.GetReverseTunnel(tunnel.GetName()) c.Assert(err, check.IsNil) @@ -1662,13 +1663,15 @@ func TestDatabaseServers(t *testing.T) { ctx := context.Background() // Upsert database server into backend. - server := types.NewDatabaseServerV3("foo", nil, + server, err := types.NewDatabaseServerV3("foo", nil, types.DatabaseServerSpecV3{ Protocol: defaults.ProtocolPostgres, URI: "localhost:5432", Hostname: "localhost", HostID: uuid.New(), }) + require.NoError(t, err) + _, err = p.presenceS.UpsertDatabaseServer(ctx, server) require.NoError(t, err) diff --git a/lib/config/configuration.go b/lib/config/configuration.go index f2d3e8068ce..679ee5266cf 100644 --- a/lib/config/configuration.go +++ b/lib/config/configuration.go @@ -980,7 +980,7 @@ func parseAuthorizedKeys(bytes []byte, allowedLogins []string) (types.CertAuthor } // create a new certificate authority - ca := types.NewCertAuthority(types.CertAuthoritySpecV2{ + ca, err := types.NewCertAuthority(types.CertAuthoritySpecV2{ Type: types.UserCA, ClusterName: clusterName, ActiveKeys: types.CAKeySet{ @@ -991,6 +991,9 @@ func parseAuthorizedKeys(bytes []byte, allowedLogins []string) (types.CertAuthor Roles: nil, SigningAlg: types.CertAuthoritySpecV2_UNKNOWN, }) + if err != nil { + return nil, nil, trace.Wrap(err) + } // transform old allowed logins into roles role := services.RoleForCertAuthority(ca) @@ -1024,7 +1027,7 @@ func parseKnownHosts(bytes []byte, allowedLogins []string) (types.CertAuthority, const prefix = "*." domainName := strings.TrimPrefix(options[0], prefix) - ca := types.NewCertAuthority(types.CertAuthoritySpecV2{ + ca, err := types.NewCertAuthority(types.CertAuthoritySpecV2{ Type: authType, ClusterName: domainName, ActiveKeys: types.CAKeySet{ @@ -1033,6 +1036,9 @@ func parseKnownHosts(bytes []byte, allowedLogins []string) (types.CertAuthority, }}, }, }) + if err != nil { + return nil, nil, trace.Wrap(err) + } // transform old allowed logins into roles role := services.RoleForCertAuthority(ca) @@ -1135,7 +1141,11 @@ func readTrustedClusters(clusters []TrustedCluster, conf *service.Config) error tunnelAddresses = append(tunnelAddresses, addr.FullAddress()) } if len(tunnelAddresses) > 0 { - conf.ReverseTunnels = append(conf.ReverseTunnels, types.NewReverseTunnel(clusterName, tunnelAddresses)) + rt, err := types.NewReverseTunnel(clusterName, tunnelAddresses) + if err != nil { + return trace.Wrap(err) + } + conf.ReverseTunnels = append(conf.ReverseTunnels, rt) } } return nil diff --git a/lib/config/fileconf.go b/lib/config/fileconf.go index 9469c3698a9..61fa9d5bbca 100644 --- a/lib/config/fileconf.go +++ b/lib/config/fileconf.go @@ -958,7 +958,10 @@ func (t *ReverseTunnel) ConvertAndValidate() (types.ReverseTunnel, error) { t.Addresses[i] = addr.String() } - out := types.NewReverseTunnel(t.DomainName, t.Addresses) + out, err := types.NewReverseTunnel(t.DomainName, t.Addresses) + if err != nil { + return nil, trace.Wrap(err) + } if err := services.ValidateReverseTunnel(out); err != nil { return nil, trace.Wrap(err) } @@ -1026,7 +1029,7 @@ func (o *OIDCConnector) Parse() (types.OIDCConnector, error) { }) } - v2 := types.NewOIDCConnector(o.ID, types.OIDCConnectorSpecV2{ + v2, err := types.NewOIDCConnector(o.ID, types.OIDCConnectorSpecV2{ IssuerURL: o.IssuerURL, ClientID: o.ClientID, ClientSecret: o.ClientSecret, @@ -1035,10 +1038,13 @@ func (o *OIDCConnector) Parse() (types.OIDCConnector, error) { Scope: o.Scope, ClaimsToRoles: mappings, }) + if err != nil { + return nil, trace.Wrap(err) + } v2.SetACR(o.ACR) v2.SetProvider(o.Provider) - if err := v2.Check(); err != nil { + if err := v2.CheckAndSetDefaults(); err != nil { return nil, trace.Wrap(err) } return v2, nil diff --git a/lib/kube/proxy/server_test.go b/lib/kube/proxy/server_test.go index 5f5c54756e1..d2c3471637c 100644 --- a/lib/kube/proxy/server_test.go +++ b/lib/kube/proxy/server_test.go @@ -48,7 +48,7 @@ func TestMTLSClientCAs(t *testing.T) { addCA := func(t *testing.T, name string) (key, cert []byte) { key, cert, err := tlsca.GenerateSelfSignedCAWithPrivateKey(caKey, pkix.Name{CommonName: name}, nil, time.Minute) require.NoError(t, err) - ca := types.NewCertAuthority(types.CertAuthoritySpecV2{ + ca, err := types.NewCertAuthority(types.CertAuthoritySpecV2{ Type: types.HostCA, ClusterName: name, ActiveKeys: types.CAKeySet{ @@ -58,6 +58,7 @@ func TestMTLSClientCAs(t *testing.T) { }}, }, }) + require.NoError(t, err) ap.cas[name] = ca return key, cert } diff --git a/lib/reversetunnel/rc_manager_test.go b/lib/reversetunnel/rc_manager_test.go index 227dc2a893c..db9766f6518 100644 --- a/lib/reversetunnel/rc_manager_test.go +++ b/lib/reversetunnel/rc_manager_test.go @@ -44,46 +44,46 @@ func TestRemoteClusterTunnelManagerSync(t *testing.T) { { desc: "one reverse tunnel with one address", reverseTunnels: []types.ReverseTunnel{ - types.NewReverseTunnel("cluster-a", []string{"addr-a"}), + mustNewReverseTunnel(t, "cluster-a", []string{"addr-a"}), }, wantPools: map[remoteClusterKey]*AgentPool{ - remoteClusterKey{cluster: "cluster-a", addr: "addr-a"}: &AgentPool{cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-a"}}, + {cluster: "cluster-a", addr: "addr-a"}: {cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-a"}}, }, assertErr: require.NoError, }, { desc: "one reverse tunnel added with multiple addresses", reverseTunnels: []types.ReverseTunnel{ - types.NewReverseTunnel("cluster-a", []string{"addr-a", "addr-b", "addr-c"}), + mustNewReverseTunnel(t, "cluster-a", []string{"addr-a", "addr-b", "addr-c"}), }, wantPools: map[remoteClusterKey]*AgentPool{ - remoteClusterKey{cluster: "cluster-a", addr: "addr-a"}: &AgentPool{cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-a"}}, - remoteClusterKey{cluster: "cluster-a", addr: "addr-b"}: &AgentPool{cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-b"}}, - remoteClusterKey{cluster: "cluster-a", addr: "addr-c"}: &AgentPool{cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-c"}}, + {cluster: "cluster-a", addr: "addr-a"}: {cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-a"}}, + {cluster: "cluster-a", addr: "addr-b"}: {cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-b"}}, + {cluster: "cluster-a", addr: "addr-c"}: {cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-c"}}, }, assertErr: require.NoError, }, { desc: "one reverse tunnel added and one removed", reverseTunnels: []types.ReverseTunnel{ - types.NewReverseTunnel("cluster-b", []string{"addr-b"}), + mustNewReverseTunnel(t, "cluster-b", []string{"addr-b"}), }, wantPools: map[remoteClusterKey]*AgentPool{ - remoteClusterKey{cluster: "cluster-b", addr: "addr-b"}: &AgentPool{cfg: AgentPoolConfig{Cluster: "cluster-b", ProxyAddr: "addr-b"}}, + {cluster: "cluster-b", addr: "addr-b"}: {cfg: AgentPoolConfig{Cluster: "cluster-b", ProxyAddr: "addr-b"}}, }, assertErr: require.NoError, }, { desc: "multiple reverse tunnels", reverseTunnels: []types.ReverseTunnel{ - types.NewReverseTunnel("cluster-a", []string{"addr-a", "addr-b", "addr-c"}), - types.NewReverseTunnel("cluster-b", []string{"addr-b"}), + mustNewReverseTunnel(t, "cluster-a", []string{"addr-a", "addr-b", "addr-c"}), + mustNewReverseTunnel(t, "cluster-b", []string{"addr-b"}), }, wantPools: map[remoteClusterKey]*AgentPool{ - remoteClusterKey{cluster: "cluster-a", addr: "addr-a"}: &AgentPool{cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-a"}}, - remoteClusterKey{cluster: "cluster-a", addr: "addr-b"}: &AgentPool{cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-b"}}, - remoteClusterKey{cluster: "cluster-a", addr: "addr-c"}: &AgentPool{cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-c"}}, - remoteClusterKey{cluster: "cluster-b", addr: "addr-b"}: &AgentPool{cfg: AgentPoolConfig{Cluster: "cluster-b", ProxyAddr: "addr-b"}}, + {cluster: "cluster-a", addr: "addr-a"}: {cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-a"}}, + {cluster: "cluster-a", addr: "addr-b"}: {cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-b"}}, + {cluster: "cluster-a", addr: "addr-c"}: {cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-c"}}, + {cluster: "cluster-b", addr: "addr-b"}: {cfg: AgentPoolConfig{Cluster: "cluster-b", ProxyAddr: "addr-b"}}, }, assertErr: require.NoError, }, @@ -91,26 +91,26 @@ func TestRemoteClusterTunnelManagerSync(t *testing.T) { desc: "GetReverseTunnels error, keep existing pools", reverseTunnelsErr: errors.New("nah"), wantPools: map[remoteClusterKey]*AgentPool{ - remoteClusterKey{cluster: "cluster-a", addr: "addr-a"}: &AgentPool{cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-a"}}, - remoteClusterKey{cluster: "cluster-a", addr: "addr-b"}: &AgentPool{cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-b"}}, - remoteClusterKey{cluster: "cluster-a", addr: "addr-c"}: &AgentPool{cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-c"}}, - remoteClusterKey{cluster: "cluster-b", addr: "addr-b"}: &AgentPool{cfg: AgentPoolConfig{Cluster: "cluster-b", ProxyAddr: "addr-b"}}, + {cluster: "cluster-a", addr: "addr-a"}: {cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-a"}}, + {cluster: "cluster-a", addr: "addr-b"}: {cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-b"}}, + {cluster: "cluster-a", addr: "addr-c"}: {cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-c"}}, + {cluster: "cluster-b", addr: "addr-b"}: {cfg: AgentPoolConfig{Cluster: "cluster-b", ProxyAddr: "addr-b"}}, }, assertErr: require.Error, }, { desc: "AgentPool creation fails, keep existing pools", reverseTunnels: []types.ReverseTunnel{ - types.NewReverseTunnel("cluster-a", []string{"addr-a", "addr-b", "addr-c"}), - types.NewReverseTunnel("cluster-b", []string{"addr-b"}), - types.NewReverseTunnel("cluster-c", []string{"addr-c1", "addr-c2"}), + mustNewReverseTunnel(t, "cluster-a", []string{"addr-a", "addr-b", "addr-c"}), + mustNewReverseTunnel(t, "cluster-b", []string{"addr-b"}), + mustNewReverseTunnel(t, "cluster-c", []string{"addr-c1", "addr-c2"}), }, newAgentPoolErr: errors.New("nah"), wantPools: map[remoteClusterKey]*AgentPool{ - remoteClusterKey{cluster: "cluster-a", addr: "addr-a"}: &AgentPool{cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-a"}}, - remoteClusterKey{cluster: "cluster-a", addr: "addr-b"}: &AgentPool{cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-b"}}, - remoteClusterKey{cluster: "cluster-a", addr: "addr-c"}: &AgentPool{cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-c"}}, - remoteClusterKey{cluster: "cluster-b", addr: "addr-b"}: &AgentPool{cfg: AgentPoolConfig{Cluster: "cluster-b", ProxyAddr: "addr-b"}}, + {cluster: "cluster-a", addr: "addr-a"}: {cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-a"}}, + {cluster: "cluster-a", addr: "addr-b"}: {cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-b"}}, + {cluster: "cluster-a", addr: "addr-c"}: {cfg: AgentPoolConfig{Cluster: "cluster-a", ProxyAddr: "addr-c"}}, + {cluster: "cluster-b", addr: "addr-b"}: {cfg: AgentPoolConfig{Cluster: "cluster-b", ProxyAddr: "addr-b"}}, }, assertErr: require.Error, }, @@ -152,3 +152,9 @@ type mockAuthClient struct { func (c mockAuthClient) GetReverseTunnels(...services.MarshalOption) ([]types.ReverseTunnel, error) { return c.reverseTunnels, c.reverseTunnelsErr } + +func mustNewReverseTunnel(t *testing.T, clusterName string, dialAddrs []string) types.ReverseTunnel { + tun, err := types.NewReverseTunnel(clusterName, dialAddrs) + require.NoError(t, err) + return tun +} diff --git a/lib/reversetunnel/srv_test.go b/lib/reversetunnel/srv_test.go index b5a7ae2b45a..e81ea7e9349 100644 --- a/lib/reversetunnel/srv_test.go +++ b/lib/reversetunnel/srv_test.go @@ -35,26 +35,29 @@ import ( ) func TestServerKeyAuth(t *testing.T) { - ca := testauthority.New() - priv, pub, err := ca.GenerateKeyPair("") + ta := testauthority.New() + priv, pub, err := ta.GenerateKeyPair("") + require.NoError(t, err) + + ca, err := types.NewCertAuthority(types.CertAuthoritySpecV2{ + Type: types.HostCA, + ClusterName: "cluster-name", + ActiveKeys: types.CAKeySet{ + SSH: []*types.SSHKeyPair{{ + PrivateKey: priv, + PrivateKeyType: types.PrivateKeyType_RAW, + PublicKey: pub, + }}, + }, + Roles: nil, + SigningAlg: types.CertAuthoritySpecV2_RSA_SHA2_256, + }) require.NoError(t, err) s := &server{ log: testlog.FailureOnly(t), localAccessPoint: mockAccessPoint{ - ca: types.NewCertAuthority(types.CertAuthoritySpecV2{ - Type: types.HostCA, - ClusterName: "cluster-name", - ActiveKeys: types.CAKeySet{ - SSH: []*types.SSHKeyPair{{ - PrivateKey: priv, - PrivateKeyType: types.PrivateKeyType_RAW, - PublicKey: pub, - }}, - }, - Roles: nil, - SigningAlg: types.CertAuthoritySpecV2_RSA_SHA2_256, - }), + ca: ca, }, } con := mockSSHConnMetadata{} @@ -67,7 +70,7 @@ func TestServerKeyAuth(t *testing.T) { { desc: "host cert", key: func() ssh.PublicKey { - rawCert, err := ca.GenerateHostCert(services.HostCertParams{ + rawCert, err := ta.GenerateHostCert(services.HostCertParams{ PrivateCASigningKey: priv, CASigningAlg: defaults.CASignatureAlgorithm, PublicHostKey: pub, @@ -92,7 +95,7 @@ func TestServerKeyAuth(t *testing.T) { { desc: "user cert", key: func() ssh.PublicKey { - rawCert, err := ca.GenerateUserCert(services.UserCertParams{ + rawCert, err := ta.GenerateUserCert(services.UserCertParams{ PrivateCASigningKey: priv, CASigningAlg: defaults.CASignatureAlgorithm, PublicUserKey: pub, diff --git a/lib/service/cfg.go b/lib/service/cfg.go index 10729b02f24..027b9766798 100644 --- a/lib/service/cfg.go +++ b/lib/service/cfg.go @@ -858,8 +858,8 @@ func ApplyDefaults(cfg *Config) { cfg.Auth.SSHAddr = *defaults.AuthListenAddr() cfg.Auth.StorageConfig.Type = lite.GetName() cfg.Auth.StorageConfig.Params = backend.Params{defaults.BackendPath: filepath.Join(cfg.DataDir, defaults.BackendDir)} - cfg.Auth.StaticTokens = services.DefaultStaticTokens() - cfg.Auth.ClusterConfig = services.DefaultClusterConfig() + cfg.Auth.StaticTokens = types.DefaultStaticTokens() + cfg.Auth.ClusterConfig = types.DefaultClusterConfig() cfg.Auth.AuditConfig = types.DefaultClusterAuditConfig() cfg.Auth.NetworkingConfig = types.DefaultClusterNetworkingConfig() cfg.Auth.SessionRecordingConfig = types.DefaultSessionRecordingConfig() diff --git a/lib/service/db.go b/lib/service/db.go index e4635ec5f24..795dccace6c 100644 --- a/lib/service/db.go +++ b/lib/service/db.go @@ -84,7 +84,7 @@ func (process *TeleportProcess) initDatabaseService() (retErr error) { // Create database server for each of the proxied databases. var databaseServers []types.DatabaseServer for _, db := range process.Config.Databases.Databases { - databaseServers = append(databaseServers, types.NewDatabaseServerV3( + db, err := types.NewDatabaseServerV3( db.Name, db.StaticLabels, types.DatabaseServerSpecV3{ @@ -106,7 +106,11 @@ func (process *TeleportProcess) initDatabaseService() (retErr error) { Version: teleport.Version, Hostname: process.Config.Hostname, HostID: process.Config.HostUUID, - })) + }) + if err != nil { + return trace.Wrap(err) + } + databaseServers = append(databaseServers, db) } clusterName := conn.ServerIdentity.Cert.Extensions[utils.CertExtensionAuthority] diff --git a/lib/services/access_request.go b/lib/services/access_request.go index 65d24bfb052..6681ba16364 100644 --- a/lib/services/access_request.go +++ b/lib/services/access_request.go @@ -1180,6 +1180,10 @@ func UnmarshalAccessRequest(data []byte, opts ...MarshalOption) (types.AccessReq // MarshalAccessRequest marshals the AccessRequest resource to JSON. func MarshalAccessRequest(accessRequest types.AccessRequest, opts ...MarshalOption) ([]byte, error) { + if err := ValidateAccessRequest(accessRequest); err != nil { + return nil, trace.Wrap(err) + } + cfg, err := CollectOptions(opts) if err != nil { return nil, trace.Wrap(err) @@ -1187,9 +1191,6 @@ func MarshalAccessRequest(accessRequest types.AccessRequest, opts ...MarshalOpti switch accessRequest := accessRequest.(type) { case *types.AccessRequestV3: - if version := accessRequest.GetVersion(); version != types.V3 { - return nil, trace.BadParameter("mismatched access request version %v and type %T", version, accessRequest) - } if !cfg.PreserveResourceID { // avoid modifying the original object // to prevent unexpected data races diff --git a/lib/services/authentication.go b/lib/services/authentication.go index 73b59da2527..ea0b693e684 100644 --- a/lib/services/authentication.go +++ b/lib/services/authentication.go @@ -124,5 +124,8 @@ func UnmarshalAuthPreference(bytes []byte, opts ...MarshalOption) (types.AuthPre // MarshalAuthPreference marshals the AuthPreference resource to JSON. func MarshalAuthPreference(c types.AuthPreference, opts ...MarshalOption) ([]byte, error) { + if err := c.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } return json.Marshal(c) } diff --git a/lib/services/authority.go b/lib/services/authority.go index 1b0b269687f..c29cc6c538f 100644 --- a/lib/services/authority.go +++ b/lib/services/authority.go @@ -59,7 +59,7 @@ func NewJWTAuthority(clusterName string) (types.CertAuthority, error) { ActiveKeys: types.CAKeySet{ JWT: []*types.JWTKeyPair{&keyPair}, }, - }), nil + }) } // ValidateCertAuthority validates the CertAuthority @@ -382,6 +382,10 @@ func UnmarshalCertAuthority(bytes []byte, opts ...MarshalOption) (types.CertAuth // MarshalCertAuthority marshals the CertAuthority resource to JSON. func MarshalCertAuthority(certAuthority types.CertAuthority, opts ...MarshalOption) ([]byte, error) { + if err := ValidateCertAuthority(certAuthority); err != nil { + return nil, trace.Wrap(err) + } + cfg, err := CollectOptions(opts) if err != nil { return nil, trace.Wrap(err) @@ -389,9 +393,6 @@ func MarshalCertAuthority(certAuthority types.CertAuthority, opts ...MarshalOpti switch certAuthority := certAuthority.(type) { case *types.CertAuthorityV2: - if version := certAuthority.GetVersion(); version != types.V2 { - return nil, trace.BadParameter("mismatched certificate authority version %v and type %T", version, certAuthority) - } if !cfg.PreserveResourceID { // avoid modifying the original object // to prevent unexpected data races diff --git a/lib/services/authority_test.go b/lib/services/authority_test.go index 4e63fea2f09..3be2762e890 100644 --- a/lib/services/authority_test.go +++ b/lib/services/authority_test.go @@ -31,7 +31,7 @@ func TestCertPoolFromCertAuthorities(t *testing.T) { // CA for cluster1 with 1 key pair. key, cert, err := tlsca.GenerateSelfSignedCA(pkix.Name{CommonName: "cluster1"}, nil, time.Minute) require.NoError(t, err) - ca1 := types.NewCertAuthority(types.CertAuthoritySpecV2{ + ca1, err := types.NewCertAuthority(types.CertAuthoritySpecV2{ Type: types.HostCA, ClusterName: "cluster1", ActiveKeys: types.CAKeySet{ @@ -41,12 +41,14 @@ func TestCertPoolFromCertAuthorities(t *testing.T) { }}, }, }) + require.NoError(t, err) + // CA for cluster2 with 2 key pairs. key, cert, err = tlsca.GenerateSelfSignedCA(pkix.Name{CommonName: "cluster2"}, nil, time.Minute) require.NoError(t, err) key2, cert2, err := tlsca.GenerateSelfSignedCA(pkix.Name{CommonName: "cluster2"}, nil, time.Minute) require.NoError(t, err) - ca2 := types.NewCertAuthority(types.CertAuthoritySpecV2{ + ca2, err := types.NewCertAuthority(types.CertAuthoritySpecV2{ Type: types.HostCA, ClusterName: "cluster2", ActiveKeys: types.CAKeySet{ @@ -62,6 +64,7 @@ func TestCertPoolFromCertAuthorities(t *testing.T) { }, }, }) + require.NoError(t, err) t.Run("ca1 with 1 cert", func(t *testing.T) { pool, err := CertPoolFromCertAuthorities([]types.CertAuthority{ca1}) @@ -85,7 +88,7 @@ func TestCertAuthorityEquivalence(t *testing.T) { // CA for cluster1 with 1 key pair. key, cert, err := tlsca.GenerateSelfSignedCA(pkix.Name{CommonName: "cluster1"}, nil, time.Minute) require.NoError(t, err) - ca1 := types.NewCertAuthority(types.CertAuthoritySpecV2{ + ca1, err := types.NewCertAuthority(types.CertAuthoritySpecV2{ Type: types.HostCA, ClusterName: "cluster1", ActiveKeys: types.CAKeySet{ @@ -95,12 +98,14 @@ func TestCertAuthorityEquivalence(t *testing.T) { }}, }, }) + require.NoError(t, err) + // CA for cluster2 with 2 key pairs. key, cert, err = tlsca.GenerateSelfSignedCA(pkix.Name{CommonName: "cluster2"}, nil, time.Minute) require.NoError(t, err) key2, cert2, err := tlsca.GenerateSelfSignedCA(pkix.Name{CommonName: "cluster2"}, nil, time.Minute) require.NoError(t, err) - ca2 := types.NewCertAuthority(types.CertAuthoritySpecV2{ + ca2, err := types.NewCertAuthority(types.CertAuthoritySpecV2{ Type: types.HostCA, ClusterName: "cluster2", ActiveKeys: types.CAKeySet{ @@ -116,6 +121,7 @@ func TestCertAuthorityEquivalence(t *testing.T) { }, }, }) + require.NoError(t, err) // different CAs are different require.False(t, CertAuthoritiesEquivalent(ca1, ca2)) diff --git a/lib/services/clusterconfig.go b/lib/services/clusterconfig.go index 1dc97e2fb4d..7b95d41d6fa 100644 --- a/lib/services/clusterconfig.go +++ b/lib/services/clusterconfig.go @@ -19,25 +19,10 @@ package services import ( "github.com/gravitational/trace" - apidefaults "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/utils" ) -// DefaultClusterConfig is used as the default cluster configuration when -// one is not specified (record at node). -func DefaultClusterConfig() types.ClusterConfig { - return &types.ClusterConfigV3{ - Kind: types.KindClusterConfig, - Version: types.V3, - Metadata: types.Metadata{ - Name: types.MetaNameClusterConfig, - Namespace: apidefaults.Namespace, - }, - Spec: types.ClusterConfigSpecV3{}, - } -} - // UnmarshalClusterConfig unmarshals the ClusterConfig resource from JSON. func UnmarshalClusterConfig(bytes []byte, opts ...MarshalOption) (types.ClusterConfig, error) { var clusterConfig types.ClusterConfigV3 @@ -71,6 +56,10 @@ func UnmarshalClusterConfig(bytes []byte, opts ...MarshalOption) (types.ClusterC // MarshalClusterConfig marshals the ClusterConfig resource to JSON. func MarshalClusterConfig(clusterConfig types.ClusterConfig, opts ...MarshalOption) ([]byte, error) { + if err := clusterConfig.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + cfg, err := CollectOptions(opts) if err != nil { return nil, trace.Wrap(err) @@ -78,9 +67,6 @@ func MarshalClusterConfig(clusterConfig types.ClusterConfig, opts ...MarshalOpti switch clusterConfig := clusterConfig.(type) { case *types.ClusterConfigV3: - if version := clusterConfig.GetVersion(); version != types.V3 { - return nil, trace.BadParameter("mismatched cluster config version %v and type %T", version, clusterConfig) - } if !cfg.PreserveResourceID { // avoid modifying the original object // to prevent unexpected data races diff --git a/lib/services/clustername.go b/lib/services/clustername.go index 1ec89c238db..50acf1b444e 100644 --- a/lib/services/clustername.go +++ b/lib/services/clustername.go @@ -68,6 +68,10 @@ func UnmarshalClusterName(bytes []byte, opts ...MarshalOption) (types.ClusterNam // MarshalClusterName marshals the ClusterName resource to JSON. func MarshalClusterName(clusterName types.ClusterName, opts ...MarshalOption) ([]byte, error) { + if err := clusterName.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + cfg, err := CollectOptions(opts) if err != nil { return nil, trace.Wrap(err) @@ -75,9 +79,6 @@ func MarshalClusterName(clusterName types.ClusterName, opts ...MarshalOption) ([ switch clusterName := clusterName.(type) { case *types.ClusterNameV2: - if version := clusterName.GetVersion(); version != types.V2 { - return nil, trace.BadParameter("mismatched cluster name version %v and type %T", version, clusterName) - } if !cfg.PreserveResourceID { // avoid modifying the original object // to prevent unexpected data races diff --git a/lib/services/databaseserver.go b/lib/services/databaseserver.go index 3656c9f4458..d39a314bd3d 100644 --- a/lib/services/databaseserver.go +++ b/lib/services/databaseserver.go @@ -28,6 +28,7 @@ func MarshalDatabaseServer(databaseServer types.DatabaseServer, opts ...MarshalO if err := databaseServer.CheckAndSetDefaults(); err != nil { return nil, trace.Wrap(err) } + cfg, err := CollectOptions(opts) if err != nil { return nil, trace.Wrap(err) @@ -35,9 +36,6 @@ func MarshalDatabaseServer(databaseServer types.DatabaseServer, opts ...MarshalO switch databaseServer := databaseServer.(type) { case *types.DatabaseServerV3: - if version := databaseServer.GetVersion(); version != types.V3 { - return nil, trace.BadParameter("mismatched database server version %v and type %T", version, databaseServer) - } if !cfg.PreserveResourceID { // avoid modifying the original object // to prevent unexpected data races diff --git a/lib/services/github.go b/lib/services/github.go index a2341ae0c94..f873a456d30 100644 --- a/lib/services/github.go +++ b/lib/services/github.go @@ -48,6 +48,10 @@ func UnmarshalGithubConnector(bytes []byte) (types.GithubConnector, error) { // MarshalGithubConnector marshals the GithubConnector resource to JSON. func MarshalGithubConnector(githubConnector types.GithubConnector, opts ...MarshalOption) ([]byte, error) { + if err := githubConnector.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + cfg, err := CollectOptions(opts) if err != nil { return nil, trace.Wrap(err) @@ -55,9 +59,6 @@ func MarshalGithubConnector(githubConnector types.GithubConnector, opts ...Marsh switch githubConnector := githubConnector.(type) { case *types.GithubConnectorV3: - if version := githubConnector.GetVersion(); version != types.V3 { - return nil, trace.BadParameter("mismatched github connector version %v and type %T", version, githubConnector) - } if !cfg.PreserveResourceID { // avoid modifying the original object // to prevent unexpected data races diff --git a/lib/services/github_test.go b/lib/services/github_test.go index fed21216550..28786ffa7fe 100644 --- a/lib/services/github_test.go +++ b/lib/services/github_test.go @@ -44,7 +44,7 @@ func (g *GithubSuite) TestUnmarshal(c *check.C) { }}`) connector, err := UnmarshalGithubConnector(data) c.Assert(err, check.IsNil) - expected := types.NewGithubConnector("github", types.GithubConnectorSpecV3{ + expected, err := types.NewGithubConnector("github", types.GithubConnectorSpecV3{ ClientID: "aaa", ClientSecret: "bbb", RedirectURL: "https://localhost:3080/v1/webapi/github/callback", @@ -57,11 +57,12 @@ func (g *GithubSuite) TestUnmarshal(c *check.C) { }, }, }) + c.Assert(err, check.IsNil) c.Assert(expected, check.DeepEquals, connector) } func (g *GithubSuite) TestMapClaims(c *check.C) { - connector := types.NewGithubConnector("github", types.GithubConnectorSpecV3{ + connector, err := types.NewGithubConnector("github", types.GithubConnectorSpecV3{ ClientID: "aaa", ClientSecret: "bbb", RedirectURL: "https://localhost:3080/v1/webapi/github/callback", @@ -82,6 +83,8 @@ func (g *GithubSuite) TestMapClaims(c *check.C) { }, }, }) + c.Assert(err, check.IsNil) + logins, kubeGroups, kubeUsers := connector.MapClaims(types.GithubClaims{ OrganizationToTeams: map[string][]string{ "gravitational": {"admins"}, diff --git a/lib/services/license.go b/lib/services/license.go index bb0ee0646a4..e8a84228fa2 100644 --- a/lib/services/license.go +++ b/lib/services/license.go @@ -48,6 +48,10 @@ func UnmarshalLicense(bytes []byte) (types.License, error) { // MarshalLicense marshals the License resource to JSON. func MarshalLicense(license types.License, opts ...MarshalOption) ([]byte, error) { + if err := license.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + cfg, err := CollectOptions(opts) if err != nil { return nil, trace.Wrap(err) @@ -55,9 +59,6 @@ func MarshalLicense(license types.License, opts ...MarshalOption) ([]byte, error switch license := license.(type) { case *types.LicenseV3: - if version := license.GetVersion(); version != types.V3 { - return nil, trace.BadParameter("mismatched license version %v and type %T", version, license) - } if !cfg.PreserveResourceID { // avoid modifying the original object // to prevent unexpected data races diff --git a/lib/services/local/configuration.go b/lib/services/local/configuration.go index 836c25c4fac..28da78f5a42 100644 --- a/lib/services/local/configuration.go +++ b/lib/services/local/configuration.go @@ -232,7 +232,7 @@ func (s *ClusterConfigurationService) GetClusterConfig(opts ...services.MarshalO // a default ClusterConfig instead (to be filled with data from the other // resources). This helps keep backward compatibility when a non-upgraded // v7.x auth server needs to work with v6.x cluster components. - clusterConfig = services.DefaultClusterConfig() + clusterConfig = types.DefaultClusterConfig() } else { clusterConfig, err = services.UnmarshalClusterConfig(item.Value, append(opts, services.WithResourceID(item.ID), services.WithExpires(item.Expires))...) if err != nil { diff --git a/lib/services/local/presence_test.go b/lib/services/local/presence_test.go index 35667a968aa..c41fbbda5b3 100644 --- a/lib/services/local/presence_test.go +++ b/lib/services/local/presence_test.go @@ -119,13 +119,14 @@ func TestDatabaseServersCRUD(t *testing.T) { presence := NewPresenceService(backend) // Create a database server. - server := types.NewDatabaseServerV3("foo", nil, + server, err := types.NewDatabaseServerV3("foo", nil, types.DatabaseServerSpecV3{ Protocol: defaults.ProtocolPostgres, URI: "localhost:5432", Hostname: "localhost", HostID: uuid.New(), }) + require.NoError(t, err) // Initially expect not to be returned any servers. out, err := presence.GetDatabaseServers(ctx, apidefaults.Namespace) diff --git a/lib/services/local/resource.go b/lib/services/local/resource.go index cd3b0166c20..ac05346e532 100644 --- a/lib/services/local/resource.go +++ b/lib/services/local/resource.go @@ -346,9 +346,6 @@ func itemToRole(item backend.Item) (types.Role, error) { // itemFromOIDCConnector attempts to encode the supplied connector as an // instance of `backend.Item` suitable for storage. func itemFromOIDCConnector(connector types.OIDCConnector) (*backend.Item, error) { - if err := connector.Check(); err != nil { - return nil, trace.Wrap(err) - } value, err := services.MarshalOIDCConnector(connector) if err != nil { return nil, trace.Wrap(err) diff --git a/lib/services/local/users.go b/lib/services/local/users.go index 63fe7720e36..3f6b3d7f1f7 100644 --- a/lib/services/local/users.go +++ b/lib/services/local/users.go @@ -671,9 +671,6 @@ func (s *IdentityService) GetU2FSignChallenge(user string) (*u2f.Challenge, erro // UpsertOIDCConnector upserts OIDC Connector func (s *IdentityService) UpsertOIDCConnector(ctx context.Context, connector types.OIDCConnector) error { - if err := connector.Check(); err != nil { - return trace.Wrap(err) - } value, err := services.MarshalOIDCConnector(connector) if err != nil { return trace.Wrap(err) diff --git a/lib/services/namespace.go b/lib/services/namespace.go index 5490550f6d9..d0a3d581ed1 100644 --- a/lib/services/namespace.go +++ b/lib/services/namespace.go @@ -25,6 +25,10 @@ import ( // MarshalNamespace marshals the Namespace resource to JSON. func MarshalNamespace(resource types.Namespace, opts ...MarshalOption) ([]byte, error) { + if err := resource.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + cfg, err := CollectOptions(opts) if err != nil { return nil, trace.Wrap(err) diff --git a/lib/services/networking.go b/lib/services/networking.go index f70d5718ea7..fbb93710f55 100644 --- a/lib/services/networking.go +++ b/lib/services/networking.go @@ -67,9 +67,6 @@ func MarshalClusterNetworkingConfig(netConfig types.ClusterNetworkingConfig, opt switch netConfig := netConfig.(type) { case *types.ClusterNetworkingConfigV2: - if version := netConfig.GetVersion(); version != types.V2 { - return nil, trace.BadParameter("mismatched cluster networking config version %v and type %T", version, netConfig) - } if !cfg.PreserveResourceID { // avoid modifying the original object // to prevent unexpected data races diff --git a/lib/services/oidc.go b/lib/services/oidc.go index eeae26702b1..ecfd049ac08 100644 --- a/lib/services/oidc.go +++ b/lib/services/oidc.go @@ -124,6 +124,10 @@ func UnmarshalOIDCConnector(bytes []byte, opts ...MarshalOption) (types.OIDCConn // MarshalOIDCConnector marshals the OIDCConnector resource to JSON. func MarshalOIDCConnector(oidcConnector types.OIDCConnector, opts ...MarshalOption) ([]byte, error) { + if err := ValidateOIDCConnector(oidcConnector); err != nil { + return nil, trace.Wrap(err) + } + cfg, err := CollectOptions(opts) if err != nil { return nil, trace.Wrap(err) @@ -131,9 +135,6 @@ func MarshalOIDCConnector(oidcConnector types.OIDCConnector, opts ...MarshalOpti switch oidcConnector := oidcConnector.(type) { case *types.OIDCConnectorV2: - if version := oidcConnector.GetVersion(); version != types.V2 { - return nil, trace.BadParameter("mismatched OIDC connector version %v and type %T", version, oidcConnector) - } if !cfg.PreserveResourceID { // avoid modifying the original object // to prevent unexpected data races diff --git a/lib/services/oidc_test.go b/lib/services/oidc_test.go index 2d396b01273..2059b983c3e 100644 --- a/lib/services/oidc_test.go +++ b/lib/services/oidc_test.go @@ -30,7 +30,7 @@ import ( // Verify that an OIDC connector with no mappings produces no roles. func TestOIDCRoleMappingEmpty(t *testing.T) { // create a connector - oidcConnector := types.NewOIDCConnector("example", types.OIDCConnectorSpecV2{ + oidcConnector, err := types.NewOIDCConnector("example", types.OIDCConnectorSpecV2{ IssuerURL: "https://www.exmaple.com", ClientID: "example-client-id", ClientSecret: "example-client-secret", @@ -38,6 +38,7 @@ func TestOIDCRoleMappingEmpty(t *testing.T) { Display: "sign in with example.com", Scope: []string{"foo", "bar"}, }) + require.NoError(t, err) // create some claims var claims = make(jose.Claims) @@ -56,7 +57,7 @@ func TestOIDCRoleMappingEmpty(t *testing.T) { // TestOIDCRoleMapping verifies basic mapping from OIDC claims to roles. func TestOIDCRoleMapping(t *testing.T) { // create a connector - oidcConnector := types.NewOIDCConnector("example", types.OIDCConnectorSpecV2{ + oidcConnector, err := types.NewOIDCConnector("example", types.OIDCConnectorSpecV2{ IssuerURL: "https://www.exmaple.com", ClientID: "example-client-id", ClientSecret: "example-client-secret", @@ -71,6 +72,7 @@ func TestOIDCRoleMapping(t *testing.T) { }, }, }) + require.NoError(t, err) // create some claims var claims = make(jose.Claims) diff --git a/lib/services/plugin_data.go b/lib/services/plugin_data.go index e1cd49a8acd..15ed30d0df1 100644 --- a/lib/services/plugin_data.go +++ b/lib/services/plugin_data.go @@ -25,6 +25,10 @@ import ( //MarshalPluginData marshals the PluginData resource to JSON. func MarshalPluginData(pluginData types.PluginData, opts ...MarshalOption) ([]byte, error) { + if err := pluginData.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + cfg, err := CollectOptions(opts) if err != nil { return nil, trace.Wrap(err) @@ -32,9 +36,6 @@ func MarshalPluginData(pluginData types.PluginData, opts ...MarshalOption) ([]by switch pluginData := pluginData.(type) { case *types.PluginDataV3: - if version := pluginData.GetVersion(); version != types.V3 { - return nil, trace.BadParameter("mismatched plugin data version %v and type %T", version, pluginData) - } if !cfg.PreserveResourceID { // avoid modifying the original object // to prevent unexpected data races diff --git a/lib/services/provisioning.go b/lib/services/provisioning.go index e4c8195d0c7..3f035ab5cab 100644 --- a/lib/services/provisioning.go +++ b/lib/services/provisioning.go @@ -101,6 +101,10 @@ func UnmarshalProvisionToken(data []byte, opts ...MarshalOption) (types.Provisio // MarshalProvisionToken marshals the ProvisionToken resource to JSON. func MarshalProvisionToken(provisionToken types.ProvisionToken, opts ...MarshalOption) ([]byte, error) { + if err := provisionToken.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + cfg, err := CollectOptions(opts) if err != nil { return nil, trace.Wrap(err) @@ -108,9 +112,6 @@ func MarshalProvisionToken(provisionToken types.ProvisionToken, opts ...MarshalO switch provisionToken := provisionToken.(type) { case *types.ProvisionTokenV2: - if version := provisionToken.GetVersion(); version != types.V2 { - return nil, trace.BadParameter("mismatched provision token version %v and type %T", version, provisionToken) - } if !cfg.PreserveResourceID { // avoid modifying the original object // to prevent unexpected data races diff --git a/lib/services/remotecluster.go b/lib/services/remotecluster.go index 95270e95a1d..a463aea5cd3 100644 --- a/lib/services/remotecluster.go +++ b/lib/services/remotecluster.go @@ -57,6 +57,10 @@ func UnmarshalRemoteCluster(bytes []byte, opts ...MarshalOption) (types.RemoteCl // MarshalRemoteCluster marshals the RemoteCluster resource to JSON. func MarshalRemoteCluster(remoteCluster types.RemoteCluster, opts ...MarshalOption) ([]byte, error) { + if err := remoteCluster.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + cfg, err := CollectOptions(opts) if err != nil { return nil, trace.Wrap(err) @@ -64,9 +68,6 @@ func MarshalRemoteCluster(remoteCluster types.RemoteCluster, opts ...MarshalOpti switch remoteCluster := remoteCluster.(type) { case *types.RemoteClusterV3: - if version := remoteCluster.GetVersion(); version != types.V3 { - return nil, trace.BadParameter("mismatched remote cluster version %v and type %T", version, remoteCluster) - } if !cfg.PreserveResourceID { // avoid modifying the original object // to prevent unexpected data races diff --git a/lib/services/resetpasswordtoken.go b/lib/services/resetpasswordtoken.go index 2a3d7990a6d..209a15c7402 100644 --- a/lib/services/resetpasswordtoken.go +++ b/lib/services/resetpasswordtoken.go @@ -42,5 +42,8 @@ func UnmarshalResetPasswordToken(bytes []byte, opts ...MarshalOption) (types.Res // MarshalResetPasswordToken marshals the ResetPasswordToken resource to JSON. func MarshalResetPasswordToken(token types.ResetPasswordToken, opts ...MarshalOption) ([]byte, error) { + if err := token.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } return utils.FastMarshal(token) } diff --git a/lib/services/resetpasswordtokensecrets.go b/lib/services/resetpasswordtokensecrets.go index fbaeb9458e6..ac20d294233 100644 --- a/lib/services/resetpasswordtokensecrets.go +++ b/lib/services/resetpasswordtokensecrets.go @@ -42,5 +42,8 @@ func UnmarshalResetPasswordTokenSecrets(bytes []byte, opts ...MarshalOption) (ty // MarshalResetPasswordTokenSecrets marshals the ResetPasswordTokenSecrets resource to JSON. func MarshalResetPasswordTokenSecrets(secrets types.ResetPasswordTokenSecrets, opts ...MarshalOption) ([]byte, error) { + if err := secrets.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } return utils.FastMarshal(secrets) } diff --git a/lib/services/resource.go b/lib/services/resource.go index fb7473dbd57..059483240d8 100644 --- a/lib/services/resource.go +++ b/lib/services/resource.go @@ -478,6 +478,10 @@ func init() { // NOTE: This function only supports the subset of resources which may be imported/exported // by users (e.g. via `tctl get`). func MarshalResource(resource types.Resource, opts ...MarshalOption) ([]byte, error) { + if err := resource.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + marshal, ok := getResourceMarshaler(resource.GetKind()) if !ok { return nil, trace.NotImplemented("cannot dynamically marshal resources of kind %q", resource.GetKind()) diff --git a/lib/services/role.go b/lib/services/role.go index dad4efa5f52..07b97fb5b9c 100644 --- a/lib/services/role.go +++ b/lib/services/role.go @@ -28,7 +28,7 @@ import ( "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/constants" - apidefaults "github.com/gravitational/teleport/api/defaults" + "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/wrappers" apiutils "github.com/gravitational/teleport/api/utils" @@ -111,33 +111,25 @@ func RoleNameForCertAuthority(name string) string { // is not explicitly assigned (this role applies to all users in OSS version). func NewAdminRole() types.Role { adminRules := getExtendedAdminUserRules(modules.GetModules().Features()) - role := &types.RoleV4{ - Kind: types.KindRole, - Version: types.V3, - Metadata: types.Metadata{ - Name: teleport.AdminRoleName, - Namespace: apidefaults.Namespace, + role, _ := types.NewRole(teleport.AdminRoleName, types.RoleSpecV4{ + Options: types.RoleOptions{ + CertificateFormat: constants.CertificateFormatStandard, + MaxSessionTTL: types.NewDuration(defaults.MaxCertDuration), + PortForwarding: types.NewBoolOption(true), + ForwardAgent: types.NewBool(true), + BPF: defaults.EnhancedEvents(), }, - Spec: types.RoleSpecV4{ - Options: types.RoleOptions{ - CertificateFormat: constants.CertificateFormatStandard, - MaxSessionTTL: types.NewDuration(apidefaults.MaxCertDuration), - PortForwarding: types.NewBoolOption(true), - ForwardAgent: types.NewBool(true), - BPF: apidefaults.EnhancedEvents(), - }, - Allow: types.RoleConditions{ - Namespaces: []string{apidefaults.Namespace}, - NodeLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, - AppLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, - KubernetesLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, - DatabaseLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, - DatabaseNames: []string{teleport.TraitInternalDBNamesVariable}, - DatabaseUsers: []string{teleport.TraitInternalDBUsersVariable}, - Rules: adminRules, - }, + Allow: types.RoleConditions{ + Namespaces: []string{defaults.Namespace}, + NodeLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, + AppLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, + KubernetesLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, + DatabaseLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, + DatabaseNames: []string{teleport.TraitInternalDBNamesVariable}, + DatabaseUsers: []string{teleport.TraitInternalDBUsersVariable}, + Rules: adminRules, }, - } + }) role.SetLogins(Allow, []string{teleport.TraitInternalLoginsVariable, teleport.Root}) role.SetKubeUsers(Allow, []string{teleport.TraitInternalKubeUsersVariable}) role.SetKubeGroups(Allow, []string{teleport.TraitInternalKubeGroupsVariable}) @@ -147,65 +139,51 @@ func NewAdminRole() types.Role { // NewImplicitRole is the default implicit role that gets added to all // RoleSets. func NewImplicitRole() types.Role { - return &types.RoleV4{ - Kind: types.KindRole, - Version: types.V3, - Metadata: types.Metadata{ - Name: constants.DefaultImplicitRole, - Namespace: apidefaults.Namespace, + role, _ := types.NewRole(constants.DefaultImplicitRole, types.RoleSpecV4{ + Options: types.RoleOptions{ + MaxSessionTTL: types.MaxDuration(), + // PortForwarding has to be set to false in the default-implicit-role + // otherwise all roles will be allowed to forward ports (since we default + // to true in the check). + PortForwarding: types.NewBoolOption(false), }, - Spec: types.RoleSpecV4{ - Options: types.RoleOptions{ - MaxSessionTTL: types.MaxDuration(), - // PortForwarding has to be set to false in the default-implicit-role - // otherwise all roles will be allowed to forward ports (since we default - // to true in the check). - PortForwarding: types.NewBoolOption(false), - }, - Allow: types.RoleConditions{ - Namespaces: []string{apidefaults.Namespace}, - Rules: types.CopyRulesSlice(DefaultImplicitRules), - }, + Allow: types.RoleConditions{ + Namespaces: []string{defaults.Namespace}, + Rules: types.CopyRulesSlice(DefaultImplicitRules), }, - } + }) + return role } // RoleForUser creates an admin role for a services.User. func RoleForUser(u types.User) types.Role { - return &types.RoleV4{ - Kind: types.KindRole, - Version: types.V3, - Metadata: types.Metadata{ - Name: RoleNameForUser(u.GetName()), - Namespace: apidefaults.Namespace, + role, _ := types.NewRole(RoleNameForUser(u.GetName()), types.RoleSpecV4{ + Options: types.RoleOptions{ + CertificateFormat: constants.CertificateFormatStandard, + MaxSessionTTL: types.NewDuration(defaults.MaxCertDuration), + PortForwarding: types.NewBoolOption(true), + ForwardAgent: types.NewBool(true), + BPF: defaults.EnhancedEvents(), }, - Spec: types.RoleSpecV4{ - Options: types.RoleOptions{ - CertificateFormat: constants.CertificateFormatStandard, - MaxSessionTTL: types.NewDuration(apidefaults.MaxCertDuration), - PortForwarding: types.NewBoolOption(true), - ForwardAgent: types.NewBool(true), - BPF: apidefaults.EnhancedEvents(), - }, - Allow: types.RoleConditions{ - Namespaces: []string{apidefaults.Namespace}, - NodeLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, - AppLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, - KubernetesLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, - DatabaseLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, - Rules: []types.Rule{ - types.NewRule(types.KindRole, RW()), - types.NewRule(types.KindAuthConnector, RW()), - types.NewRule(types.KindSession, RO()), - types.NewRule(types.KindTrustedCluster, RW()), - types.NewRule(types.KindEvent, RO()), - types.NewRule(types.KindClusterAuthPreference, RW()), - types.NewRule(types.KindClusterNetworkingConfig, RW()), - types.NewRule(types.KindSessionRecordingConfig, RW()), - }, + Allow: types.RoleConditions{ + Namespaces: []string{defaults.Namespace}, + NodeLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, + AppLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, + KubernetesLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, + DatabaseLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, + Rules: []types.Rule{ + types.NewRule(types.KindRole, RW()), + types.NewRule(types.KindAuthConnector, RW()), + types.NewRule(types.KindSession, RO()), + types.NewRule(types.KindTrustedCluster, RW()), + types.NewRule(types.KindEvent, RO()), + types.NewRule(types.KindClusterAuthPreference, RW()), + types.NewRule(types.KindClusterNetworkingConfig, RW()), + types.NewRule(types.KindSessionRecordingConfig, RW()), }, }, - } + }) + return role } // NewDowngradedOSSAdminRole is a role for enabling RBAC for open source users. @@ -217,19 +195,19 @@ func NewDowngradedOSSAdminRole() types.Role { Version: types.V3, Metadata: types.Metadata{ Name: teleport.AdminRoleName, - Namespace: apidefaults.Namespace, + Namespace: defaults.Namespace, Labels: map[string]string{teleport.OSSMigratedV6: types.True}, }, Spec: types.RoleSpecV4{ Options: types.RoleOptions{ CertificateFormat: constants.CertificateFormatStandard, - MaxSessionTTL: types.NewDuration(apidefaults.MaxCertDuration), + MaxSessionTTL: types.NewDuration(defaults.MaxCertDuration), PortForwarding: types.NewBoolOption(true), ForwardAgent: types.NewBool(true), - BPF: apidefaults.EnhancedEvents(), + BPF: defaults.EnhancedEvents(), }, Allow: types.RoleConditions{ - Namespaces: []string{apidefaults.Namespace}, + Namespaces: []string{defaults.Namespace}, NodeLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, AppLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, KubernetesLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, @@ -251,35 +229,27 @@ func NewDowngradedOSSAdminRole() types.Role { // NewOSSGithubRole creates a role for enabling RBAC for open source Github users func NewOSSGithubRole(logins []string, kubeUsers []string, kubeGroups []string) types.Role { - role := &types.RoleV4{ - Kind: types.KindRole, - Version: types.V3, - Metadata: types.Metadata{ - Name: "github-" + uuid.New(), - Namespace: apidefaults.Namespace, + role, _ := types.NewRole("github-"+uuid.New(), types.RoleSpecV4{ + Options: types.RoleOptions{ + CertificateFormat: constants.CertificateFormatStandard, + MaxSessionTTL: types.NewDuration(defaults.MaxCertDuration), + PortForwarding: types.NewBoolOption(true), + ForwardAgent: types.NewBool(true), + BPF: defaults.EnhancedEvents(), }, - Spec: types.RoleSpecV4{ - Options: types.RoleOptions{ - CertificateFormat: constants.CertificateFormatStandard, - MaxSessionTTL: types.NewDuration(apidefaults.MaxCertDuration), - PortForwarding: types.NewBoolOption(true), - ForwardAgent: types.NewBool(true), - BPF: apidefaults.EnhancedEvents(), - }, - Allow: types.RoleConditions{ - Namespaces: []string{apidefaults.Namespace}, - NodeLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, - AppLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, - KubernetesLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, - DatabaseLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, - DatabaseNames: []string{teleport.TraitInternalDBNamesVariable}, - DatabaseUsers: []string{teleport.TraitInternalDBUsersVariable}, - Rules: []types.Rule{ - types.NewRule(types.KindEvent, RO()), - }, + Allow: types.RoleConditions{ + Namespaces: []string{defaults.Namespace}, + NodeLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, + AppLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, + KubernetesLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, + DatabaseLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, + DatabaseNames: []string{teleport.TraitInternalDBNamesVariable}, + DatabaseUsers: []string{teleport.TraitInternalDBUsersVariable}, + Rules: []types.Rule{ + types.NewRule(types.KindEvent, RO()), }, }, - } + }) role.SetLogins(Allow, logins) role.SetKubeUsers(Allow, kubeUsers) role.SetKubeGroups(Allow, kubeGroups) @@ -288,27 +258,20 @@ func NewOSSGithubRole(logins []string, kubeUsers []string, kubeGroups []string) // RoleForCertAuthority creates role using types.CertAuthority. func RoleForCertAuthority(ca types.CertAuthority) types.Role { - return &types.RoleV4{ - Kind: types.KindRole, - Version: types.V3, - Metadata: types.Metadata{ - Name: RoleNameForCertAuthority(ca.GetClusterName()), - Namespace: apidefaults.Namespace, + role, _ := types.NewRole(RoleNameForCertAuthority(ca.GetClusterName()), types.RoleSpecV4{ + Options: types.RoleOptions{ + MaxSessionTTL: types.NewDuration(defaults.MaxCertDuration), }, - Spec: types.RoleSpecV4{ - Options: types.RoleOptions{ - MaxSessionTTL: types.NewDuration(apidefaults.MaxCertDuration), - }, - Allow: types.RoleConditions{ - Namespaces: []string{apidefaults.Namespace}, - NodeLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, - AppLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, - KubernetesLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, - DatabaseLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, - Rules: types.CopyRulesSlice(DefaultCertAuthorityRules), - }, + Allow: types.RoleConditions{ + Namespaces: []string{defaults.Namespace}, + NodeLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, + AppLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, + KubernetesLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, + DatabaseLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, + Rules: types.CopyRulesSlice(DefaultCertAuthorityRules), }, - } + }) + return role } // Access service manages roles and permissions @@ -2191,6 +2154,10 @@ func UnmarshalRole(bytes []byte, opts ...MarshalOption) (types.Role, error) { // MarshalRole marshals the Role resource to JSON. func MarshalRole(role types.Role, opts ...MarshalOption) ([]byte, error) { + if err := ValidateRole(role); err != nil { + return nil, trace.Wrap(err) + } + cfg, err := CollectOptions(opts) if err != nil { return nil, trace.Wrap(err) @@ -2198,10 +2165,6 @@ func MarshalRole(role types.Role, opts ...MarshalOption) ([]byte, error) { switch role := role.(type) { case *types.RoleV4: - // V4 role version is compatible with V3 - if version := role.GetVersion(); version != types.V3 && version != types.V4 { - return nil, trace.BadParameter("mismatched role version %v and type %T", version, role) - } if !cfg.PreserveResourceID { // avoid modifying the original object // to prevent unexpected data races diff --git a/lib/services/role_test.go b/lib/services/role_test.go index 76c48078ec8..7914ac58430 100644 --- a/lib/services/role_test.go +++ b/lib/services/role_test.go @@ -2172,12 +2172,24 @@ func TestBoolOptions(t *testing.T) { } func TestCheckAccessToDatabase(t *testing.T) { - dbStage := types.NewDatabaseServerV3("stage", + dbStage, err := types.NewDatabaseServerV3("stage", map[string]string{"env": "stage"}, - types.DatabaseServerSpecV3{}) - dbProd := types.NewDatabaseServerV3("prod", + types.DatabaseServerSpecV3{ + Protocol: "protocol", + URI: "uri", + Hostname: "hostname", + HostID: "host_id", + }) + require.NoError(t, err) + dbProd, err := types.NewDatabaseServerV3("prod", map[string]string{"env": "prod"}, - types.DatabaseServerSpecV3{}) + types.DatabaseServerSpecV3{ + Protocol: "protocol", + URI: "uri", + Hostname: "hostname", + HostID: "host_id", + }) + require.NoError(t, err) roleDevStage := &types.RoleV4{ Metadata: types.Metadata{Name: "dev-stage", Namespace: defaults.Namespace}, Version: types.V3, @@ -2336,12 +2348,24 @@ func TestCheckAccessToDatabase(t *testing.T) { } func TestCheckAccessToDatabaseUser(t *testing.T) { - dbStage := types.NewDatabaseServerV3("stage", + dbStage, err := types.NewDatabaseServerV3("stage", map[string]string{"env": "stage"}, - types.DatabaseServerSpecV3{}) - dbProd := types.NewDatabaseServerV3("prod", + types.DatabaseServerSpecV3{ + Protocol: "protocol", + URI: "uri", + Hostname: "hostname", + HostID: "host_id", + }) + require.NoError(t, err) + dbProd, err := types.NewDatabaseServerV3("prod", map[string]string{"env": "prod"}, - types.DatabaseServerSpecV3{}) + types.DatabaseServerSpecV3{ + Protocol: "protocol", + URI: "uri", + Hostname: "hostname", + HostID: "host_id", + }) + require.NoError(t, err) roleDevStage := &types.RoleV4{ Metadata: types.Metadata{Name: "dev-stage", Namespace: defaults.Namespace}, Spec: types.RoleSpecV4{ @@ -2504,22 +2528,44 @@ func TestCheckDatabaseNamesAndUsers(t *testing.T) { } func TestCheckAccessToDatabaseService(t *testing.T) { - dbNoLabels := types.NewDatabaseServerV3("test", + dbNoLabels, err := types.NewDatabaseServerV3("test", nil, - types.DatabaseServerSpecV3{}) - dbStage := types.NewDatabaseServerV3("stage", + types.DatabaseServerSpecV3{ + Protocol: "protocol", + URI: "uri", + Hostname: "hostname", + HostID: "host_id", + }) + require.NoError(t, err) + dbStage, err := types.NewDatabaseServerV3("stage", map[string]string{"env": "stage"}, types.DatabaseServerSpecV3{ + Protocol: "protocol", + URI: "uri", + Hostname: "hostname", + HostID: "host_id", DynamicLabels: map[string]types.CommandLabelV2{"arch": {Result: "x86"}}, }) - dbStage2 := types.NewDatabaseServerV3("stage2", + require.NoError(t, err) + dbStage2, err := types.NewDatabaseServerV3("stage2", map[string]string{"env": "stage"}, types.DatabaseServerSpecV3{ + Protocol: "protocol", + URI: "uri", + Hostname: "hostname", + HostID: "host_id", DynamicLabels: map[string]types.CommandLabelV2{"arch": {Result: "amd64"}}, }) - dbProd := types.NewDatabaseServerV3("prod", + require.NoError(t, err) + dbProd, err := types.NewDatabaseServerV3("prod", map[string]string{"env": "prod"}, - types.DatabaseServerSpecV3{}) + types.DatabaseServerSpecV3{ + Protocol: "protocol", + URI: "uri", + Hostname: "hostname", + HostID: "host_id", + }) + require.NoError(t, err) roleAdmin := &types.RoleV4{ Metadata: types.Metadata{Name: "admin", Namespace: apidefaults.Namespace}, Spec: types.RoleSpecV4{ diff --git a/lib/services/saml.go b/lib/services/saml.go index 07c215c352a..17e0f3f0575 100644 --- a/lib/services/saml.go +++ b/lib/services/saml.go @@ -251,6 +251,10 @@ func UnmarshalSAMLConnector(bytes []byte, opts ...MarshalOption) (types.SAMLConn // MarshalSAMLConnector marshals the SAMLConnector resource to JSON. func MarshalSAMLConnector(samlConnector types.SAMLConnector, opts ...MarshalOption) ([]byte, error) { + if err := ValidateSAMLConnector(samlConnector); err != nil { + return nil, trace.Wrap(err) + } + cfg, err := CollectOptions(opts) if err != nil { return nil, trace.Wrap(err) @@ -258,9 +262,6 @@ func MarshalSAMLConnector(samlConnector types.SAMLConnector, opts ...MarshalOpti switch samlConnector := samlConnector.(type) { case *types.SAMLConnectorV2: - if version := samlConnector.GetVersion(); version != types.V2 { - return nil, trace.BadParameter("mismatched SAML connector version %v and type %T", version, samlConnector) - } if !cfg.PreserveResourceID { // avoid modifying the original object // to prevent unexpected data races diff --git a/lib/services/semaphore.go b/lib/services/semaphore.go index 544f2f642dd..d53701322da 100644 --- a/lib/services/semaphore.go +++ b/lib/services/semaphore.go @@ -251,15 +251,17 @@ func UnmarshalSemaphore(bytes []byte, opts ...MarshalOption) (types.Semaphore, e // MarshalSemaphore marshals the Semaphore resource to JSON. func MarshalSemaphore(semaphore types.Semaphore, opts ...MarshalOption) ([]byte, error) { + if err := semaphore.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + cfg, err := CollectOptions(opts) if err != nil { return nil, trace.Wrap(err) } + switch semaphore := semaphore.(type) { case *types.SemaphoreV3: - if version := semaphore.GetVersion(); version != types.V3 { - return nil, trace.BadParameter("mismatched semaphore version %v and type %T", version, semaphore) - } if !cfg.PreserveResourceID { // avoid modifying the original object // to prevent unexpected data races diff --git a/lib/services/server.go b/lib/services/server.go index d7ec8ec24ad..5d50059d79b 100644 --- a/lib/services/server.go +++ b/lib/services/server.go @@ -264,6 +264,7 @@ func MarshalServer(server types.Server, opts ...MarshalOption) ([]byte, error) { if err := server.CheckAndSetDefaults(); err != nil { return nil, trace.Wrap(err) } + cfg, err := CollectOptions(opts) if err != nil { return nil, trace.Wrap(err) @@ -271,9 +272,6 @@ func MarshalServer(server types.Server, opts ...MarshalOption) ([]byte, error) { switch server := server.(type) { case *types.ServerV2: - if version := server.GetVersion(); version != types.V2 { - return nil, trace.BadParameter("mismatched server version %v and type %T", version, server) - } if !cfg.PreserveResourceID { // avoid modifying the original object // to prevent unexpected data races diff --git a/lib/services/session.go b/lib/services/session.go index 5a71fa9575c..ffd66fb79ba 100644 --- a/lib/services/session.go +++ b/lib/services/session.go @@ -90,6 +90,10 @@ func MarshalWebSession(webSession types.WebSession, opts ...MarshalOption) ([]by // MarshalWebToken serializes the web token as JSON-encoded payload func MarshalWebToken(webToken types.WebToken, opts ...MarshalOption) ([]byte, error) { + if err := webToken.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + cfg, err := CollectOptions(opts) if err != nil { return nil, trace.Wrap(err) @@ -97,9 +101,6 @@ func MarshalWebToken(webToken types.WebToken, opts ...MarshalOption) ([]byte, er switch webToken := webToken.(type) { case *types.WebTokenV3: - if version := webToken.GetVersion(); version != types.V3 { - return nil, trace.BadParameter("mismatched web token version %v and type %T", version, webToken) - } if !cfg.PreserveResourceID { // avoid modifying the original object // to prevent unexpected data races diff --git a/lib/services/statictokens.go b/lib/services/statictokens.go index b3e1c3e7faa..9cbc6990193 100644 --- a/lib/services/statictokens.go +++ b/lib/services/statictokens.go @@ -19,27 +19,10 @@ package services import ( "github.com/gravitational/trace" - apidefaults "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/utils" ) -// DefaultStaticTokens is used to get the default static tokens (empty list) -// when nothing is specified in file configuration. -func DefaultStaticTokens() types.StaticTokens { - return &types.StaticTokensV2{ - Kind: types.KindStaticTokens, - Version: types.V2, - Metadata: types.Metadata{ - Name: types.MetaNameStaticTokens, - Namespace: apidefaults.Namespace, - }, - Spec: types.StaticTokensSpecV2{ - StaticTokens: []types.ProvisionTokenV1{}, - }, - } -} - // UnmarshalStaticTokens unmarshals the StaticTokens resource from JSON. func UnmarshalStaticTokens(bytes []byte, opts ...MarshalOption) (types.StaticTokens, error) { var staticTokens types.StaticTokensV2 @@ -71,6 +54,10 @@ func UnmarshalStaticTokens(bytes []byte, opts ...MarshalOption) (types.StaticTok // MarshalStaticTokens marshals the StaticTokens resource to JSON. func MarshalStaticTokens(staticToken types.StaticTokens, opts ...MarshalOption) ([]byte, error) { + if err := staticToken.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + cfg, err := CollectOptions(opts) if err != nil { return nil, trace.Wrap(err) @@ -78,9 +65,6 @@ func MarshalStaticTokens(staticToken types.StaticTokens, opts ...MarshalOption) switch staticToken := staticToken.(type) { case *types.StaticTokensV2: - if version := staticToken.GetVersion(); version != types.V2 { - return nil, trace.BadParameter("mismatched static token version %v and type %T", version, staticToken) - } if !cfg.PreserveResourceID { // avoid modifying the original object // to prevent unexpected data races diff --git a/lib/services/suite/suite.go b/lib/services/suite/suite.go index 13021ae6bea..126bd7a521b 100644 --- a/lib/services/suite/suite.go +++ b/lib/services/suite/suite.go @@ -455,7 +455,7 @@ func NewAppServer(name string, internalAddr string, publicAddr string) *types.Se }, Spec: types.ServerSpecV2{ Apps: []*types.App{ - &types.App{ + { Name: name, URI: internalAddr, PublicAddr: publicAddr, @@ -570,13 +570,15 @@ func (s *ServicesTestSuite) WebSessionCRUD(c *check.C) { c.Assert(trace.IsNotFound(err), check.Equals, true, check.Commentf("%#v", err)) dt := s.Clock.Now().Add(1 * time.Minute) - ws := types.NewWebSession("sid1", types.KindWebSession, types.KindWebSession, + ws, err := types.NewWebSession("sid1", types.KindWebSession, types.WebSessionSpecV2{ User: "user1", Pub: []byte("pub123"), Priv: []byte("priv123"), Expires: dt, }) + c.Assert(err, check.IsNil) + err = s.WebS.WebSessions().Upsert(ctx, ws) c.Assert(err, check.IsNil) @@ -584,13 +586,15 @@ func (s *ServicesTestSuite) WebSessionCRUD(c *check.C) { c.Assert(err, check.IsNil) c.Assert(out, check.DeepEquals, ws) - ws1 := types.NewWebSession("sid1", types.KindWebSession, types.KindWebSession, + ws1, err := types.NewWebSession("sid1", types.KindWebSession, types.WebSessionSpecV2{ User: "user1", Pub: []byte("pub321"), Priv: []byte("priv321"), Expires: dt, }) + c.Assert(err, check.IsNil) + err = s.WebS.WebSessions().Upsert(ctx, ws1) c.Assert(err, check.IsNil) diff --git a/lib/services/trustedcluster.go b/lib/services/trustedcluster.go index ce1c9ed62f5..49fdfefd3fb 100644 --- a/lib/services/trustedcluster.go +++ b/lib/services/trustedcluster.go @@ -151,7 +151,6 @@ func UnmarshalTrustedCluster(bytes []byte, opts ...MarshalOption) (types.Trusted if err := utils.FastUnmarshal(bytes, &trustedCluster); err != nil { return nil, trace.BadParameter(err.Error()) } - // DELETE IN(7.0) // temporarily allow to read trusted cluster with no role map // until users migrate from 6.0 OSS that had no role map present @@ -170,6 +169,14 @@ func UnmarshalTrustedCluster(bytes []byte, opts ...MarshalOption) (types.Trusted // MarshalTrustedCluster marshals the TrustedCluster resource to JSON. func MarshalTrustedCluster(trustedCluster types.TrustedCluster, opts ...MarshalOption) ([]byte, error) { + // DELETE IN(7.0) + // temporarily allow to read trusted cluster with no role map + // until users migrate from 6.0 OSS that had no role map present + const allowEmptyRoleMap = true + if err := ValidateTrustedCluster(trustedCluster, allowEmptyRoleMap); err != nil { + return nil, trace.Wrap(err) + } + cfg, err := CollectOptions(opts) if err != nil { return nil, trace.Wrap(err) @@ -177,9 +184,6 @@ func MarshalTrustedCluster(trustedCluster types.TrustedCluster, opts ...MarshalO switch trustedCluster := trustedCluster.(type) { case *types.TrustedClusterV2: - if version := trustedCluster.GetVersion(); version != types.V2 { - return nil, trace.BadParameter("mismatched trusted cluster version %v and type %T", version, trustedCluster) - } if !cfg.PreserveResourceID { // avoid modifying the original object // to prevent unexpected data races diff --git a/lib/services/tunnel.go b/lib/services/tunnel.go index dba37dab440..328c74aa198 100644 --- a/lib/services/tunnel.go +++ b/lib/services/tunnel.go @@ -75,6 +75,10 @@ func UnmarshalReverseTunnel(bytes []byte, opts ...MarshalOption) (types.ReverseT // MarshalReverseTunnel marshals the ReverseTunnel resource to JSON. func MarshalReverseTunnel(reverseTunnel types.ReverseTunnel, opts ...MarshalOption) ([]byte, error) { + if err := ValidateReverseTunnel(reverseTunnel); err != nil { + return nil, trace.Wrap(err) + } + cfg, err := CollectOptions(opts) if err != nil { return nil, trace.Wrap(err) @@ -82,9 +86,6 @@ func MarshalReverseTunnel(reverseTunnel types.ReverseTunnel, opts ...MarshalOpti switch reverseTunnel := reverseTunnel.(type) { case *types.ReverseTunnelV2: - if version := reverseTunnel.GetVersion(); version != types.V2 { - return nil, trace.BadParameter("mismatched reverse tunnel version %v and type %T", version, reverseTunnel) - } if !cfg.PreserveResourceID { // avoid modifying the original object // to prevent unexpected data races diff --git a/lib/services/tunnelconn.go b/lib/services/tunnelconn.go index 0b6bf8799dd..aa71a1692d3 100644 --- a/lib/services/tunnelconn.go +++ b/lib/services/tunnelconn.go @@ -92,6 +92,10 @@ func UnmarshalTunnelConnection(data []byte, opts ...MarshalOption) (types.Tunnel // MarshalTunnelConnection marshals the TunnelConnection resource to JSON. func MarshalTunnelConnection(tunnelConnection types.TunnelConnection, opts ...MarshalOption) ([]byte, error) { + if err := tunnelConnection.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + cfg, err := CollectOptions(opts) if err != nil { return nil, trace.Wrap(err) @@ -99,9 +103,6 @@ func MarshalTunnelConnection(tunnelConnection types.TunnelConnection, opts ...Ma switch tunnelConnection := tunnelConnection.(type) { case *types.TunnelConnectionV2: - if version := tunnelConnection.GetVersion(); version != types.V2 { - return nil, trace.BadParameter("mismatched tunnel connection version %v and type %T", version, tunnelConnection) - } if !cfg.PreserveResourceID { // avoid modifying the original object // to prevent unexpected data races diff --git a/lib/services/user.go b/lib/services/user.go index 354c3528446..db899951266 100644 --- a/lib/services/user.go +++ b/lib/services/user.go @@ -104,6 +104,10 @@ func UnmarshalUser(bytes []byte, opts ...MarshalOption) (types.User, error) { // MarshalUser marshals the User resource to JSON. func MarshalUser(user types.User, opts ...MarshalOption) ([]byte, error) { + if err := ValidateUser(user); err != nil { + return nil, trace.Wrap(err) + } + cfg, err := CollectOptions(opts) if err != nil { return nil, trace.Wrap(err) @@ -111,9 +115,6 @@ func MarshalUser(user types.User, opts ...MarshalOption) ([]byte, error) { switch user := user.(type) { case *types.UserV2: - if version := user.GetVersion(); version != types.V2 { - return nil, trace.BadParameter("mismatched user version %v and type %T", version, user) - } if !cfg.PreserveResourceID { // avoid modifying the original object // to prevent unexpected data races diff --git a/lib/srv/db/access_test.go b/lib/srv/db/access_test.go index cc20518fa96..123cc1a45bb 100644 --- a/lib/srv/db/access_test.go +++ b/lib/srv/db/access_test.go @@ -572,7 +572,7 @@ func withSelfHostedPostgres(name string) withDatabaseOption { require.NoError(t, err) go postgresServer.Serve() t.Cleanup(func() { postgresServer.Close() }) - server := types.NewDatabaseServerV3(name, nil, + server, err := types.NewDatabaseServerV3(name, nil, types.DatabaseServerSpecV3{ Protocol: defaults.ProtocolPostgres, URI: net.JoinHostPort("localhost", postgresServer.Port()), @@ -581,6 +581,7 @@ func withSelfHostedPostgres(name string) withDatabaseOption { HostID: testCtx.hostID, DynamicLabels: dynamicLabels, }) + require.NoError(t, err) _, err = testCtx.authClient.UpsertDatabaseServer(ctx, server) require.NoError(t, err) testCtx.postgres[name] = testPostgres{ @@ -601,7 +602,7 @@ func withRDSPostgres(name, authToken string) withDatabaseOption { require.NoError(t, err) go postgresServer.Serve() t.Cleanup(func() { postgresServer.Close() }) - server := types.NewDatabaseServerV3(name, nil, + server, err := types.NewDatabaseServerV3(name, nil, types.DatabaseServerSpecV3{ Protocol: defaults.ProtocolPostgres, URI: net.JoinHostPort("localhost", postgresServer.Port()), @@ -615,6 +616,7 @@ func withRDSPostgres(name, authToken string) withDatabaseOption { // Set CA cert, otherwise we will attempt to download RDS roots. CACert: testCtx.hostCA.GetActiveKeys().TLS[0].Cert, }) + require.NoError(t, err) _, err = testCtx.authClient.UpsertDatabaseServer(ctx, server) require.NoError(t, err) testCtx.postgres[name] = testPostgres{ @@ -635,7 +637,7 @@ func withRedshiftPostgres(name, authToken string) withDatabaseOption { require.NoError(t, err) go postgresServer.Serve() t.Cleanup(func() { postgresServer.Close() }) - server := types.NewDatabaseServerV3(name, nil, + server, err := types.NewDatabaseServerV3(name, nil, types.DatabaseServerSpecV3{ Protocol: defaults.ProtocolPostgres, URI: net.JoinHostPort("localhost", postgresServer.Port()), @@ -650,6 +652,7 @@ func withRedshiftPostgres(name, authToken string) withDatabaseOption { // Set CA cert, otherwise we will attempt to download Redshift roots. CACert: testCtx.hostCA.GetActiveKeys().TLS[0].Cert, }) + require.NoError(t, err) _, err = testCtx.authClient.UpsertDatabaseServer(ctx, server) require.NoError(t, err) testCtx.postgres[name] = testPostgres{ @@ -673,7 +676,7 @@ func withCloudSQLPostgres(name, authToken string) withDatabaseOption { require.NoError(t, err) go postgresServer.Serve() t.Cleanup(func() { postgresServer.Close() }) - server := types.NewDatabaseServerV3(name, nil, + server, err := types.NewDatabaseServerV3(name, nil, types.DatabaseServerSpecV3{ Protocol: defaults.ProtocolPostgres, URI: net.JoinHostPort("localhost", postgresServer.Port()), @@ -688,6 +691,7 @@ func withCloudSQLPostgres(name, authToken string) withDatabaseOption { // Set CA cert to pass cert validation. CACert: testCtx.hostCA.GetActiveKeys().TLS[0].Cert, }) + require.NoError(t, err) _, err = testCtx.authClient.UpsertDatabaseServer(ctx, server) require.NoError(t, err) testCtx.postgres[name] = testPostgres{ @@ -707,7 +711,7 @@ func withSelfHostedMySQL(name string) withDatabaseOption { require.NoError(t, err) go mysqlServer.Serve() t.Cleanup(func() { mysqlServer.Close() }) - server := types.NewDatabaseServerV3(name, nil, + server, err := types.NewDatabaseServerV3(name, nil, types.DatabaseServerSpecV3{ Protocol: defaults.ProtocolMySQL, URI: net.JoinHostPort("localhost", mysqlServer.Port()), @@ -716,6 +720,7 @@ func withSelfHostedMySQL(name string) withDatabaseOption { HostID: testCtx.hostID, DynamicLabels: dynamicLabels, }) + require.NoError(t, err) _, err = testCtx.authClient.UpsertDatabaseServer(ctx, server) require.NoError(t, err) testCtx.mysql[name] = testMySQL{ @@ -737,7 +742,7 @@ func withRDSMySQL(name, authUser, authToken string) withDatabaseOption { require.NoError(t, err) go mysqlServer.Serve() t.Cleanup(func() { mysqlServer.Close() }) - server := types.NewDatabaseServerV3(name, nil, + server, err := types.NewDatabaseServerV3(name, nil, types.DatabaseServerSpecV3{ Protocol: defaults.ProtocolMySQL, URI: net.JoinHostPort("localhost", mysqlServer.Port()), @@ -751,6 +756,7 @@ func withRDSMySQL(name, authUser, authToken string) withDatabaseOption { // Set CA cert, otherwise we will attempt to download RDS roots. CACert: testCtx.hostCA.GetActiveKeys().TLS[0].Cert, }) + require.NoError(t, err) _, err = testCtx.authClient.UpsertDatabaseServer(ctx, server) require.NoError(t, err) testCtx.mysql[name] = testMySQL{ diff --git a/lib/srv/db/ha_test.go b/lib/srv/db/ha_test.go index cf8a264ad50..a20e5603e53 100644 --- a/lib/srv/db/ha_test.go +++ b/lib/srv/db/ha_test.go @@ -49,7 +49,7 @@ func TestHA(t *testing.T) { // Offline database server will be tried first and trigger connection error. offlineHostID := "host-id-1" - offlineDBServer := types.NewDatabaseServerV3("postgres", nil, + offlineDBServer, err := types.NewDatabaseServerV3("postgres", nil, types.DatabaseServerSpecV3{ Protocol: defaults.ProtocolPostgres, URI: net.JoinHostPort("localhost", postgresServer.Port()), @@ -57,6 +57,7 @@ func TestHA(t *testing.T) { Hostname: constants.APIDomain, HostID: offlineHostID, }) + require.NoError(t, err) _, err = testCtx.authClient.UpsertDatabaseServer(ctx, offlineDBServer) require.NoError(t, err) testCtx.fakeRemoteSite.OfflineTunnels = map[string]struct{}{ @@ -65,7 +66,7 @@ func TestHA(t *testing.T) { // Online database server will serve the connection. onlineHostID := "host-id-2" - onlineDBServer := types.NewDatabaseServerV3("postgres", nil, + onlineDBServer, err := types.NewDatabaseServerV3("postgres", nil, types.DatabaseServerSpecV3{ Protocol: defaults.ProtocolPostgres, URI: net.JoinHostPort("localhost", postgresServer.Port()), @@ -73,6 +74,7 @@ func TestHA(t *testing.T) { Hostname: constants.APIDomain, HostID: onlineHostID, }) + require.NoError(t, err) _, err = testCtx.authClient.UpsertDatabaseServer(ctx, onlineDBServer) require.NoError(t, err) onlineServer := testCtx.setupDatabaseServer(ctx, t, onlineHostID, onlineDBServer) diff --git a/lib/srv/regular/sshserver_test.go b/lib/srv/regular/sshserver_test.go index 3c338be1897..0e9e4867c04 100644 --- a/lib/srv/regular/sshserver_test.go +++ b/lib/srv/regular/sshserver_test.go @@ -838,8 +838,9 @@ func TestProxyReverseTunnel(t *testing.T) { // Create a reverse tunnel and remote cluster simulating what the trusted // cluster exchange does. - err = f.testSrv.Auth().UpsertReverseTunnel( - types.NewReverseTunnel(f.testSrv.ClusterName(), []string{reverseTunnelAddress.String()})) + rt, err := types.NewReverseTunnel(f.testSrv.ClusterName(), []string{reverseTunnelAddress.String()}) + require.NoError(t, err) + err = f.testSrv.Auth().UpsertReverseTunnel(rt) require.NoError(t, err) remoteCluster, err := types.NewRemoteCluster("localhost") require.NoError(t, err) diff --git a/lib/web/apiserver.go b/lib/web/apiserver.go index 375b2e0c911..e225399510a 100644 --- a/lib/web/apiserver.go +++ b/lib/web/apiserver.go @@ -1241,7 +1241,10 @@ func newSessionResponse(ctx *SessionContext) (*CreateSessionResponse, error) { if err != nil { return nil, trace.Wrap(err) } - token := ctx.getToken() + token, err := ctx.getToken() + if err != nil { + return nil, trace.Wrap(err) + } user, err := clt.GetUser(ctx.GetUser(), false) if err != nil { return nil, trace.Wrap(err) diff --git a/lib/web/apiserver_test.go b/lib/web/apiserver_test.go index 3cbb01851a3..b8f016666f3 100644 --- a/lib/web/apiserver_test.go +++ b/lib/web/apiserver_test.go @@ -1599,9 +1599,13 @@ func (s *WebSuite) TestMultipleConnectors(c *C) { }, }, } - err := s.server.Auth().UpsertOIDCConnector(ctx, types.NewOIDCConnector("foo", oidcConnectorSpec)) + o, err := types.NewOIDCConnector("foo", oidcConnectorSpec) c.Assert(err, IsNil) - err = s.server.Auth().UpsertOIDCConnector(ctx, types.NewOIDCConnector("bar", oidcConnectorSpec)) + err = s.server.Auth().UpsertOIDCConnector(ctx, o) + c.Assert(err, IsNil) + o2, err := types.NewOIDCConnector("bar", oidcConnectorSpec) + c.Assert(err, IsNil) + err = s.server.Auth().UpsertOIDCConnector(ctx, o2) c.Assert(err, IsNil) // set the auth preferences to oidc with no connector name @@ -1891,13 +1895,14 @@ func TestClusterDatabasesGet(t *testing.T) { require.Len(t, dbs, 0) // Register a database. - db := types.NewDatabaseServerV3("test-db-name", map[string]string{"test-field": "test-value"}, types.DatabaseServerSpecV3{ + db, err := types.NewDatabaseServerV3("test-db-name", map[string]string{"test-field": "test-value"}, types.DatabaseServerSpecV3{ Description: "test-description", Protocol: "test-protocol", URI: "test-uri", Hostname: "test-hostname", HostID: "test-hostID", }) + require.NoError(t, err) _, err = env.server.Auth().UpsertDatabaseServer(context.Background(), db) require.NoError(t, err) diff --git a/lib/web/resources_test.go b/lib/web/resources_test.go index d8f157ae003..a588adcf40c 100644 --- a/lib/web/resources_test.go +++ b/lib/web/resources_test.go @@ -80,7 +80,8 @@ spec: teams_to_logins: null version: v3 ` - githubConn := types.NewGithubConnector("githubName", types.GithubConnectorSpecV3{}) + githubConn, err := types.NewGithubConnector("githubName", types.GithubConnectorSpecV3{}) + require.NoError(t, err) item, err := ui.NewResourceItem(githubConn) require.Nil(t, err) require.Equal(t, item, &ui.ResourceItem{ @@ -224,7 +225,8 @@ func TestGetGithubConnectors(t *testing.T) { m := &mockedResourceAPIGetter{} m.mockGetGithubConnectors = func(ctx context.Context, withSecrets bool) ([]types.GithubConnector, error) { - connector := types.NewGithubConnector("test", types.GithubConnectorSpecV3{}) + connector, err := types.NewGithubConnector("test", types.GithubConnectorSpecV3{}) + require.NoError(t, err) return []types.GithubConnector{connector}, nil } diff --git a/lib/web/sessions.go b/lib/web/sessions.go index 0c168c1b9c9..32f0d017a45 100644 --- a/lib/web/sessions.go +++ b/lib/web/sessions.go @@ -349,10 +349,15 @@ func (c *SessionContext) Close() error { // session. Note that sessions are separate from bearer tokens and this // is only useful immediately after a session has been created to query // the token. -func (c *SessionContext) getToken() types.WebToken { - return types.NewWebToken(c.session.GetBearerTokenExpiryTime(), types.WebTokenSpecV3{ +func (c *SessionContext) getToken() (types.WebToken, error) { + t, err := types.NewWebToken(c.session.GetBearerTokenExpiryTime(), types.WebTokenSpecV3{ + User: c.session.GetUser(), Token: c.session.GetBearerToken(), }) + if err != nil { + return nil, trace.Wrap(err) + } + return t, nil } // expired returns whether this context has expired. diff --git a/tool/tctl/common/auth_command_test.go b/tool/tctl/common/auth_command_test.go index b8c4b42b6b5..d8acebbb57e 100644 --- a/tool/tctl/common/auth_command_test.go +++ b/tool/tctl/common/auth_command_test.go @@ -42,7 +42,7 @@ func TestAuthSignKubeconfig(t *testing.T) { t.Fatal(err) } - ca := types.NewCertAuthority(types.CertAuthoritySpecV2{ + ca, err := types.NewCertAuthority(types.CertAuthoritySpecV2{ Type: types.HostCA, ClusterName: "example.com", ActiveKeys: types.CAKeySet{ @@ -52,6 +52,7 @@ func TestAuthSignKubeconfig(t *testing.T) { Roles: nil, SigningAlg: types.CertAuthoritySpecV2_RSA_SHA2_512, }) + require.NoError(t, err) client := mockClient{ clusterName: clusterName, diff --git a/tool/tsh/tsh_test.go b/tool/tsh/tsh_test.go index 8d820a19714..8beda525aff 100644 --- a/tool/tsh/tsh_test.go +++ b/tool/tsh/tsh_test.go @@ -875,12 +875,12 @@ func makeTestServers(t *testing.T, bootstrap ...types.Resource) (auth *service.T func mockConnector(t *testing.T) types.OIDCConnector { // Connector need not be functional since we are going to mock the actual // login operation. - connector := types.NewOIDCConnector("auth.example.com", types.OIDCConnectorSpecV2{ + connector, err := types.NewOIDCConnector("auth.example.com", types.OIDCConnectorSpecV2{ IssuerURL: "https://auth.example.com", RedirectURL: "https://cluster.example.com", ClientID: "fake-client", }) - require.NoError(t, connector.CheckAndSetDefaults()) + require.NoError(t, err) return connector }