feat: SSO MFA - support for OIDC MaxAge (#47292)

* Add max age to oidc mfa settings.

* Validate oidc max age.

* Update error message.

* Upate terraform schema and docs and crds.
This commit is contained in:
Brian Joerger 2024-10-16 13:19:18 -07:00 committed by GitHub
parent 4c76609576
commit 94295c981c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 1833 additions and 1725 deletions

View file

@ -4600,6 +4600,10 @@ message OIDCConnectorMFASettings {
// Prompt is an optional OIDC prompt. An empty string omits prompt.
// If not specified, it defaults to select_account for backwards compatibility.
string prompt = 5;
// MaxAge is the amount of time in nanoseconds that an IdP session is valid for. Defaults to
// 0 to always force re-authentication for MFA checks. This should only be set to a non-zero
// value if the IdP is setup to perform MFA checks on top of active user sessions.
int64 max_age = 6 [(gogoproto.casttype) = "Duration"];
}
// OIDCAuthRequest is a request to authenticate with OIDC

View file

@ -110,7 +110,7 @@ type OIDCConnector interface {
// GetClientRedirectSettings returns the client redirect settings.
GetClientRedirectSettings() *SSOClientRedirectSettings
// GetMFASettings returns the connector's MFA settings.
GetMFASettings() OIDCConnectorMFASettings
GetMFASettings() *OIDCConnectorMFASettings
// IsMFAEnabled returns whether the connector has MFA enabled.
IsMFAEnabled() bool
// WithMFASettings returns the connector will some settings overwritten set from MFA settings.
@ -465,7 +465,17 @@ func (o *OIDCConnectorV3) CheckAndSetDefaults() error {
return trace.BadParameter("max_age cannot be negative")
}
if maxAge.Round(time.Second) != maxAge {
return trace.BadParameter("max_age must be a multiple of seconds")
return trace.BadParameter("max_age %q is invalid, cannot have sub-second units", maxAge.String())
}
}
if o.Spec.MFASettings != nil {
maxAge := o.Spec.MFASettings.MaxAge.Duration()
if maxAge < 0 {
return trace.BadParameter("max_age cannot be negative")
}
if maxAge.Round(time.Second) != maxAge {
return trace.BadParameter("max_age %q invalid, cannot have sub-second units", maxAge.String())
}
}
@ -514,18 +524,14 @@ func (o *OIDCConnectorV3) GetClientRedirectSettings() *SSOClientRedirectSettings
}
// GetMFASettings returns the connector's MFA settings.
func (o *OIDCConnectorV3) GetMFASettings() OIDCConnectorMFASettings {
if o.Spec.MFASettings == nil {
return OIDCConnectorMFASettings{
Enabled: false,
}
}
return *o.Spec.MFASettings
func (o *OIDCConnectorV3) GetMFASettings() *OIDCConnectorMFASettings {
return o.Spec.MFASettings
}
// IsMFAEnabled returns whether the connector has MFA enabled.
func (o *OIDCConnectorV3) IsMFAEnabled() bool {
return o.GetMFASettings().Enabled
mfa := o.GetMFASettings()
return mfa != nil && mfa.Enabled
}
// WithMFASettings returns the connector will some settings overwritten set from MFA settings.
@ -538,6 +544,9 @@ func (o *OIDCConnectorV3) WithMFASettings() error {
o.Spec.ClientSecret = o.Spec.MFASettings.ClientSecret
o.Spec.ACR = o.Spec.MFASettings.AcrValues
o.Spec.Prompt = o.Spec.MFASettings.Prompt
o.Spec.MaxAge = &MaxAge{
Value: o.Spec.MFASettings.MaxAge,
}
return nil
}

File diff suppressed because it is too large Load diff

View file

@ -68,5 +68,6 @@ resource, which you can apply after installing the Teleport Kubernetes operator.
|client_id|string|ClientID is the OIDC OAuth app client ID.|
|client_secret|string|ClientSecret is the OIDC OAuth app client secret.|
|enabled|boolean|Enabled specified whether this OIDC connector supports MFA checks. Defaults to false.|
|max_age|string|MaxAge is the amount of time in nanoseconds that an IdP session is valid for. Defaults to 0 to always force re-authentication for MFA checks. This should only be set to a non-zero value if the IdP is setup to perform MFA checks on top of active user sessions.|
|prompt|string|Prompt is an optional OIDC prompt. An empty string omits prompt. If not specified, it defaults to select_account for backwards compatibility.|

View file

@ -71,6 +71,7 @@ Optional:
- `client_id` (String) ClientID is the OIDC OAuth app client ID.
- `client_secret` (String) ClientSecret is the OIDC OAuth app client secret.
- `enabled` (Boolean) Enabled specified whether this OIDC connector supports MFA checks. Defaults to false.
- `max_age` (String) MaxAge is the amount of time in nanoseconds that an IdP session is valid for. Defaults to 0 to always force re-authentication for MFA checks. This should only be set to a non-zero value if the IdP is setup to perform MFA checks on top of active user sessions.
- `prompt` (String) Prompt is an optional OIDC prompt. An empty string omits prompt. If not specified, it defaults to select_account for backwards compatibility.

View file

@ -101,6 +101,7 @@ Optional:
- `client_id` (String) ClientID is the OIDC OAuth app client ID.
- `client_secret` (String) ClientSecret is the OIDC OAuth app client secret.
- `enabled` (Boolean) Enabled specified whether this OIDC connector supports MFA checks. Defaults to false.
- `max_age` (String) MaxAge is the amount of time in nanoseconds that an IdP session is valid for. Defaults to 0 to always force re-authentication for MFA checks. This should only be set to a non-zero value if the IdP is setup to perform MFA checks on top of active user sessions.
- `prompt` (String) Prompt is an optional OIDC prompt. An empty string omits prompt. If not specified, it defaults to select_account for backwards compatibility.

View file

@ -138,6 +138,14 @@ spec:
description: Enabled specified whether this OIDC connector supports
MFA checks. Defaults to false.
type: boolean
max_age:
description: MaxAge is the amount of time in nanoseconds that
an IdP session is valid for. Defaults to 0 to always force re-authentication
for MFA checks. This should only be set to a non-zero value
if the IdP is setup to perform MFA checks on top of active user
sessions.
format: duration
type: string
prompt:
description: Prompt is an optional OIDC prompt. An empty string
omits prompt. If not specified, it defaults to select_account

View file

@ -138,6 +138,14 @@ spec:
description: Enabled specified whether this OIDC connector supports
MFA checks. Defaults to false.
type: boolean
max_age:
description: MaxAge is the amount of time in nanoseconds that
an IdP session is valid for. Defaults to 0 to always force re-authentication
for MFA checks. This should only be set to a non-zero value
if the IdP is setup to perform MFA checks on top of active user
sessions.
format: duration
type: string
prompt:
description: Prompt is an optional OIDC prompt. An empty string
omits prompt. If not specified, it defaults to select_account

View file

@ -2961,6 +2961,11 @@ func GenSchemaOIDCConnectorV3(ctx context.Context) (github_com_hashicorp_terrafo
Optional: true,
Type: github_com_hashicorp_terraform_plugin_framework_types.BoolType,
},
"max_age": {
Description: "MaxAge is the amount of time in nanoseconds that an IdP session is valid for. Defaults to 0 to always force re-authentication for MFA checks. This should only be set to a non-zero value if the IdP is setup to perform MFA checks on top of active user sessions.",
Optional: true,
Type: DurationType{},
},
"prompt": {
Description: "Prompt is an optional OIDC prompt. An empty string omits prompt. If not specified, it defaults to select_account for backwards compatibility.",
Optional: true,
@ -29448,6 +29453,23 @@ func CopyOIDCConnectorV3FromTerraform(_ context.Context, tf github_com_hashicorp
}
}
}
{
a, ok := tf.Attrs["max_age"]
if !ok {
diags.Append(attrReadMissingDiag{"OIDCConnectorV3.Spec.MFASettings.max_age"})
} else {
v, ok := a.(DurationValue)
if !ok {
diags.Append(attrReadConversionFailureDiag{"OIDCConnectorV3.Spec.MFASettings.max_age", "DurationValue"})
} else {
var t github_com_gravitational_teleport_api_types.Duration
if !v.Null && !v.Unknown {
t = github_com_gravitational_teleport_api_types.Duration(v.Value)
}
obj.MaxAge = t
}
}
}
}
}
}
@ -30531,6 +30553,28 @@ func CopyOIDCConnectorV3ToTerraform(ctx context.Context, obj *github_com_gravita
tf.Attrs["prompt"] = v
}
}
{
t, ok := tf.AttrTypes["max_age"]
if !ok {
diags.Append(attrWriteMissingDiag{"OIDCConnectorV3.Spec.MFASettings.max_age"})
} else {
v, ok := tf.Attrs["max_age"].(DurationValue)
if !ok {
i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil))
if err != nil {
diags.Append(attrWriteGeneralError{"OIDCConnectorV3.Spec.MFASettings.max_age", err})
}
v, ok = i.(DurationValue)
if !ok {
diags.Append(attrWriteConversionFailureDiag{"OIDCConnectorV3.Spec.MFASettings.max_age", "DurationValue"})
}
v.Null = false
}
v.Value = time.Duration(obj.MaxAge)
v.Unknown = false
tf.Attrs["max_age"] = v
}
}
}
v.Unknown = false
tf.Attrs["mfa"] = v