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

     1  /*
     2  Copyright 2021 Gravitational, Inc.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package types
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"encoding/json"
    23  	"fmt"
    24  	"log/slog"
    25  	"net/url"
    26  	"strings"
    27  	"time"
    28  
    29  	"github.com/gogo/protobuf/jsonpb"
    30  	"github.com/gravitational/trace"
    31  
    32  	"github.com/gravitational/teleport/api/constants"
    33  	"github.com/gravitational/teleport/api/defaults"
    34  	"github.com/gravitational/teleport/api/utils/keys"
    35  	"github.com/gravitational/teleport/api/utils/tlsutils"
    36  )
    37  
    38  var (
    39  	// ErrPasswordlessRequiresWebauthn is issued if a passwordless challenge is
    40  	// requested but WebAuthn isn't enabled.
    41  	ErrPasswordlessRequiresWebauthn = &trace.BadParameterError{
    42  		Message: "passwordless requires WebAuthn",
    43  	}
    44  
    45  	// ErrPasswordlessDisabledBySettings is issued if a passwordless challenge is
    46  	// requested but passwordless is disabled by cluster settings.
    47  	// See AuthPreferenceV2.AuthPreferenceV2.
    48  	ErrPasswordlessDisabledBySettings = &trace.BadParameterError{
    49  		Message: "passwordless disabled by cluster settings",
    50  	}
    51  
    52  	// ErrPassswordlessLoginBySSOUser is issued if an SSO user tries to login
    53  	// using passwordless.
    54  	ErrPassswordlessLoginBySSOUser = &trace.AccessDeniedError{
    55  		Message: "SSO user cannot login using passwordless",
    56  	}
    57  )
    58  
    59  // AuthPreference defines the authentication preferences for a specific
    60  // cluster. It defines the type (local, oidc) and second factor (off, otp, oidc).
    61  // AuthPreference is a configuration resource, never create more than one instance
    62  // of it.
    63  type AuthPreference interface {
    64  	// Resource provides common resource properties.
    65  	ResourceWithOrigin
    66  
    67  	// GetType gets the type of authentication: local, saml, or oidc.
    68  	GetType() string
    69  	// SetType sets the type of authentication: local, saml, or oidc.
    70  	SetType(string)
    71  
    72  	// GetSecondFactor gets the type of second factor.
    73  	GetSecondFactor() constants.SecondFactorType
    74  	// SetSecondFactor sets the type of second factor.
    75  	SetSecondFactor(constants.SecondFactorType)
    76  	// GetPreferredLocalMFA returns a server-side hint for clients to pick an MFA
    77  	// method when various options are available.
    78  	// It is empty if there is nothing to suggest.
    79  	GetPreferredLocalMFA() constants.SecondFactorType
    80  	// IsSecondFactorEnforced checks if second factor is enforced
    81  	// (not disabled or set to optional).
    82  	IsSecondFactorEnforced() bool
    83  	// IsSecondFactorTOTPAllowed checks if users are allowed to register TOTP devices.
    84  	IsSecondFactorTOTPAllowed() bool
    85  	// IsSecondFactorWebauthnAllowed checks if users are allowed to register
    86  	// Webauthn devices.
    87  	IsSecondFactorWebauthnAllowed() bool
    88  	// IsAdminActionMFAEnforced checks if admin action MFA is enforced.
    89  	IsAdminActionMFAEnforced() bool
    90  
    91  	// GetConnectorName gets the name of the OIDC or SAML connector to use. If
    92  	// this value is empty, we fall back to the first connector in the backend.
    93  	GetConnectorName() string
    94  	// SetConnectorName sets the name of the OIDC or SAML connector to use. If
    95  	// this value is empty, we fall back to the first connector in the backend.
    96  	SetConnectorName(string)
    97  
    98  	// GetU2F gets the U2F configuration settings.
    99  	GetU2F() (*U2F, error)
   100  	// SetU2F sets the U2F configuration settings.
   101  	SetU2F(*U2F)
   102  
   103  	// GetWebauthn returns the Webauthn configuration settings.
   104  	GetWebauthn() (*Webauthn, error)
   105  	// SetWebauthn sets the Webauthn configuration settings.
   106  	SetWebauthn(*Webauthn)
   107  
   108  	// GetAllowPasswordless returns if passwordless is allowed by cluster
   109  	// settings.
   110  	GetAllowPasswordless() bool
   111  	// SetAllowPasswordless sets the value of the allow passwordless setting.
   112  	SetAllowPasswordless(b bool)
   113  
   114  	// GetAllowHeadless returns if headless is allowed by cluster settings.
   115  	GetAllowHeadless() bool
   116  	// SetAllowHeadless sets the value of the allow headless setting.
   117  	SetAllowHeadless(b bool)
   118  
   119  	// GetRequireMFAType returns the type of MFA requirement enforced for this cluster.
   120  	GetRequireMFAType() RequireMFAType
   121  	// GetPrivateKeyPolicy returns the configured private key policy for the cluster.
   122  	GetPrivateKeyPolicy() keys.PrivateKeyPolicy
   123  
   124  	// GetHardwareKey returns the hardware key settings configured for the cluster.
   125  	GetHardwareKey() (*HardwareKey, error)
   126  	// GetPIVSlot returns the configured piv slot for the cluster.
   127  	GetPIVSlot() keys.PIVSlot
   128  	// GetHardwareKeySerialNumberValidation returns the cluster's hardware key
   129  	// serial number validation settings.
   130  	GetHardwareKeySerialNumberValidation() (*HardwareKeySerialNumberValidation, error)
   131  
   132  	// GetDisconnectExpiredCert returns disconnect expired certificate setting
   133  	GetDisconnectExpiredCert() bool
   134  	// SetDisconnectExpiredCert sets disconnect client with expired certificate setting
   135  	SetDisconnectExpiredCert(bool)
   136  
   137  	// GetAllowLocalAuth gets if local authentication is allowed.
   138  	GetAllowLocalAuth() bool
   139  	// SetAllowLocalAuth sets if local authentication is allowed.
   140  	SetAllowLocalAuth(bool)
   141  
   142  	// GetMessageOfTheDay fetches the MOTD
   143  	GetMessageOfTheDay() string
   144  	// SetMessageOfTheDay sets the MOTD
   145  	SetMessageOfTheDay(string)
   146  
   147  	// GetLockingMode gets the cluster-wide locking mode default.
   148  	GetLockingMode() constants.LockingMode
   149  	// SetLockingMode sets the cluster-wide locking mode default.
   150  	SetLockingMode(constants.LockingMode)
   151  
   152  	// GetDeviceTrust returns the cluster device trust settings, or nil if no
   153  	// explicit configurations are present.
   154  	GetDeviceTrust() *DeviceTrust
   155  	// SetDeviceTrust sets the cluster device trust settings.
   156  	SetDeviceTrust(*DeviceTrust)
   157  
   158  	// IsSAMLIdPEnabled returns true if the SAML IdP is enabled.
   159  	IsSAMLIdPEnabled() bool
   160  	// SetSAMLIdPEnabled sets the SAML IdP to enabled.
   161  	SetSAMLIdPEnabled(bool)
   162  
   163  	// GetDefaultSessionTTL retrieves the max session ttl
   164  	GetDefaultSessionTTL() Duration
   165  	// SetDefaultSessionTTL sets the max session ttl
   166  	SetDefaultSessionTTL(Duration)
   167  
   168  	// GetOktaSyncPeriod returns the duration between Okta synchronization calls if the Okta service is running.
   169  	GetOktaSyncPeriod() time.Duration
   170  	// SetOktaSyncPeriod sets the duration between Okta synchronzation calls.
   171  	SetOktaSyncPeriod(timeBetweenSyncs time.Duration)
   172  
   173  	// String represents a human readable version of authentication settings.
   174  	String() string
   175  }
   176  
   177  // NewAuthPreference is a convenience method to to create AuthPreferenceV2.
   178  func NewAuthPreference(spec AuthPreferenceSpecV2) (AuthPreference, error) {
   179  	return newAuthPreferenceWithLabels(spec, map[string]string{})
   180  }
   181  
   182  // NewAuthPreferenceFromConfigFile is a convenience method to create
   183  // AuthPreferenceV2 labeled as originating from config file.
   184  func NewAuthPreferenceFromConfigFile(spec AuthPreferenceSpecV2) (AuthPreference, error) {
   185  	return newAuthPreferenceWithLabels(spec, map[string]string{
   186  		OriginLabel: OriginConfigFile,
   187  	})
   188  }
   189  
   190  // NewAuthPreferenceWithLabels is a convenience method to create
   191  // AuthPreferenceV2 with a specific map of labels.
   192  func newAuthPreferenceWithLabels(spec AuthPreferenceSpecV2, labels map[string]string) (AuthPreference, error) {
   193  	pref := &AuthPreferenceV2{
   194  		Metadata: Metadata{
   195  			Labels: labels,
   196  		},
   197  		Spec: spec,
   198  	}
   199  	if err := pref.CheckAndSetDefaults(); err != nil {
   200  		return nil, trace.Wrap(err)
   201  	}
   202  	return pref, nil
   203  }
   204  
   205  // DefaultAuthPreference returns the default authentication preferences.
   206  func DefaultAuthPreference() AuthPreference {
   207  	authPref, _ := newAuthPreferenceWithLabels(AuthPreferenceSpecV2{}, map[string]string{
   208  		OriginLabel: OriginDefaults,
   209  	})
   210  	return authPref
   211  }
   212  
   213  // GetVersion returns resource version.
   214  func (c *AuthPreferenceV2) GetVersion() string {
   215  	return c.Version
   216  }
   217  
   218  // GetName returns the name of the resource.
   219  func (c *AuthPreferenceV2) GetName() string {
   220  	return c.Metadata.Name
   221  }
   222  
   223  // SetName sets the name of the resource.
   224  func (c *AuthPreferenceV2) SetName(e string) {
   225  	c.Metadata.Name = e
   226  }
   227  
   228  // SetExpiry sets expiry time for the object.
   229  func (c *AuthPreferenceV2) SetExpiry(expires time.Time) {
   230  	c.Metadata.SetExpiry(expires)
   231  }
   232  
   233  // Expiry returns object expiry setting.
   234  func (c *AuthPreferenceV2) Expiry() time.Time {
   235  	return c.Metadata.Expiry()
   236  }
   237  
   238  // GetMetadata returns object metadata.
   239  func (c *AuthPreferenceV2) GetMetadata() Metadata {
   240  	return c.Metadata
   241  }
   242  
   243  // GetResourceID returns resource ID.
   244  func (c *AuthPreferenceV2) GetResourceID() int64 {
   245  	return c.Metadata.ID
   246  }
   247  
   248  // SetResourceID sets resource ID.
   249  func (c *AuthPreferenceV2) SetResourceID(id int64) {
   250  	c.Metadata.ID = id
   251  }
   252  
   253  // GetRevision returns the revision
   254  func (c *AuthPreferenceV2) GetRevision() string {
   255  	return c.Metadata.GetRevision()
   256  }
   257  
   258  // SetRevision sets the revision
   259  func (c *AuthPreferenceV2) SetRevision(rev string) {
   260  	c.Metadata.SetRevision(rev)
   261  }
   262  
   263  // Origin returns the origin value of the resource.
   264  func (c *AuthPreferenceV2) Origin() string {
   265  	return c.Metadata.Origin()
   266  }
   267  
   268  // SetOrigin sets the origin value of the resource.
   269  func (c *AuthPreferenceV2) SetOrigin(origin string) {
   270  	c.Metadata.SetOrigin(origin)
   271  }
   272  
   273  // GetKind returns resource kind.
   274  func (c *AuthPreferenceV2) GetKind() string {
   275  	return c.Kind
   276  }
   277  
   278  // GetSubKind returns resource subkind.
   279  func (c *AuthPreferenceV2) GetSubKind() string {
   280  	return c.SubKind
   281  }
   282  
   283  // SetSubKind sets resource subkind.
   284  func (c *AuthPreferenceV2) SetSubKind(sk string) {
   285  	c.SubKind = sk
   286  }
   287  
   288  // GetType returns the type of authentication.
   289  func (c *AuthPreferenceV2) GetType() string {
   290  	return c.Spec.Type
   291  }
   292  
   293  // SetType sets the type of authentication.
   294  func (c *AuthPreferenceV2) SetType(s string) {
   295  	c.Spec.Type = s
   296  }
   297  
   298  // GetSecondFactor returns the type of second factor.
   299  func (c *AuthPreferenceV2) GetSecondFactor() constants.SecondFactorType {
   300  	return c.Spec.SecondFactor
   301  }
   302  
   303  // SetSecondFactor sets the type of second factor.
   304  func (c *AuthPreferenceV2) SetSecondFactor(s constants.SecondFactorType) {
   305  	c.Spec.SecondFactor = s
   306  }
   307  
   308  func (c *AuthPreferenceV2) GetPreferredLocalMFA() constants.SecondFactorType {
   309  	switch sf := c.GetSecondFactor(); sf {
   310  	case constants.SecondFactorOff:
   311  		return "" // Nothing to suggest.
   312  	case constants.SecondFactorOTP, constants.SecondFactorWebauthn:
   313  		return sf // Single method.
   314  	case constants.SecondFactorOn, constants.SecondFactorOptional:
   315  		// In order of preference:
   316  		// 1. WebAuthn (public-key based)
   317  		// 2. OTP
   318  		if _, err := c.GetWebauthn(); err == nil {
   319  			return constants.SecondFactorWebauthn
   320  		}
   321  		return constants.SecondFactorOTP
   322  	default:
   323  		slog.WarnContext(context.Background(), "Found unknown second_factor setting", "second_factor", sf)
   324  		return "" // Unsure, say nothing.
   325  	}
   326  }
   327  
   328  // IsSecondFactorEnforced checks if second factor is enforced (not disabled or set to optional).
   329  func (c *AuthPreferenceV2) IsSecondFactorEnforced() bool {
   330  	return c.Spec.SecondFactor != constants.SecondFactorOff && c.Spec.SecondFactor != constants.SecondFactorOptional
   331  }
   332  
   333  // IsSecondFactorTOTPAllowed checks if users are allowed to register TOTP devices.
   334  func (c *AuthPreferenceV2) IsSecondFactorTOTPAllowed() bool {
   335  	return c.Spec.SecondFactor == constants.SecondFactorOTP ||
   336  		c.Spec.SecondFactor == constants.SecondFactorOptional ||
   337  		c.Spec.SecondFactor == constants.SecondFactorOn
   338  }
   339  
   340  // IsSecondFactorWebauthnAllowed checks if users are allowed to register
   341  // Webauthn devices.
   342  func (c *AuthPreferenceV2) IsSecondFactorWebauthnAllowed() bool {
   343  	// Is Webauthn configured and enabled?
   344  	switch _, err := c.GetWebauthn(); {
   345  	case trace.IsNotFound(err): // OK, expected to happen in some cases.
   346  		return false
   347  	case err != nil:
   348  		slog.WarnContext(context.Background(), "Got unexpected error when reading Webauthn config", "error", err)
   349  		return false
   350  	}
   351  
   352  	// Are second factor settings in accordance?
   353  	return c.Spec.SecondFactor == constants.SecondFactorWebauthn ||
   354  		c.Spec.SecondFactor == constants.SecondFactorOptional ||
   355  		c.Spec.SecondFactor == constants.SecondFactorOn
   356  }
   357  
   358  // IsAdminActionMFAEnforced checks if admin action MFA is enforced. Currently, the only
   359  // prerequisite for admin action MFA enforcement is whether Webauthn is enforced.
   360  func (c *AuthPreferenceV2) IsAdminActionMFAEnforced() bool {
   361  	return c.Spec.SecondFactor == constants.SecondFactorWebauthn
   362  }
   363  
   364  // GetConnectorName gets the name of the OIDC or SAML connector to use. If
   365  // this value is empty, we fall back to the first connector in the backend.
   366  func (c *AuthPreferenceV2) GetConnectorName() string {
   367  	return c.Spec.ConnectorName
   368  }
   369  
   370  // SetConnectorName sets the name of the OIDC or SAML connector to use. If
   371  // this value is empty, we fall back to the first connector in the backend.
   372  func (c *AuthPreferenceV2) SetConnectorName(cn string) {
   373  	c.Spec.ConnectorName = cn
   374  }
   375  
   376  // GetU2F gets the U2F configuration settings.
   377  func (c *AuthPreferenceV2) GetU2F() (*U2F, error) {
   378  	if c.Spec.U2F == nil {
   379  		return nil, trace.NotFound("U2F is not configured in this cluster, please contact your administrator and ask them to follow https://goteleport.com/docs/access-controls/guides/u2f/")
   380  	}
   381  	return c.Spec.U2F, nil
   382  }
   383  
   384  // SetU2F sets the U2F configuration settings.
   385  func (c *AuthPreferenceV2) SetU2F(u2f *U2F) {
   386  	c.Spec.U2F = u2f
   387  }
   388  
   389  func (c *AuthPreferenceV2) GetWebauthn() (*Webauthn, error) {
   390  	if c.Spec.Webauthn == nil {
   391  		return nil, trace.NotFound("Webauthn is not configured in this cluster, please contact your administrator and ask them to follow https://goteleport.com/docs/access-controls/guides/webauthn/")
   392  	}
   393  	return c.Spec.Webauthn, nil
   394  }
   395  
   396  func (c *AuthPreferenceV2) SetWebauthn(w *Webauthn) {
   397  	c.Spec.Webauthn = w
   398  }
   399  
   400  func (c *AuthPreferenceV2) GetAllowPasswordless() bool {
   401  	return c.Spec.AllowPasswordless != nil && c.Spec.AllowPasswordless.Value
   402  }
   403  
   404  func (c *AuthPreferenceV2) SetAllowPasswordless(b bool) {
   405  	c.Spec.AllowPasswordless = NewBoolOption(b)
   406  }
   407  
   408  func (c *AuthPreferenceV2) GetAllowHeadless() bool {
   409  	return c.Spec.AllowHeadless != nil && c.Spec.AllowHeadless.Value
   410  }
   411  
   412  func (c *AuthPreferenceV2) SetAllowHeadless(b bool) {
   413  	c.Spec.AllowHeadless = NewBoolOption(b)
   414  }
   415  
   416  // GetRequireMFAType returns the type of MFA requirement enforced for this cluster.
   417  func (c *AuthPreferenceV2) GetRequireMFAType() RequireMFAType {
   418  	return c.Spec.RequireMFAType
   419  }
   420  
   421  // GetPrivateKeyPolicy returns the configured private key policy for the cluster.
   422  func (c *AuthPreferenceV2) GetPrivateKeyPolicy() keys.PrivateKeyPolicy {
   423  	switch c.Spec.RequireMFAType {
   424  	case RequireMFAType_SESSION_AND_HARDWARE_KEY:
   425  		return keys.PrivateKeyPolicyHardwareKey
   426  	case RequireMFAType_HARDWARE_KEY_TOUCH:
   427  		return keys.PrivateKeyPolicyHardwareKeyTouch
   428  	case RequireMFAType_HARDWARE_KEY_PIN:
   429  		return keys.PrivateKeyPolicyHardwareKeyPIN
   430  	case RequireMFAType_HARDWARE_KEY_TOUCH_AND_PIN:
   431  		return keys.PrivateKeyPolicyHardwareKeyTouchAndPIN
   432  	default:
   433  		return keys.PrivateKeyPolicyNone
   434  	}
   435  }
   436  
   437  // GetHardwareKey returns the hardware key settings configured for the cluster.
   438  func (c *AuthPreferenceV2) GetHardwareKey() (*HardwareKey, error) {
   439  	if c.Spec.HardwareKey == nil {
   440  		return nil, trace.NotFound("Hardware key support is not configured in this cluster")
   441  	}
   442  	return c.Spec.HardwareKey, nil
   443  }
   444  
   445  // GetPIVSlot returns the configured piv slot for the cluster.
   446  func (c *AuthPreferenceV2) GetPIVSlot() keys.PIVSlot {
   447  	if hk, err := c.GetHardwareKey(); err == nil {
   448  		return keys.PIVSlot(hk.PIVSlot)
   449  	}
   450  	return ""
   451  }
   452  
   453  // GetHardwareKeySerialNumberValidation returns the cluster's hardware key
   454  // serial number validation settings.
   455  func (c *AuthPreferenceV2) GetHardwareKeySerialNumberValidation() (*HardwareKeySerialNumberValidation, error) {
   456  	if c.Spec.HardwareKey == nil || c.Spec.HardwareKey.SerialNumberValidation == nil {
   457  		return nil, trace.NotFound("Hardware key serial number validation is not configured in this cluster")
   458  	}
   459  	return c.Spec.HardwareKey.SerialNumberValidation, nil
   460  }
   461  
   462  // GetDisconnectExpiredCert returns disconnect expired certificate setting
   463  func (c *AuthPreferenceV2) GetDisconnectExpiredCert() bool {
   464  	return c.Spec.DisconnectExpiredCert.Value
   465  }
   466  
   467  // SetDisconnectExpiredCert sets disconnect client with expired certificate setting
   468  func (c *AuthPreferenceV2) SetDisconnectExpiredCert(b bool) {
   469  	c.Spec.DisconnectExpiredCert = NewBoolOption(b)
   470  }
   471  
   472  // GetAllowLocalAuth gets if local authentication is allowed.
   473  func (c *AuthPreferenceV2) GetAllowLocalAuth() bool {
   474  	return c.Spec.AllowLocalAuth.Value
   475  }
   476  
   477  // SetAllowLocalAuth gets if local authentication is allowed.
   478  func (c *AuthPreferenceV2) SetAllowLocalAuth(b bool) {
   479  	c.Spec.AllowLocalAuth = NewBoolOption(b)
   480  }
   481  
   482  // GetMessageOfTheDay gets the current Message Of The Day. May be empty.
   483  func (c *AuthPreferenceV2) GetMessageOfTheDay() string {
   484  	return c.Spec.MessageOfTheDay
   485  }
   486  
   487  // SetMessageOfTheDay sets the current Message Of The Day. May be empty.
   488  func (c *AuthPreferenceV2) SetMessageOfTheDay(motd string) {
   489  	c.Spec.MessageOfTheDay = motd
   490  }
   491  
   492  // GetLockingMode gets the cluster-wide locking mode default.
   493  func (c *AuthPreferenceV2) GetLockingMode() constants.LockingMode {
   494  	return c.Spec.LockingMode
   495  }
   496  
   497  // SetLockingMode sets the cluster-wide locking mode default.
   498  func (c *AuthPreferenceV2) SetLockingMode(mode constants.LockingMode) {
   499  	c.Spec.LockingMode = mode
   500  }
   501  
   502  // GetDeviceTrust returns the cluster device trust settings, or nil if no
   503  // explicit configurations are present.
   504  func (c *AuthPreferenceV2) GetDeviceTrust() *DeviceTrust {
   505  	if c == nil {
   506  		return nil
   507  	}
   508  	return c.Spec.DeviceTrust
   509  }
   510  
   511  // SetDeviceTrust sets the cluster device trust settings.
   512  func (c *AuthPreferenceV2) SetDeviceTrust(dt *DeviceTrust) {
   513  	c.Spec.DeviceTrust = dt
   514  }
   515  
   516  // IsSAMLIdPEnabled returns true if the SAML IdP is enabled.
   517  func (c *AuthPreferenceV2) IsSAMLIdPEnabled() bool {
   518  	return c.Spec.IDP.SAML.Enabled.Value
   519  }
   520  
   521  // SetSAMLIdPEnabled sets the SAML IdP to enabled.
   522  func (c *AuthPreferenceV2) SetSAMLIdPEnabled(enabled bool) {
   523  	c.Spec.IDP.SAML.Enabled = NewBoolOption(enabled)
   524  }
   525  
   526  // SetDefaultSessionTTL sets the default session ttl
   527  func (c *AuthPreferenceV2) SetDefaultSessionTTL(sessionTTL Duration) {
   528  	c.Spec.DefaultSessionTTL = sessionTTL
   529  }
   530  
   531  // GetDefaultSessionTTL retrieves the default session ttl
   532  func (c *AuthPreferenceV2) GetDefaultSessionTTL() Duration {
   533  	return c.Spec.DefaultSessionTTL
   534  }
   535  
   536  // GetOktaSyncPeriod returns the duration between Okta synchronization calls if the Okta service is running.
   537  func (c *AuthPreferenceV2) GetOktaSyncPeriod() time.Duration {
   538  	return c.Spec.Okta.SyncPeriod.Duration()
   539  }
   540  
   541  // SetOktaSyncPeriod sets the duration between Okta synchronzation calls.
   542  func (c *AuthPreferenceV2) SetOktaSyncPeriod(syncPeriod time.Duration) {
   543  	c.Spec.Okta.SyncPeriod = Duration(syncPeriod)
   544  }
   545  
   546  // setStaticFields sets static resource header and metadata fields.
   547  func (c *AuthPreferenceV2) setStaticFields() {
   548  	c.Kind = KindClusterAuthPreference
   549  	c.Version = V2
   550  	c.Metadata.Name = MetaNameClusterAuthPreference
   551  }
   552  
   553  // CheckAndSetDefaults verifies the constraints for AuthPreference.
   554  func (c *AuthPreferenceV2) CheckAndSetDefaults() error {
   555  	c.setStaticFields()
   556  	if err := c.Metadata.CheckAndSetDefaults(); err != nil {
   557  		return trace.Wrap(err)
   558  	}
   559  
   560  	if c.Spec.Type == "" {
   561  		c.Spec.Type = constants.Local
   562  	}
   563  	if c.Spec.SecondFactor == "" {
   564  		c.Spec.SecondFactor = constants.SecondFactorOTP
   565  	}
   566  	if c.Spec.AllowLocalAuth == nil {
   567  		c.Spec.AllowLocalAuth = NewBoolOption(true)
   568  	}
   569  	if c.Spec.DisconnectExpiredCert == nil {
   570  		c.Spec.DisconnectExpiredCert = NewBoolOption(false)
   571  	}
   572  	if c.Spec.LockingMode == "" {
   573  		c.Spec.LockingMode = constants.LockingModeBestEffort
   574  	}
   575  	if c.Origin() == "" {
   576  		c.SetOrigin(OriginDynamic)
   577  	}
   578  
   579  	if c.Spec.DefaultSessionTTL == 0 {
   580  		c.Spec.DefaultSessionTTL = Duration(defaults.CertDuration)
   581  	}
   582  
   583  	switch c.Spec.Type {
   584  	case constants.Local, constants.OIDC, constants.SAML, constants.Github:
   585  		// Note that "type:local" and "local_auth:false" is considered a valid
   586  		// setting, as it is a common idiom for clusters that rely on dynamic
   587  		// configuration.
   588  	default:
   589  		return trace.BadParameter("authentication type %q not supported", c.Spec.Type)
   590  	}
   591  
   592  	if c.Spec.SecondFactor == constants.SecondFactorU2F {
   593  		const deprecationMessage = `` +
   594  			`Second Factor "u2f" is deprecated and marked for removal, using "webauthn" instead. ` +
   595  			`Please update your configuration to use WebAuthn. ` +
   596  			`Refer to https://goteleport.com/docs/access-controls/guides/webauthn/`
   597  		slog.WarnContext(context.Background(), deprecationMessage)
   598  		c.Spec.SecondFactor = constants.SecondFactorWebauthn
   599  	}
   600  
   601  	// Make sure second factor makes sense.
   602  	sf := c.Spec.SecondFactor
   603  	switch sf {
   604  	case constants.SecondFactorOff, constants.SecondFactorOTP:
   605  	case constants.SecondFactorWebauthn:
   606  		// If U2F is present validate it, we can derive Webauthn from it.
   607  		if c.Spec.U2F != nil {
   608  			if err := c.Spec.U2F.Check(); err != nil {
   609  				return trace.Wrap(err)
   610  			}
   611  			if c.Spec.Webauthn == nil {
   612  				// Not a problem, try to derive from U2F.
   613  				c.Spec.Webauthn = &Webauthn{}
   614  			}
   615  		}
   616  		if c.Spec.Webauthn == nil {
   617  			return trace.BadParameter("missing required webauthn configuration for second factor type %q", sf)
   618  		}
   619  		if err := c.Spec.Webauthn.CheckAndSetDefaults(c.Spec.U2F); err != nil {
   620  			return trace.Wrap(err)
   621  		}
   622  	case constants.SecondFactorOn, constants.SecondFactorOptional:
   623  		// The following scenarios are allowed for "on" and "optional":
   624  		// - Webauthn is configured (preferred)
   625  		// - U2F is configured, Webauthn derived from it (U2F-compat mode)
   626  
   627  		if c.Spec.U2F == nil && c.Spec.Webauthn == nil {
   628  			return trace.BadParameter("missing required webauthn configuration for second factor type %q", sf)
   629  		}
   630  
   631  		// Is U2F configured?
   632  		if c.Spec.U2F != nil {
   633  			if err := c.Spec.U2F.Check(); err != nil {
   634  				return trace.Wrap(err)
   635  			}
   636  			if c.Spec.Webauthn == nil {
   637  				// Not a problem, try to derive from U2F.
   638  				c.Spec.Webauthn = &Webauthn{}
   639  			}
   640  		}
   641  
   642  		// Is Webauthn valid? At this point we should always have a config.
   643  		if err := c.Spec.Webauthn.CheckAndSetDefaults(c.Spec.U2F); err != nil {
   644  			return trace.Wrap(err)
   645  		}
   646  	default:
   647  		return trace.BadParameter("second factor type %q not supported", c.Spec.SecondFactor)
   648  	}
   649  
   650  	// Set/validate AllowPasswordless. We need Webauthn first to do this properly.
   651  	hasWebauthn := sf == constants.SecondFactorWebauthn ||
   652  		sf == constants.SecondFactorOn ||
   653  		sf == constants.SecondFactorOptional
   654  	switch {
   655  	case c.Spec.AllowPasswordless == nil:
   656  		c.Spec.AllowPasswordless = NewBoolOption(hasWebauthn)
   657  	case !hasWebauthn && c.Spec.AllowPasswordless.Value:
   658  		return trace.BadParameter("missing required Webauthn configuration for passwordless=true")
   659  	}
   660  
   661  	// Set/validate AllowHeadless. We need Webauthn first to do this properly.
   662  	switch {
   663  	case c.Spec.AllowHeadless == nil:
   664  		c.Spec.AllowHeadless = NewBoolOption(hasWebauthn)
   665  	case !hasWebauthn && c.Spec.AllowHeadless.Value:
   666  		return trace.BadParameter("missing required Webauthn configuration for headless=true")
   667  	}
   668  
   669  	// Validate connector name for type=local.
   670  	if c.Spec.Type == constants.Local {
   671  		switch connectorName := c.Spec.ConnectorName; connectorName {
   672  		case "", constants.LocalConnector: // OK
   673  		case constants.PasswordlessConnector:
   674  			if !c.Spec.AllowPasswordless.Value {
   675  				return trace.BadParameter("invalid local connector %q, passwordless not allowed by cluster settings", connectorName)
   676  			}
   677  		case constants.HeadlessConnector:
   678  			if !c.Spec.AllowHeadless.Value {
   679  				return trace.BadParameter("invalid local connector %q, headless not allowed by cluster settings", connectorName)
   680  			}
   681  		default:
   682  			return trace.BadParameter("invalid local connector %q", connectorName)
   683  		}
   684  	}
   685  
   686  	switch c.Spec.LockingMode {
   687  	case constants.LockingModeBestEffort, constants.LockingModeStrict:
   688  	default:
   689  		return trace.BadParameter("locking mode %q not supported", c.Spec.LockingMode)
   690  	}
   691  
   692  	if dt := c.Spec.DeviceTrust; dt != nil {
   693  		switch dt.Mode {
   694  		case "": // OK, "default" mode. Varies depending on OSS or Enterprise.
   695  		case constants.DeviceTrustModeOff,
   696  			constants.DeviceTrustModeOptional,
   697  			constants.DeviceTrustModeRequired: // OK.
   698  		default:
   699  			return trace.BadParameter("device trust mode %q not supported", dt.Mode)
   700  		}
   701  
   702  		// Ensure configured ekcert_allowed_cas are valid
   703  		for _, pem := range dt.EKCertAllowedCAs {
   704  			if err := isValidCertificatePEM(pem); err != nil {
   705  				return trace.BadParameter("device trust has invalid EKCert allowed CAs entry: %v", err)
   706  			}
   707  		}
   708  	}
   709  
   710  	// TODO(Joerger): DELETE IN 17.0.0
   711  	c.CheckSetPIVSlot()
   712  
   713  	if hk, err := c.GetHardwareKey(); err == nil && hk.PIVSlot != "" {
   714  		if err := keys.PIVSlot(hk.PIVSlot).Validate(); err != nil {
   715  			return trace.Wrap(err)
   716  		}
   717  	}
   718  
   719  	// Make sure the IdP section is populated.
   720  	if c.Spec.IDP == nil {
   721  		c.Spec.IDP = &IdPOptions{}
   722  	}
   723  
   724  	// Make sure the SAML section is populated.
   725  	if c.Spec.IDP.SAML == nil {
   726  		c.Spec.IDP.SAML = &IdPSAMLOptions{}
   727  	}
   728  
   729  	// Make sure the SAML enabled field is populated.
   730  	if c.Spec.IDP.SAML.Enabled == nil {
   731  		// Enable the IdP by default.
   732  		c.Spec.IDP.SAML.Enabled = NewBoolOption(true)
   733  	}
   734  
   735  	// Make sure the Okta field is populated.
   736  	if c.Spec.Okta == nil {
   737  		c.Spec.Okta = &OktaOptions{}
   738  	}
   739  
   740  	return nil
   741  }
   742  
   743  // CheckSetPIVSlot ensures that the PIVSlot and Hardwarekey.PIVSlot stay in sync so that
   744  // older versions of Teleport that do not know about Hardwarekey.PIVSlot are able to keep
   745  // using PIVSlot and newer versions of Teleport can rely solely on Hardwarekey.PIVSlot
   746  // without causing any service degradation.
   747  // TODO(Joerger): DELETE IN 17.0.0
   748  func (c *AuthPreferenceV2) CheckSetPIVSlot() {
   749  	if c.Spec.PIVSlot != "" {
   750  		if c.Spec.HardwareKey == nil {
   751  			c.Spec.HardwareKey = &HardwareKey{}
   752  		}
   753  		c.Spec.HardwareKey.PIVSlot = c.Spec.PIVSlot
   754  	} else if c.Spec.HardwareKey != nil && c.Spec.HardwareKey.PIVSlot != "" {
   755  		c.Spec.PIVSlot = c.Spec.HardwareKey.PIVSlot
   756  	}
   757  }
   758  
   759  // String represents a human readable version of authentication settings.
   760  func (c *AuthPreferenceV2) String() string {
   761  	return fmt.Sprintf("AuthPreference(Type=%q,SecondFactor=%q)", c.Spec.Type, c.Spec.SecondFactor)
   762  }
   763  
   764  func (u *U2F) Check() error {
   765  	if u.AppID == "" {
   766  		return trace.BadParameter("u2f configuration missing app_id")
   767  	}
   768  	for _, ca := range u.DeviceAttestationCAs {
   769  		if err := isValidCertificatePEM(ca); err != nil {
   770  			return trace.BadParameter("u2f configuration has an invalid attestation CA: %v", err)
   771  		}
   772  	}
   773  	return nil
   774  }
   775  
   776  func (w *Webauthn) CheckAndSetDefaults(u *U2F) error {
   777  	// RPID.
   778  	switch {
   779  	case w.RPID != "": // Explicit RPID
   780  		_, err := url.Parse(w.RPID)
   781  		if err != nil {
   782  			return trace.BadParameter("webauthn rp_id is not a valid URI: %v", err)
   783  		}
   784  	case u != nil && w.RPID == "": // Infer RPID from U2F app_id
   785  		parsedAppID, err := url.Parse(u.AppID)
   786  		if err != nil {
   787  			return trace.BadParameter("webauthn missing rp_id and U2F app_id is not an URL (%v)", err)
   788  		}
   789  
   790  		var rpID string
   791  		switch {
   792  		case parsedAppID.Host != "":
   793  			rpID = parsedAppID.Host
   794  			rpID = strings.Split(rpID, ":")[0] // Remove :port, if present
   795  		case parsedAppID.Path == u.AppID:
   796  			// App ID is not a proper URL, take it literally.
   797  			rpID = u.AppID
   798  		default:
   799  			return trace.BadParameter("failed to infer webauthn RPID from U2F App ID (%q)", u.AppID)
   800  		}
   801  		slog.InfoContext(context.Background(), "WebAuthn: RPID inferred from U2F configuration", "rpid", rpID)
   802  		w.RPID = rpID
   803  	default:
   804  		return trace.BadParameter("webauthn configuration missing rp_id")
   805  	}
   806  
   807  	// AttestationAllowedCAs.
   808  	switch {
   809  	case u != nil && len(u.DeviceAttestationCAs) > 0 && len(w.AttestationAllowedCAs) == 0 && len(w.AttestationDeniedCAs) == 0:
   810  		slog.InfoContext(context.Background(), "WebAuthn: using U2F device attestation CAs as allowed CAs")
   811  		w.AttestationAllowedCAs = u.DeviceAttestationCAs
   812  	default:
   813  		for _, pem := range w.AttestationAllowedCAs {
   814  			if err := isValidCertificatePEM(pem); err != nil {
   815  				return trace.BadParameter("webauthn allowed CAs entry invalid: %v", err)
   816  			}
   817  		}
   818  	}
   819  
   820  	// AttestationDeniedCAs.
   821  	for _, pem := range w.AttestationDeniedCAs {
   822  		if err := isValidCertificatePEM(pem); err != nil {
   823  			return trace.BadParameter("webauthn denied CAs entry invalid: %v", err)
   824  		}
   825  	}
   826  
   827  	return nil
   828  }
   829  
   830  func isValidCertificatePEM(pem string) error {
   831  	_, err := tlsutils.ParseCertificatePEM([]byte(pem))
   832  	return err
   833  }
   834  
   835  // Check validates WebauthnLocalAuth, returning an error if it's not valid.
   836  func (wal *WebauthnLocalAuth) Check() error {
   837  	if len(wal.UserID) == 0 {
   838  		return trace.BadParameter("missing UserID field")
   839  	}
   840  	return nil
   841  }
   842  
   843  // NewMFADevice creates a new MFADevice with the given name. Caller must set
   844  // the Device field in the returned MFADevice.
   845  func NewMFADevice(name, id string, addedAt time.Time) *MFADevice {
   846  	return &MFADevice{
   847  		Metadata: Metadata{
   848  			Name: name,
   849  		},
   850  		Id:       id,
   851  		AddedAt:  addedAt,
   852  		LastUsed: addedAt,
   853  	}
   854  }
   855  
   856  // setStaticFields sets static resource header and metadata fields.
   857  func (d *MFADevice) setStaticFields() {
   858  	d.Kind = KindMFADevice
   859  	d.Version = V1
   860  }
   861  
   862  // CheckAndSetDefaults validates MFADevice fields and populates empty fields
   863  // with default values.
   864  func (d *MFADevice) CheckAndSetDefaults() error {
   865  	d.setStaticFields()
   866  	if err := d.Metadata.CheckAndSetDefaults(); err != nil {
   867  		return trace.Wrap(err)
   868  	}
   869  	if d.Id == "" {
   870  		return trace.BadParameter("MFADevice missing ID field")
   871  	}
   872  	if d.AddedAt.IsZero() {
   873  		return trace.BadParameter("MFADevice missing AddedAt field")
   874  	}
   875  	if d.LastUsed.IsZero() {
   876  		return trace.BadParameter("MFADevice missing LastUsed field")
   877  	}
   878  	if d.LastUsed.Before(d.AddedAt) {
   879  		return trace.BadParameter("MFADevice LastUsed field must be earlier than AddedAt")
   880  	}
   881  	if d.Device == nil {
   882  		return trace.BadParameter("MFADevice missing Device field")
   883  	}
   884  	if err := checkWebauthnDevice(d); err != nil {
   885  		return trace.Wrap(err)
   886  	}
   887  	return nil
   888  }
   889  
   890  func checkWebauthnDevice(d *MFADevice) error {
   891  	wrapper, ok := d.Device.(*MFADevice_Webauthn)
   892  	if !ok {
   893  		return nil
   894  	}
   895  	switch webDev := wrapper.Webauthn; {
   896  	case webDev == nil:
   897  		return trace.BadParameter("MFADevice has malformed WebauthnDevice")
   898  	case len(webDev.CredentialId) == 0:
   899  		return trace.BadParameter("WebauthnDevice missing CredentialId field")
   900  	case len(webDev.PublicKeyCbor) == 0:
   901  		return trace.BadParameter("WebauthnDevice missing PublicKeyCbor field")
   902  	default:
   903  		return nil
   904  	}
   905  }
   906  
   907  func (d *MFADevice) GetKind() string         { return d.Kind }
   908  func (d *MFADevice) GetSubKind() string      { return d.SubKind }
   909  func (d *MFADevice) SetSubKind(sk string)    { d.SubKind = sk }
   910  func (d *MFADevice) GetVersion() string      { return d.Version }
   911  func (d *MFADevice) GetMetadata() Metadata   { return d.Metadata }
   912  func (d *MFADevice) GetName() string         { return d.Metadata.GetName() }
   913  func (d *MFADevice) SetName(n string)        { d.Metadata.SetName(n) }
   914  func (d *MFADevice) GetResourceID() int64    { return d.Metadata.GetID() }
   915  func (d *MFADevice) SetResourceID(id int64)  { d.Metadata.SetID(id) }
   916  func (d *MFADevice) GetRevision() string     { return d.Metadata.GetRevision() }
   917  func (d *MFADevice) SetRevision(rev string)  { d.Metadata.SetRevision(rev) }
   918  func (d *MFADevice) Expiry() time.Time       { return d.Metadata.Expiry() }
   919  func (d *MFADevice) SetExpiry(exp time.Time) { d.Metadata.SetExpiry(exp) }
   920  
   921  // MFAType returns the human-readable name of the MFA protocol of this device.
   922  func (d *MFADevice) MFAType() string {
   923  	switch d.Device.(type) {
   924  	case *MFADevice_Totp:
   925  		return "TOTP"
   926  	case *MFADevice_U2F:
   927  		return "U2F"
   928  	case *MFADevice_Webauthn:
   929  		return "WebAuthn"
   930  	default:
   931  		return "unknown"
   932  	}
   933  }
   934  
   935  func (d *MFADevice) MarshalJSON() ([]byte, error) {
   936  	buf := new(bytes.Buffer)
   937  	err := (&jsonpb.Marshaler{}).Marshal(buf, d)
   938  	return buf.Bytes(), trace.Wrap(err)
   939  }
   940  
   941  func (d *MFADevice) UnmarshalJSON(buf []byte) error {
   942  	unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: true}
   943  	err := unmarshaler.Unmarshal(bytes.NewReader(buf), d)
   944  	return trace.Wrap(err)
   945  }
   946  
   947  // IsSessionMFARequired returns whether this RequireMFAType requires per-session MFA.
   948  func (r RequireMFAType) IsSessionMFARequired() bool {
   949  	return r != RequireMFAType_OFF
   950  }
   951  
   952  // MarshalJSON marshals RequireMFAType to boolean or string.
   953  func (r *RequireMFAType) MarshalYAML() (interface{}, error) {
   954  	val, err := r.encode()
   955  	if err != nil {
   956  		return nil, trace.Wrap(err)
   957  	}
   958  	return val, nil
   959  }
   960  
   961  // UnmarshalYAML supports parsing RequireMFAType from boolean or alias.
   962  func (r *RequireMFAType) UnmarshalYAML(unmarshal func(interface{}) error) error {
   963  	var val interface{}
   964  	err := unmarshal(&val)
   965  	if err != nil {
   966  		return trace.Wrap(err)
   967  	}
   968  
   969  	err = r.decode(val)
   970  	return trace.Wrap(err)
   971  }
   972  
   973  // MarshalJSON marshals RequireMFAType to boolean or string.
   974  func (r *RequireMFAType) MarshalJSON() ([]byte, error) {
   975  	val, err := r.encode()
   976  	if err != nil {
   977  		return nil, trace.Wrap(err)
   978  	}
   979  	out, err := json.Marshal(val)
   980  	return out, trace.Wrap(err)
   981  }
   982  
   983  // UnmarshalJSON supports parsing RequireMFAType from boolean or alias.
   984  func (r *RequireMFAType) UnmarshalJSON(data []byte) error {
   985  	var val interface{}
   986  	err := json.Unmarshal(data, &val)
   987  	if err != nil {
   988  		return trace.Wrap(err)
   989  	}
   990  
   991  	err = r.decode(val)
   992  	return trace.Wrap(err)
   993  }
   994  
   995  const (
   996  	// RequireMFATypeHardwareKeyString is the string representation of RequireMFATypeHardwareKey
   997  	RequireMFATypeHardwareKeyString = "hardware_key"
   998  	// RequireMFATypeHardwareKeyTouchString is the string representation of RequireMFATypeHardwareKeyTouch
   999  	RequireMFATypeHardwareKeyTouchString = "hardware_key_touch"
  1000  	// RequireMFATypeHardwareKeyPINString is the string representation of RequireMFATypeHardwareKeyPIN
  1001  	RequireMFATypeHardwareKeyPINString = "hardware_key_pin"
  1002  	// RequireMFATypeHardwareKeyTouchAndPINString is the string representation of RequireMFATypeHardwareKeyTouchAndPIN
  1003  	RequireMFATypeHardwareKeyTouchAndPINString = "hardware_key_touch_and_pin"
  1004  )
  1005  
  1006  // encode RequireMFAType into a string or boolean. This is necessary for
  1007  // backwards compatibility with the json/yaml tag "require_session_mfa",
  1008  // which used to be a boolean.
  1009  func (r *RequireMFAType) encode() (interface{}, error) {
  1010  	switch *r {
  1011  	case RequireMFAType_OFF:
  1012  		return false, nil
  1013  	case RequireMFAType_SESSION:
  1014  		return true, nil
  1015  	case RequireMFAType_SESSION_AND_HARDWARE_KEY:
  1016  		return RequireMFATypeHardwareKeyString, nil
  1017  	case RequireMFAType_HARDWARE_KEY_TOUCH:
  1018  		return RequireMFATypeHardwareKeyTouchString, nil
  1019  	case RequireMFAType_HARDWARE_KEY_PIN:
  1020  		return RequireMFATypeHardwareKeyPINString, nil
  1021  	case RequireMFAType_HARDWARE_KEY_TOUCH_AND_PIN:
  1022  		return RequireMFATypeHardwareKeyTouchAndPINString, nil
  1023  	default:
  1024  		return nil, trace.BadParameter("RequireMFAType invalid value %v", *r)
  1025  	}
  1026  }
  1027  
  1028  // decode RequireMFAType from a string or boolean. This is necessary for
  1029  // backwards compatibility with the json/yaml tag "require_session_mfa",
  1030  // which used to be a boolean.
  1031  func (r *RequireMFAType) decode(val interface{}) error {
  1032  	switch v := val.(type) {
  1033  	case string:
  1034  		switch v {
  1035  		case RequireMFATypeHardwareKeyString:
  1036  			*r = RequireMFAType_SESSION_AND_HARDWARE_KEY
  1037  		case RequireMFATypeHardwareKeyTouchString:
  1038  			*r = RequireMFAType_HARDWARE_KEY_TOUCH
  1039  		case RequireMFATypeHardwareKeyPINString:
  1040  			*r = RequireMFAType_HARDWARE_KEY_PIN
  1041  		case RequireMFATypeHardwareKeyTouchAndPINString:
  1042  			*r = RequireMFAType_HARDWARE_KEY_TOUCH_AND_PIN
  1043  		case "":
  1044  			// default to off
  1045  			*r = RequireMFAType_OFF
  1046  		default:
  1047  			// try parsing as a boolean
  1048  			switch strings.ToLower(v) {
  1049  			case "yes", "yeah", "y", "true", "1", "on":
  1050  				*r = RequireMFAType_SESSION
  1051  			case "no", "nope", "n", "false", "0", "off":
  1052  				*r = RequireMFAType_OFF
  1053  			default:
  1054  				return trace.BadParameter("RequireMFAType invalid value %v", val)
  1055  			}
  1056  		}
  1057  	case bool:
  1058  		if v {
  1059  			*r = RequireMFAType_SESSION
  1060  		} else {
  1061  			*r = RequireMFAType_OFF
  1062  		}
  1063  	case int32:
  1064  		return trace.Wrap(r.setFromEnum(v))
  1065  	case int64:
  1066  		return trace.Wrap(r.setFromEnum(int32(v)))
  1067  	case int:
  1068  		return trace.Wrap(r.setFromEnum(int32(v)))
  1069  	case float64:
  1070  		return trace.Wrap(r.setFromEnum(int32(v)))
  1071  	case float32:
  1072  		return trace.Wrap(r.setFromEnum(int32(v)))
  1073  	default:
  1074  		return trace.BadParameter("RequireMFAType invalid type %T", val)
  1075  	}
  1076  	return nil
  1077  }
  1078  
  1079  // setFromEnum sets the value from enum value as int32.
  1080  func (r *RequireMFAType) setFromEnum(val int32) error {
  1081  	if _, ok := RequireMFAType_name[val]; !ok {
  1082  		return trace.BadParameter("invalid required mfa mode %v", val)
  1083  	}
  1084  	*r = RequireMFAType(val)
  1085  	return nil
  1086  }