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 }