Skip to content

Commit

Permalink
add support form multiple external idps for okta_policy_mfa
Browse files Browse the repository at this point in the history
Signed-off-by: Tien Nguyen <[email protected]>
  • Loading branch information
duytiennguyen-okta committed Jul 18, 2024
1 parent c7f45bf commit f7ffde2
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 20 deletions.
33 changes: 32 additions & 1 deletion docs/resources/policy_mfa.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,36 @@ resource "okta_policy_mfa" "oie_example" {
enroll = "REQUIRED"
}
groups_included = ["${data.okta_group.everyone.id}"]
}
// policy_mfa that support multiple external_idps
resource "okta_policy_mfa" "oie_example" {
name = "MFA Policy OIE"
status = "ACTIVE"
description = "Example MFA policy that uses Okta Identity Engine (OIE) with authenticators"
is_oie = true
okta_email = {
enroll = "REQUIRED"
}
google_otp = {
enroll = "REQUIRED"
}
external_idps = [
{
"enroll" : "OPTIONAL",
"id" : "id1",
},
{
"enroll" : "NOT_ALLOWED",
"id" : "id2",
}
]
groups_included = ["${data.okta_group.everyone.id}"]
}
```
Expand All @@ -58,7 +88,8 @@ resource "okta_policy_mfa" "oie_example" {

- `description` (String) Policy Description
- `duo` (Map of String)
- `external_idp` (Map of String)
- `external_idp` (Map of String, Deprecated)
- `external_idps` (Set of Map of String)
- `fido_u2f` (Map of String)
- `fido_webauthn` (Map of String)
- `google_otp` (Map of String)
Expand Down
3 changes: 2 additions & 1 deletion docs/resources/policy_mfa_default.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ resource "okta_policy_mfa_default" "oie_example" {
### Optional

- `duo` (Map of String)
- `external_idp` (Map of String)
- `external_idp` (Map of String, Deprecated)
- `external_idps` (Set of Map of String)
- `fido_u2f` (Map of String)
- `fido_webauthn` (Map of String)
- `google_otp` (Map of String)
Expand Down
30 changes: 30 additions & 0 deletions examples/resources/okta_policy_mfa/resource.tf
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,35 @@ resource "okta_policy_mfa" "oie_example" {
enroll = "REQUIRED"
}

groups_included = ["${data.okta_group.everyone.id}"]
}

// policy_mfa that support multiple external_idps
resource "okta_policy_mfa" "oie_example" {
name = "MFA Policy OIE"
status = "ACTIVE"
description = "Example MFA policy that uses Okta Identity Engine (OIE) with authenticators"
is_oie = true

okta_email = {
enroll = "REQUIRED"
}

google_otp = {
enroll = "REQUIRED"
}

external_idps = [
{
"enroll" : "OPTIONAL",
"id" : "id1",
},
{
"enroll" : "NOT_ALLOWED",
"id" : "id2",
}
]


groups_included = ["${data.okta_group.everyone.id}"]
}
126 changes: 108 additions & 18 deletions okta/resource_okta_policy_mfa.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure"
"github.com/okta/terraform-provider-okta/sdk"
)

Expand Down Expand Up @@ -113,6 +114,38 @@ func buildSettings(d *schema.ResourceData) *sdk.SdkPolicySettings {
}
authenticators = append(authenticators, authenticator)
}
_, ok := d.GetOk("external_idps")
if ok {
rawExternalIDPs := d.Get("external_idps").(*schema.Set).List()
for _, r := range rawExternalIDPs {
rawExternalIDP := r.(map[string]interface{})
enroll := rawExternalIDP["enroll"]
if enroll == nil {
continue
}
id := rawExternalIDP["id"]
if id == nil {
continue
}
authenticator := &sdk.PolicyAuthenticator{
Key: "external_idp",
ID: id.(string),
Enroll: &sdk.Enroll{
Self: enroll.(string),
},
}
constraints := rawExternalIDP["constraints"]
if constraints != nil {
c, ok := constraints.(string)
if ok {
slice := strings.Split(c, ",")
sort.Strings(slice)
authenticator.Constraints = &sdk.PolicyAuthenticatorConstraints{AaguidGroups: slice}
}
}
authenticators = append(authenticators, authenticator)
}
}

return &sdk.SdkPolicySettings{
Type: "AUTHENTICATORS",
Expand Down Expand Up @@ -201,40 +234,97 @@ func syncFactor(d *schema.ResourceData, k string, f *sdk.PolicyFactor) {
}

func syncAuthenticator(d *schema.ResourceData, k string, authenticators []*sdk.PolicyAuthenticator) {
externalIdps := make([]interface{}, 0)
for _, authenticator := range authenticators {
if authenticator.Key == k {
if authenticator.Constraints != nil {
slice := authenticator.Constraints.AaguidGroups
sort.Strings(slice)
_ = d.Set(k, map[string]interface{}{
"enroll": authenticator.Enroll.Self,
"constraints": strings.Join(slice, ","),
})
if k != "external_idp" {
if authenticator.Constraints != nil {
slice := authenticator.Constraints.AaguidGroups
sort.Strings(slice)
_ = d.Set(k, map[string]interface{}{
"enroll": authenticator.Enroll.Self,
"constraints": strings.Join(slice, ","),
})
} else {
_ = d.Set(k, map[string]interface{}{
"enroll": authenticator.Enroll.Self,
})
}
return
} else {
_ = d.Set(k, map[string]interface{}{
"enroll": authenticator.Enroll.Self,
})
if idp, ok := d.GetOk("external_idp"); ok && idp != nil {
if authenticator.Constraints != nil {
slice := authenticator.Constraints.AaguidGroups
sort.Strings(slice)
_ = d.Set(k, map[string]interface{}{
"enroll": authenticator.Enroll.Self,
"constraints": strings.Join(slice, ","),
})
} else {
_ = d.Set(k, map[string]interface{}{
"enroll": authenticator.Enroll.Self,
})
}
} else {
m := make(map[string]interface{})
m["enroll"] = authenticator.Enroll.Self
m["id"] = authenticator.ID
if authenticator.Constraints != nil {
slice := authenticator.Constraints.AaguidGroups
sort.Strings(slice)
m["constraints"] = strings.Join(slice, ",")
}
}
}
return
}
}
if len(externalIdps) > 0 {
_ = d.Set("external_idps", externalIdps)
}
}

// List of factor provider above, they all follow the same schema
func buildFactorSchemaProviders() map[string]*schema.Schema {
res := make(map[string]*schema.Schema)
// 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,
if key == "external_idp" {
res[key] = &schema.Schema{
Optional: true,
Type: schema.TypeMap,
Elem: &schema.Schema{
Type: schema.TypeString,
},
Deprecated: "Since okta now support multiple external_idps, this will be deprecated. Please use `external_idps` instead",
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
return strings.HasSuffix(k, ".%") || new == ""
},
ConflictsWith: []string{"external_idps"},
}
} else {
res[key] = &schema.Schema{
Optional: true,
Type: schema.TypeMap,
Elem: &schema.Schema{
Type: schema.TypeString,
},
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
return strings.HasSuffix(k, ".%") || new == ""
},
}
}
}
res["external_idps"] = &schema.Schema{
Optional: true,
Type: schema.TypeSet,
Elem: &schema.Schema{
Type: schema.TypeMap,
Elem: &schema.Schema{
Type: schema.TypeString,
},
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
return strings.HasSuffix(k, ".%") || new == ""
},
}
},
DiffSuppressFunc: structure.SuppressJsonDiff,
ConflictsWith: []string{"external_idp"},
}
return res
}
1 change: 1 addition & 0 deletions sdk/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ type PolicyFactor struct {

type PolicyAuthenticator struct {
Key string `json:"key,omitempty"`
ID string `json:"id,omitempty"`
Enroll *Enroll `json:"enroll,omitempty"`
Constraints *PolicyAuthenticatorConstraints `json:"constraints,omitempty"`
}
Expand Down

0 comments on commit f7ffde2

Please sign in to comment.