Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add OIE support for MFA policies. #919

Merged
merged 1 commit into from
Feb 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions okta/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ var (
Default: statusActive,
ValidateDiagFunc: elemInSlice([]string{statusActive, statusInactive}),
}

isOieSchema = &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "Is the policy using Okta Identity Engine (OIE) with authenticators instead of factors?",
}
)

func findPolicy(ctx context.Context, m interface{}, name, policyType string) (*okta.Policy, error) {
Expand Down Expand Up @@ -137,6 +144,20 @@ func buildPolicySchema(target map[string]*schema.Schema) map[string]*schema.Sche
return buildSchema(basePolicySchema, target)
}

func buildDefaultMfaPolicySchema(target map[string]*schema.Schema) map[string]*schema.Schema {
schema := buildDefaultPolicySchema(target)
schema["is_oie"] = isOieSchema

return schema
}

func buildMfaPolicySchema(target map[string]*schema.Schema) map[string]*schema.Schema {
schema := buildPolicySchema(target)
schema["is_oie"] = isOieSchema

return schema
}

func createPolicy(ctx context.Context, d *schema.ResourceData, m interface{}, template sdk.Policy) error {
logger(m).Info("creating policy", "name", template.Name, "type", template.Type)
if err := ensureNotDefaultPolicy(d); err != nil {
Expand Down
13 changes: 5 additions & 8 deletions okta/resource_okta_authenticator.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,11 @@ func resourceAuthenticator() *schema.Resource {
},
Schema: map[string]*schema.Schema{
"key": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "A human-readable string that identifies the Authenticator",
ValidateDiagFunc: elemInSlice([]string{
"okta_email", "google_otp", "okta_verify", "onprem_mfa", "okta_password",
"phone_number", "rsa_token", "security_question", "duo",
}),
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "A human-readable string that identifies the Authenticator",
ValidateDiagFunc: elemInSlice(sdk.AuthenticatorProviders),
},
"name": {
Type: schema.TypeString,
Expand Down
26 changes: 5 additions & 21 deletions okta/resource_okta_factor.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,11 @@ func resourceFactor() *schema.Resource {
},
Schema: map[string]*schema.Schema{
"provider_id": {
Type: schema.TypeString,
Required: true,
ValidateDiagFunc: elemInSlice([]string{
sdk.DuoFactor,
sdk.FidoU2fFactor,
sdk.FidoWebauthnFactor,
sdk.GoogleOtpFactor,
sdk.OktaCallFactor,
sdk.OktaOtpFactor,
sdk.OktaPasswordFactor,
sdk.OktaPushFactor,
sdk.OktaQuestionFactor,
sdk.OktaSmsFactor,
sdk.OktaEmailFactor,
sdk.RsaTokenFactor,
sdk.SymantecVipFactor,
sdk.YubikeyTokenFactor,
sdk.HotpFactor,
}),
Description: "Factor provider ID",
ForceNew: true,
Type: schema.TypeString,
Required: true,
ValidateDiagFunc: elemInSlice(sdk.FactorProviders),
Description: "Factor provider ID",
ForceNew: true,
},
"active": {
Type: schema.TypeBool,
Expand Down
167 changes: 103 additions & 64 deletions okta/resource_okta_policy_mfa.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func resourcePolicyMfa() *schema.Resource {
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
Schema: buildPolicySchema(buildFactorProviders()),
Schema: buildMfaPolicySchema(buildFactorSchemaProviders()),
}
}

Expand All @@ -41,21 +41,9 @@ func resourcePolicyMfaRead(ctx context.Context, d *schema.ResourceData, m interf
if policy == nil {
return nil
}
syncFactor(d, sdk.DuoFactor, policy.Settings.Factors.Duo)
syncFactor(d, sdk.FidoU2fFactor, policy.Settings.Factors.FidoU2f)
syncFactor(d, sdk.FidoWebauthnFactor, policy.Settings.Factors.FidoWebauthn)
syncFactor(d, sdk.GoogleOtpFactor, policy.Settings.Factors.GoogleOtp)
syncFactor(d, sdk.OktaCallFactor, policy.Settings.Factors.OktaCall)
syncFactor(d, sdk.OktaOtpFactor, policy.Settings.Factors.OktaOtp)
syncFactor(d, sdk.OktaPasswordFactor, policy.Settings.Factors.OktaPassword)
syncFactor(d, sdk.OktaPushFactor, policy.Settings.Factors.OktaPush)
syncFactor(d, sdk.OktaQuestionFactor, policy.Settings.Factors.OktaQuestion)
syncFactor(d, sdk.OktaSmsFactor, policy.Settings.Factors.OktaSms)
syncFactor(d, sdk.OktaEmailFactor, policy.Settings.Factors.OktaEmail)
syncFactor(d, sdk.RsaTokenFactor, policy.Settings.Factors.RsaToken)
syncFactor(d, sdk.SymantecVipFactor, policy.Settings.Factors.SymantecVip)
syncFactor(d, sdk.YubikeyTokenFactor, policy.Settings.Factors.YubikeyToken)
syncFactor(d, sdk.HotpFactor, policy.Settings.Factors.Hotp)

syncSettings(d, policy.Settings)

err = syncPolicyFromUpstream(d, policy)
if err != nil {
return diag.Errorf("failed to sync policy: %v", err)
Expand All @@ -80,23 +68,6 @@ func resourcePolicyMfaDelete(ctx context.Context, d *schema.ResourceData, m inte
return nil
}

func buildFactorProvider(d *schema.ResourceData, key string) *sdk.PolicyFactor {
rawFactor := d.Get(key).(map[string]interface{})
consent := rawFactor["consent_type"]
enroll := rawFactor["enroll"]
if consent == nil && enroll == nil {
return nil
}
f := &sdk.PolicyFactor{}
if consent != nil {
f.Consent = &sdk.Consent{Type: consent.(string)}
}
if enroll != nil {
f.Enroll = &sdk.Enroll{Self: enroll.(string)}
}
return f
}

// create or update a MFA policy
func buildMFAPolicy(d *schema.ResourceData) sdk.Policy {
policy := sdk.MfaPolicy()
Expand All @@ -106,12 +77,47 @@ func buildMFAPolicy(d *schema.ResourceData) sdk.Policy {
if priority, ok := d.GetOk("priority"); ok {
policy.Priority = int64(priority.(int))
}
policy.Settings = &sdk.PolicySettings{
policy.Settings = buildSettings(d)
policy.Conditions = &okta.PolicyRuleConditions{
People: getGroups(d),
}
return policy
}

// Opposite of syncSettings(): Build the corresponding sdk.PolicySettings based on the schema.ResourceData
func buildSettings(d *schema.ResourceData) *sdk.PolicySettings {
if d.Get("is_oie") == true {
authenticators := []*sdk.PolicyAuthenticator{}

for _, key := range remove(sdk.AuthenticatorProviders, sdk.OktaPasswordFactor) {
rawFactor := d.Get(key).(map[string]interface{})
enroll := rawFactor["enroll"]
if enroll == nil {
continue
}

authenticator := &sdk.PolicyAuthenticator{}
authenticator.Key = key
if enroll != nil {
authenticator.Enroll = &sdk.Enroll{Self: enroll.(string)}
}
authenticators = append(authenticators, authenticator)
}

return &sdk.PolicySettings{
Type: "AUTHENTICATORS",
Authenticators: authenticators,
}
}

return &sdk.PolicySettings{
Type: "FACTORS",
Factors: &sdk.PolicyFactorsSettings{
Duo: buildFactorProvider(d, sdk.DuoFactor),
FidoU2f: buildFactorProvider(d, sdk.FidoU2fFactor),
FidoWebauthn: buildFactorProvider(d, sdk.FidoWebauthnFactor),
GoogleOtp: buildFactorProvider(d, sdk.GoogleOtpFactor),
Hotp: buildFactorProvider(d, sdk.HotpFactor),
OktaCall: buildFactorProvider(d, sdk.OktaCallFactor),
OktaOtp: buildFactorProvider(d, sdk.OktaOtpFactor),
OktaPassword: buildFactorProvider(d, sdk.OktaPasswordFactor),
Expand All @@ -122,51 +128,84 @@ func buildMFAPolicy(d *schema.ResourceData) sdk.Policy {
RsaToken: buildFactorProvider(d, sdk.RsaTokenFactor),
SymantecVip: buildFactorProvider(d, sdk.SymantecVipFactor),
YubikeyToken: buildFactorProvider(d, sdk.YubikeyTokenFactor),
Hotp: buildFactorProvider(d, sdk.HotpFactor),
},
}
policy.Conditions = &okta.PolicyRuleConditions{
People: getGroups(d),
}

func buildFactorProvider(d *schema.ResourceData, key string) *sdk.PolicyFactor {
rawFactor := d.Get(key).(map[string]interface{})
consent := rawFactor["consent_type"]
enroll := rawFactor["enroll"]
if consent == nil && enroll == nil {
return nil
}
f := &sdk.PolicyFactor{}
if consent != nil {
f.Consent = &sdk.Consent{Type: consent.(string)}
}
if enroll != nil {
f.Enroll = &sdk.Enroll{Self: enroll.(string)}
}
return f
}

// Syncs either classic factors or OIE authenticators into the resource data.
func syncSettings(d *schema.ResourceData, settings *sdk.PolicySettings) {
_ = d.Set("is_oie", settings.Type == "AUTHENTICATORS")

if settings.Type == "AUTHENTICATORS" {
for _, key := range remove(sdk.AuthenticatorProviders, sdk.OktaPasswordFactor) {
syncAuthenticator(d, key, settings.Authenticators)
}
} else {
syncFactor(d, sdk.DuoFactor, settings.Factors.Duo)
syncFactor(d, sdk.HotpFactor, settings.Factors.YubikeyToken)
syncFactor(d, sdk.FidoU2fFactor, settings.Factors.FidoU2f)
syncFactor(d, sdk.FidoWebauthnFactor, settings.Factors.FidoWebauthn)
syncFactor(d, sdk.GoogleOtpFactor, settings.Factors.GoogleOtp)
syncFactor(d, sdk.OktaCallFactor, settings.Factors.OktaCall)
syncFactor(d, sdk.OktaOtpFactor, settings.Factors.OktaOtp)
syncFactor(d, sdk.OktaPasswordFactor, settings.Factors.OktaPassword)
syncFactor(d, sdk.OktaPushFactor, settings.Factors.OktaPush)
syncFactor(d, sdk.OktaQuestionFactor, settings.Factors.OktaQuestion)
syncFactor(d, sdk.OktaSmsFactor, settings.Factors.OktaSms)
syncFactor(d, sdk.OktaEmailFactor, settings.Factors.OktaEmail)
syncFactor(d, sdk.RsaTokenFactor, settings.Factors.RsaToken)
syncFactor(d, sdk.SymantecVipFactor, settings.Factors.SymantecVip)
syncFactor(d, sdk.YubikeyTokenFactor, settings.Factors.YubikeyToken)
}
return policy
}

func syncFactor(d *schema.ResourceData, k string, f *sdk.PolicyFactor) {
if f == nil {
if f != nil {
_ = d.Set(k, map[string]interface{}{
"consent_type": "NONE",
"enroll": "NOT_ALLOWED",
"consent_type": f.Consent.Type,
"enroll": f.Enroll.Self,
})
return
}
_ = d.Set(k, map[string]interface{}{
"consent_type": f.Consent.Type,
"enroll": f.Enroll.Self,
})
}

var factorProviders = []string{
sdk.DuoFactor,
sdk.FidoU2fFactor,
sdk.FidoWebauthnFactor,
sdk.GoogleOtpFactor,
sdk.OktaCallFactor,
sdk.OktaOtpFactor,
sdk.OktaPasswordFactor,
sdk.OktaPushFactor,
sdk.OktaQuestionFactor,
sdk.OktaSmsFactor,
sdk.OktaEmailFactor,
sdk.RsaTokenFactor,
sdk.SymantecVipFactor,
sdk.YubikeyTokenFactor,
sdk.HotpFactor,
func syncAuthenticator(d *schema.ResourceData, k string, authenticators []*sdk.PolicyAuthenticator) {
for _, authenticator := range authenticators {
if authenticator.Key == k {
// Skip OktaPassword as this should never be returned for MFA policies using authenticator.
// Enrollment policy changes for OIE for password
// https://help.okta.com/okta_help.htm?type=oie&id=ext-about-mfa-enrol-policies
if k != sdk.OktaPasswordFactor {
_ = d.Set(k, map[string]interface{}{
"enroll": authenticator.Enroll.Self,
})
}
return
}
}
}

// List of factor provider above, they all follow the same schema
func buildFactorProviders() map[string]*schema.Schema {
func buildFactorSchemaProviders() map[string]*schema.Schema {
res := make(map[string]*schema.Schema)
for _, key := range factorProviders {
// Note: It's okay to append and have duplicates as we're setting back into a map here
for _, key := range append(sdk.FactorProviders, sdk.AuthenticatorProviders...) {
res[key] = &schema.Schema{
Optional: true,
Type: schema.TypeMap,
Expand Down
40 changes: 5 additions & 35 deletions okta/resource_okta_policy_mfa_default.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func resourcePolicyMfaDefault() *schema.Resource {
return []*schema.ResourceData{d}, nil
},
},
Schema: buildDefaultPolicySchema(buildFactorProviders()),
Schema: buildDefaultMfaPolicySchema(buildFactorSchemaProviders()),
}
}

Expand Down Expand Up @@ -52,21 +52,9 @@ func resourcePolicyMfaDefaultRead(ctx context.Context, d *schema.ResourceData, m
if policy == nil {
return nil
}
syncFactor(d, sdk.DuoFactor, policy.Settings.Factors.Duo)
syncFactor(d, sdk.FidoU2fFactor, policy.Settings.Factors.FidoU2f)
syncFactor(d, sdk.FidoWebauthnFactor, policy.Settings.Factors.FidoWebauthn)
syncFactor(d, sdk.GoogleOtpFactor, policy.Settings.Factors.GoogleOtp)
syncFactor(d, sdk.OktaCallFactor, policy.Settings.Factors.OktaCall)
syncFactor(d, sdk.OktaOtpFactor, policy.Settings.Factors.OktaOtp)
syncFactor(d, sdk.OktaPasswordFactor, policy.Settings.Factors.OktaPassword)
syncFactor(d, sdk.OktaPushFactor, policy.Settings.Factors.OktaPush)
syncFactor(d, sdk.OktaQuestionFactor, policy.Settings.Factors.OktaQuestion)
syncFactor(d, sdk.OktaSmsFactor, policy.Settings.Factors.OktaSms)
syncFactor(d, sdk.OktaEmailFactor, policy.Settings.Factors.OktaEmail)
syncFactor(d, sdk.RsaTokenFactor, policy.Settings.Factors.RsaToken)
syncFactor(d, sdk.SymantecVipFactor, policy.Settings.Factors.SymantecVip)
syncFactor(d, sdk.YubikeyTokenFactor, policy.Settings.Factors.YubikeyToken)
syncFactor(d, sdk.HotpFactor, policy.Settings.Factors.YubikeyToken)

syncSettings(d, policy.Settings)

return nil
}

Expand All @@ -81,25 +69,7 @@ func buildDefaultMFAPolicy(d *schema.ResourceData) sdk.Policy {
policy.Status = d.Get("status").(string)
policy.Description = d.Get("description").(string)
policy.Priority = int64(d.Get("priority").(int))
policy.Settings = &sdk.PolicySettings{
Factors: &sdk.PolicyFactorsSettings{
Duo: buildFactorProvider(d, sdk.DuoFactor),
FidoU2f: buildFactorProvider(d, sdk.FidoU2fFactor),
FidoWebauthn: buildFactorProvider(d, sdk.FidoWebauthnFactor),
GoogleOtp: buildFactorProvider(d, sdk.GoogleOtpFactor),
OktaCall: buildFactorProvider(d, sdk.OktaCallFactor),
OktaOtp: buildFactorProvider(d, sdk.OktaOtpFactor),
OktaPassword: buildFactorProvider(d, sdk.OktaPasswordFactor),
OktaPush: buildFactorProvider(d, sdk.OktaPushFactor),
OktaQuestion: buildFactorProvider(d, sdk.OktaQuestionFactor),
OktaSms: buildFactorProvider(d, sdk.OktaSmsFactor),
OktaEmail: buildFactorProvider(d, sdk.OktaEmailFactor),
RsaToken: buildFactorProvider(d, sdk.RsaTokenFactor),
SymantecVip: buildFactorProvider(d, sdk.SymantecVipFactor),
YubikeyToken: buildFactorProvider(d, sdk.YubikeyTokenFactor),
Hotp: buildFactorProvider(d, sdk.HotpFactor),
},
}
policy.Settings = buildSettings(d)
policy.Conditions = &okta.PolicyRuleConditions{
People: &okta.PolicyPeopleCondition{
Groups: &okta.GroupCondition{
Expand Down
Loading