Skip to content

Commit

Permalink
Merge pull request #1908 from okta/isaacokta_1864
Browse files Browse the repository at this point in the history
Isaacokta 1864
  • Loading branch information
duytiennguyen-okta authored Feb 23, 2024
2 parents b7055d1 + a1f11b6 commit 815d4f9
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 10 deletions.
42 changes: 33 additions & 9 deletions okta/resource_okta_authenticator.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@ func resourceAuthenticator() *schema.Resource {
Type: schema.TypeString,
Required: true,
Description: "Display name of the Authenticator",
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
return true
},
},
"settings": {
Type: schema.TypeString,
Expand Down Expand Up @@ -172,6 +169,17 @@ func resourceAuthenticatorCreate(ctx context.Context, d *schema.ResourceData, m
if err != nil {
return diag.FromErr(err)
}
if d.Get("key").(string) == "custom_otp" {
var otp *sdk.OTP
otp, err = buildOTP(d)
if err != nil {
return diag.FromErr(err)
}
_, err = getOktaClientFromMetadata(m).Authenticator.SetSettingsOTP(ctx, *otp, authenticator.Id)
if err != nil {
return diag.FromErr(err)
}
}
}

d.SetId(authenticator.Id)
Expand Down Expand Up @@ -289,13 +297,15 @@ func buildAuthenticator(d *schema.ResourceData) (*sdk.Authenticator, error) {
},
}
} else {
if s, ok := d.GetOk("settings"); ok {
var settings sdk.AuthenticatorSettings
err := json.Unmarshal([]byte(s.(string)), &settings)
if err != nil {
return nil, err
if d.Get("key").(string) != "custom_otp" {
if s, ok := d.GetOk("settings"); ok {
var settings sdk.AuthenticatorSettings
err := json.Unmarshal([]byte(s.(string)), &settings)
if err != nil {
return nil, err
}
authenticator.Settings = &settings
}
authenticator.Settings = &settings
}
}

Expand All @@ -311,6 +321,20 @@ func buildAuthenticator(d *schema.ResourceData) (*sdk.Authenticator, error) {
return &authenticator, nil
}

func buildOTP(d *schema.ResourceData) (*sdk.OTP, error) {
otp := sdk.OTP{}
if s, ok := d.GetOk("settings"); ok {
var settings sdk.AuthenticatorSettingsOTP
err := json.Unmarshal([]byte(s.(string)), &settings)
if err != nil {
return nil, err
}
otp.Settings = &settings
}

return &otp, nil
}

func validateAuthenticator(d *schema.ResourceData) error {
typ := d.Get("type").(string)
if typ == "security_key" {
Expand Down
38 changes: 38 additions & 0 deletions okta/resource_okta_authenticator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,44 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccResourceOktaAuthenticatorOTP(t *testing.T) {
config := `
resource "okta_authenticator" "otp" {
name = "Custom OTP"
key = "custom_otp"
status = "ACTIVE"
settings = jsonencode({
"protocol" : "TOTP",
"acceptableAdjacentIntervals" : 3,
"timeIntervalInSeconds" : 30,
"encoding" : "base32",
"algorithm" : "HMacSHA256",
"passCodeLength" : 6
})
}
`
resourceName := fmt.Sprintf("%s.otp", authenticator)

oktaResourceTest(t, resource.TestCase{
PreCheck: testAccPreCheck(t),
ErrorCheck: testAccErrorChecks(t),
ProviderFactories: testAccProvidersFactories,
CheckDestroy: nil,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "status", statusActive),
resource.TestCheckResourceAttr(resourceName, "type", "security_key"),
resource.TestCheckResourceAttr(resourceName, "key", "custom_otp"),
resource.TestCheckResourceAttr(resourceName, "name", "Custom OTP"),
testAttributeJSON(resourceName, "settings", `{"acceptableAdjacentIntervals":3,"algorithm":"HMacSHA256","encoding":"base32","passCodeLength":6,"protocol":"TOTP","timeIntervalInSeconds":30}`),
),
},
},
})
}

func TestAccResourceOktaAuthenticator_crud(t *testing.T) {
resourceName := fmt.Sprintf("%s.test", authenticator)
mgr := newFixtureManager("resources", authenticator, t.Name())
Expand Down
24 changes: 24 additions & 0 deletions sdk/v2_authenticator.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ type Authenticator struct {
Type string `json:"type,omitempty"`
}

type OTP struct {
Settings *AuthenticatorSettingsOTP `json:"settings"`
}

func (m *AuthenticatorResource) GetAuthenticator(ctx context.Context, authenticatorId string) (*Authenticator, *Response, error) {
url := fmt.Sprintf("/api/v1/authenticators/%v", authenticatorId)

Expand Down Expand Up @@ -110,6 +114,26 @@ func (m *AuthenticatorResource) CreateAuthenticator(ctx context.Context, body Au
return authenticator, resp, nil
}

func (m *AuthenticatorResource) SetSettingsOTP(ctx context.Context, body OTP, authenticatorId string)(*Response, error){
url := fmt.Sprintf("/api/v1/authenticators/%v/methods/otp", authenticatorId)

rq := m.client.CloneRequestExecutor()

req, err := rq.WithAccept("application/json").WithContentType("application/json").NewRequest("PUT", url, body)
if err != nil {
return nil, err
}

var otp *OTP

resp, err := rq.Do(ctx, req, &otp)
if err != nil {
return nil, err
}

return resp, nil
}

func (m *AuthenticatorResource) ActivateAuthenticator(ctx context.Context, authenticatorId string) (*Authenticator, *Response, error) {
url := fmt.Sprintf("/api/v1/authenticators/%v/lifecycle/activate", authenticatorId)

Expand Down
36 changes: 36 additions & 0 deletions sdk/v2_authenticatorSettingsOTP.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// DO NOT EDIT LOCAL SDK - USE v3 okta-sdk-golang FOR API CALLS THAT DO NOT EXIST IN LOCAL SDK
package sdk

import "encoding/json"

type AuthenticatorSettingsOTP struct {
AcceptableAdjacentIntervals int `json:"acceptableAdjacentIntervals"`
Algorithm string `json:"algorithm"`
Encoding string `json:"encoding"`
PassCodeLength int `json:"passCodeLength"`
Protocol string `json:"protocol"`
TimeIntervalInSeconds int `json:"timeIntervalInSeconds"`
}

func (a *AuthenticatorSettingsOTP) MarshalJSON() ([]byte, error) {
type Alias AuthenticatorSettingsOTP
type local struct {
*Alias
}
result := local{Alias: (*Alias)(a)}
return json.Marshal(&result)
}

func (a *AuthenticatorSettingsOTP) UnmarshalJSON(data []byte) error {
type Alias AuthenticatorSettingsOTP

result := &struct {
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(data, &result); err != nil {
return err
}
return nil
}
18 changes: 17 additions & 1 deletion website/docs/r/authenticator.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,27 @@ resource "okta_authenticator" "test" {
}
```

```hcl
resource "okta_authenticator" "test" {
name = "Custom OTP"
key = "custom_otp"
status = "ACTIVE"
settings = jsonencode({
"protocol" : "TOTP",
"acceptableAdjacentIntervals" : 3,
"timeIntervalInSeconds" : 30,
"encoding" : "base32",
"algorithm" : "HMacSHA256",
"passCodeLength" : 6
})
}
```

## Argument Reference

The following arguments are supported:

- `key` (Required) A human-readable string that identifies the authenticator. Some authenticators are available by feature flag on the organization. Possible values inclue: `duo`, `external_idp`, `google_otp`, `okta_email`, `okta_password`, `okta_verify`, `onprem_mfa`, `phone_number`, `rsa_token`, `security_question`, `webauthn`
- `key` (Required) A human-readable string that identifies the authenticator. Some authenticators are available by feature flag on the organization. Possible values inclue: `duo`, `external_idp`, `google_otp`, `okta_email`, `okta_password`, `okta_verify`, `onprem_mfa`, `phone_number`, `rsa_token`, `security_question`, `webauthn`, `custom_otp`

- `name` - (Required) Name of the authenticator.

Expand Down

0 comments on commit 815d4f9

Please sign in to comment.