Skip to content

Commit

Permalink
Merge pull request #1572 from okta/okta_policy_rule_profile_enrollment
Browse files Browse the repository at this point in the history
Refine Okta policy rule profile enrollment resource
  • Loading branch information
MikeMondragon-okta authored Jun 5, 2023
2 parents aed8e70 + e7603bc commit 0583cdf
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 827 deletions.
7 changes: 4 additions & 3 deletions okta/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,10 @@ func TestProviderValidate(t *testing.T) {
}

// NOTE: Our VCR set up is inspired by terraform-provider-google
var providerConfigsLock = sync.RWMutex{}
var providerConfigs map[string]*Config
var (
providerConfigsLock = sync.RWMutex{}
providerConfigs map[string]*Config
)

func init() {
providerConfigs = make(map[string]*Config)
Expand Down Expand Up @@ -294,7 +296,6 @@ func oktaResourceTest(t *testing.T, c resource.TestCase) {
return
}
if mgr.IsPlaying() {

if !mgr.HasCassettesToPlay() {
t.Skipf("%q test is missing VCR cassette(s) at %q, skipping test. See .github/CONTRIBUTING.md#acceptance-tests-with-vcr for more information about playing/recording cassettes.", t.Name(), mgr.CassettesPath)
return
Expand Down
1 change: 0 additions & 1 deletion okta/resource_okta_app_auto_login_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ resource "okta_app_auto_login" "test" {
CheckDestroy: createCheckResourceDestroy(appAutoLogin, createDoesAppExist(sdk.NewAutoLoginApplication())),
Steps: []resource.TestStep{
{

Config: mgr.ConfigReplace(config),
Check: resource.ComposeTestCheckFunc(
ensureResourceExists(resourceName, createDoesAppExist(sdk.NewAutoLoginApplication())),
Expand Down
1 change: 0 additions & 1 deletion okta/resource_okta_app_user_custom_schema_property_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,6 @@ resource "okta_app_user_schema_property" "test" {
CheckDestroy: createCheckResourceDestroy(appUserSchemaProperty, testAppUserSchemaExists),
Steps: []resource.TestStep{
{

Config: mgr.ConfigReplace(config),
Check: resource.ComposeTestCheckFunc(
testAppUserSchemasExists(resourceName),
Expand Down
129 changes: 100 additions & 29 deletions okta/resource_okta_policy_rule_profile_enrollment.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ func resourcePolicyProfileEnrollmentRule() *schema.Resource {
}
}

// resourcePolicyProfileEnrollmentRuleCreate
// True create does not exist for the rule of a profile enrollment policy.
// "This type of policy can only have one policy rule, so it's not possible to
// create other rules. Instead, consider editing the default one to meet your
// needs."
// https://developer.okta.com/docs/reference/api/policy/#profile-enrollment-policy
func resourcePolicyProfileEnrollmentRuleCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
if isClassicOrg(m) {
return resourceOIEOnlyFeatureError(policyRuleProfileEnrollment)
Expand All @@ -113,9 +119,13 @@ func resourcePolicyProfileEnrollmentRuleCreate(ctx context.Context, d *schema.Re
if len(rules) == 0 {
return diag.Errorf("this policy should contain one default Catch-All rule, but it doesn't")
}
rule, _, err := getAPISupplementFromMetadata(m).UpdatePolicyRule(ctx, d.Get("policy_id").(string), rules[0].Id, buildPolicyRuleProfileEnrollment(d, rules[0].Id))
updateRule, err := buildPolicyRuleProfileEnrollment(ctx, m, d, rules[0].Id)
if err != nil {
return diag.Errorf("failed to create profile enrollment policy rule: %v", err)
return diag.Errorf("failed to prepare update of existing profile enrollment policy rule: %v", err)
}
rule, _, err := getAPISupplementFromMetadata(m).UpdatePolicyRule(ctx, d.Get("policy_id").(string), rules[0].Id, *updateRule)
if err != nil {
return diag.Errorf("failed to update existing profile enrollment policy rule: %v", err)
}
d.SetId(rule.Id)
return resourcePolicyProfileEnrollmentRuleRead(ctx, d, m)
Expand Down Expand Up @@ -163,7 +173,11 @@ func resourcePolicyProfileEnrollmentRuleUpdate(ctx context.Context, d *schema.Re
return resourceOIEOnlyFeatureError(policyRuleProfileEnrollment)
}

_, _, err := getAPISupplementFromMetadata(m).UpdatePolicyRule(ctx, d.Get("policy_id").(string), d.Id(), buildPolicyRuleProfileEnrollment(d, d.Id()))
updateRule, err := buildPolicyRuleProfileEnrollment(ctx, m, d, d.Id())
if err != nil {
return diag.Errorf("failed to prepare update profile enrollment policy rule: %v", err)
}
_, _, err = getAPISupplementFromMetadata(m).UpdatePolicyRule(ctx, d.Get("policy_id").(string), d.Id(), *updateRule)
if err != nil {
return diag.Errorf("failed to update profile enrollment policy rule: %v", err)
}
Expand All @@ -179,36 +193,92 @@ func resourcePolicyProfileEnrollmentRuleDelete(ctx context.Context, d *schema.Re
return nil
}

// build profile enrollment policy rule from schema data
func buildPolicyRuleProfileEnrollment(d *schema.ResourceData, id string) sdk.SdkPolicyRule {
rule := sdk.ProfileEnrollmentPolicyRule()
rule.Id = id
rule.Name = "Catch-all Rule" // read-only
rule.Priority = 99 // read-only
rule.System = boolPtr(true) // read-only
rule.Status = statusActive
rule.Actions = sdk.SdkPolicyRuleActions{
ProfileEnrollment: &sdk.ProfileEnrollmentPolicyRuleAction{
Access: d.Get("access").(string),
ActivationRequirements: &sdk.ProfileEnrollmentPolicyRuleActivationRequirement{
EmailVerification: boolPtr(d.Get("email_verification").(bool)),
},
UnknownUserAction: d.Get("unknown_user_action").(string),
UiSchemaId: d.Get("ui_schema_id").(string),
},
// buildPolicyRuleProfileEnrollment build profile enrollment policy rule from
// copy of existing rule
func buildPolicyRuleProfileEnrollment(ctx context.Context, m interface{}, d *schema.ResourceData, id string) (*sdk.SdkPolicyRule, error) {
rule, resp, err := getAPISupplementFromMetadata(m).GetPolicyRule(ctx, d.Get("policy_id").(string), id)
if err = suppressErrorOn404(resp, err); err != nil {
return nil, err
}

// Given that the Okta API is sensitive to attributes that are already set
// on the one rule always present on a profile enrollment policy:
// 1. get a current copy of the rule
// 2. use the copy to prepopulate vaules for the update rule
// 3. apply values from the resource config to the update rule

// First, API requires these attributes always be set, prepopulate with
// existing values
updateRule := sdk.ProfileEnrollmentPolicyRule()
updateRule.Id = rule.Id
updateRule.Name = rule.Name
updateRule.Priority = rule.Priority
updateRule.System = rule.System
updateRule.Status = rule.Status

// Additionally, only prepopulate the attributes that are already set on the
// current rule

ruleAction := sdk.NewProfileEnrollmentPolicyRuleAction()

// access
if rule.Actions.ProfileEnrollment.Access != "" {
ruleAction.Access = rule.Actions.ProfileEnrollment.Access
}
if access, ok := d.GetOk("access"); ok {
ruleAction.Access = access.(string)
}

activationRequirements := sdk.NewProfileEnrollmentPolicyRuleActivationRequirement()
// email_verification is set on the config use it's value, else fallback to the rule copy
if ev, _ := d.GetOk("email_verification"); ev != nil {
activationRequirements.EmailVerification = boolPtr(ev.(bool))
} else {
activationRequirements.EmailVerification = ruleAction.ActivationRequirements.EmailVerification
}

// unknown_user_action
ruleAction.ActivationRequirements = activationRequirements
if rule.Actions.ProfileEnrollment.UnknownUserAction != "" {
ruleAction.UnknownUserAction = rule.Actions.ProfileEnrollment.UnknownUserAction
}
if uua, ok := d.GetOk("unknown_user_action"); ok {
ruleAction.UnknownUserAction = uua.(string)
}

// ui_schema_id
if rule.Actions.ProfileEnrollment.UiSchemaId != "" {
ruleAction.UiSchemaId = rule.Actions.ProfileEnrollment.UiSchemaId
}
if usi, ok := d.GetOk("ui_schema_id"); ok {
ruleAction.UiSchemaId = usi.(string)
}

updateRule.Actions = sdk.SdkPolicyRuleActions{
ProfileEnrollment: ruleAction,
}

// inline_hook_id
if len(rule.Actions.ProfileEnrollment.PreRegistrationInlineHooks) != 0 {
updateRule.Actions.ProfileEnrollment.PreRegistrationInlineHooks = rule.Actions.ProfileEnrollment.PreRegistrationInlineHooks
}
hook, ok := d.GetOk("inline_hook_id")
if ok {
rule.Actions.ProfileEnrollment.PreRegistrationInlineHooks = []*sdk.PreRegistrationInlineHook{{InlineHookId: hook.(string)}}
if hook, ok := d.GetOk("inline_hook_id"); ok {
updateRule.Actions.ProfileEnrollment.PreRegistrationInlineHooks = []*sdk.PreRegistrationInlineHook{{InlineHookId: hook.(string)}}
}

// target_group_id
if len(rule.Actions.ProfileEnrollment.TargetGroupIds) != 0 {
updateRule.Actions.ProfileEnrollment.TargetGroupIds = rule.Actions.ProfileEnrollment.TargetGroupIds
}
targetGroup, ok := d.GetOk("target_group_id")
if ok {
rule.Actions.ProfileEnrollment.TargetGroupIds = []string{targetGroup.(string)}
if targetGroup, ok := d.GetOk("target_group_id"); ok {
updateRule.Actions.ProfileEnrollment.TargetGroupIds = []string{targetGroup.(string)}
}

pa, ok := d.GetOk("profile_attributes")
if !ok {
return rule
return &updateRule, nil
}

attributes := make([]*sdk.ProfileEnrollmentPolicyRuleProfileAttribute, len(pa.([]interface{})))
for i := range pa.([]interface{}) {
attributes[i] = &sdk.ProfileEnrollmentPolicyRuleProfileAttribute{
Expand All @@ -217,6 +287,7 @@ func buildPolicyRuleProfileEnrollment(d *schema.ResourceData, id string) sdk.Sdk
Required: boolPtr(d.Get(fmt.Sprintf("profile_attributes.%d.required", i)).(bool)),
}
}
rule.Actions.ProfileEnrollment.ProfileAttributes = attributes
return rule
updateRule.Actions.ProfileEnrollment.ProfileAttributes = attributes

return &updateRule, nil
}
2 changes: 1 addition & 1 deletion okta/resource_okta_policy_rule_profile_enrollment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ resource "okta_policy_rule_profile_enrollment" "test" {
resource.TestCheckResourceAttr(resourceName, "profile_attributes.0.name", "email"),
resource.TestCheckResourceAttr(resourceName, "profile_attributes.1.name", "firstName"),
resource.TestCheckResourceAttr(resourceName, "profile_attributes.2.name", "lastName"),
resource.TestCheckResourceAttrSet(resourceName, "ui_schema_id"),
resource.TestCheckResourceAttr(resourceName, "ui_schema_id", "uis44fio9ifOCwJAO1d7"),
),
},
},
Expand Down
1 change: 0 additions & 1 deletion okta/resource_security_notification_emails_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,4 @@ func checkOktaSecurityNotificationEmailsDestroy(s *terraform.State) error {
}
}
return nil

}
Loading

0 comments on commit 0583cdf

Please sign in to comment.