Skip to content

Commit

Permalink
Merge remote-tracking branch 'tgoodsell-tempus/okta-app-role-assignme…
Browse files Browse the repository at this point in the history
…nt' into tgoodsell-tempus_1734
  • Loading branch information
duytiennguyen-okta committed Oct 5, 2023
2 parents e3998e2 + 4af3633 commit ba95fa4
Show file tree
Hide file tree
Showing 9 changed files with 578 additions and 1 deletion.
12 changes: 12 additions & 0 deletions examples/okta_app_oauth_role_assignment/basic.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
resource "okta_app_oauth" "test" {
label = "testAcc_replace_with_uuid"
type = "service"
response_types = ["token"]
grant_types = ["client_credentials"]
jwks_uri = "https://example.com"
}

resource "okta_app_oauth_role_assignment" "test" {
client_id = okta_app_oauth.test.client_id
type = "HELP_DESK_ADMIN"
}
12 changes: 12 additions & 0 deletions examples/okta_app_oauth_role_assignment/basic_updated.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
resource "okta_app_oauth" "test" {
label = "testAcc_replace_with_uuid"
type = "service"
response_types = ["token"]
grant_types = ["client_credentials"]
jwks_uri = "https://example.com"
}

resource "okta_app_oauth_role_assignment" "test" {
client_id = okta_app_oauth.test.client_id
type = "GROUP_MEMBERSHIP_ADMIN"
}
37 changes: 37 additions & 0 deletions examples/okta_app_oauth_role_assignment/custom.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
resource "okta_app_oauth" "test" {
label = "testAcc_replace_with_uuid"
type = "service"
response_types = ["token"]
grant_types = ["client_credentials"]
jwks_uri = "https://example.com"
}

variable "hostname" {
type = string
}

locals {
org_url = "https://${var.hostname}"
}

resource "okta_admin_role_custom" "test" {
label = "testAcc_replace_with_uuid"
description = "testing, testing"
permissions = ["okta.apps.assignment.manage", "okta.users.manage", "okta.apps.manage"]
}

resource "okta_resource_set" "test" {
label = "testAcc_replace_with_uuid"
description = "testing, testing"
resources = [
format("%s/api/v1/users", local.org_url),
format("%s/api/v1/apps", local.org_url)
]
}

resource "okta_app_oauth_role_assignment" "test" {
client_id = okta_app_oauth.test.client_id
type = "CUSTOM"
role = okta_admin_role_custom.test.id
resource_set = okta_resource_set.test.id
}
37 changes: 37 additions & 0 deletions examples/okta_app_oauth_role_assignment/custom_updated.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
resource "okta_app_oauth" "test" {
label = "testAcc_replace_with_uuid"
type = "service"
response_types = ["token"]
grant_types = ["client_credentials"]
jwks_uri = "https://example.com"
}

variable "hostname" {
type = string
}

locals {
org_url = "https://${var.hostname}"
}

resource "okta_admin_role_custom" "test" {
label = "testAcc_replace_with_uuid"
description = "testing, testing"
permissions = ["okta.apps.assignment.manage", "okta.users.read"]
}

resource "okta_resource_set" "test" {
label = "testAcc_replace_with_uuid"
description = "testing, testing"
resources = [
format("%s/api/v1/users", local.org_url),
format("%s/api/v1/apps", local.org_url),
]
}

resource "okta_app_oauth_role_assignment" "test" {
client_id = okta_app_oauth.test.client_id
type = "CUSTOM"
role = okta_admin_role_custom.test.id
resource_set = okta_resource_set.test.id
}
3 changes: 2 additions & 1 deletion okta/framework_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,10 +249,11 @@ func (p *FrameworkProvider) DataSources(_ context.Context) []func() datasource.D
func (p *FrameworkProvider) Resources(_ context.Context) []func() resource.Resource {
return []func() resource.Resource{
NewAppAccessPolicyAssignmentResource,
NewAppOAuthRoleAssignmentResource,
NewBrandResource,
NewPolicyDeviceAssuranceAndroidResource,
NewPolicyDeviceAssuranceIOSResource,
NewPolicyDeviceAssuranceChromeOSResource,
NewPolicyDeviceAssuranceIOSResource,
NewPolicyDeviceAssuranceMacOSResource,
NewPolicyDeviceAssuranceWindowsResource,
}
Expand Down
217 changes: 217 additions & 0 deletions okta/resource_okta_app_oauth_role_assignment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
package okta

import (
"context"
"fmt"
"strings"

"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/okta/terraform-provider-okta/sdk"
)

var _ resource.ResourceWithValidateConfig = &appOAuthRoleAssignmentResource{}
var _ resource.ResourceWithImportState = &appOAuthRoleAssignmentResource{}

func NewAppOAuthRoleAssignmentResource() resource.Resource {
return &appOAuthRoleAssignmentResource{}
}

type appOAuthRoleAssignmentResource struct {
*Config
}

type OAuthRoleAssignmentResourceModel struct {
ID types.String `tfsdk:"id"`
ClientID types.String `tfsdk:"client_id"`
Type types.String `tfsdk:"type"`
ResourceSet types.String `tfsdk:"resource_set"`
Role types.String `tfsdk:"role"`
Status types.String `tfsdk:"status"`
Label types.String `tfsdk:"label"`
}

func (r *appOAuthRoleAssignmentResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_app_oauth_role_assignment"
}

func (r *appOAuthRoleAssignmentResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
if req.ProviderData == nil {
return
}

config, ok := req.ProviderData.(*Config)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Resource Configure Type",
fmt.Sprintf("Expected *Config, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)
return
}
r.Config = config
}

func (r *appOAuthRoleAssignmentResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "Manages assignment of an admin role to an OAuth application",
MarkdownDescription: "Manages assignment of an admin role to an OAuth application",
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Description: "Role Assignment ID",
MarkdownDescription: "Role Assignment ID",
Computed: true,
},
"client_id": schema.StringAttribute{
Description: "Client ID for the role to be assigned to",
MarkdownDescription: "Client ID for the role to be assigned to",
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"type": schema.StringAttribute{
Description: "Role type to assign. This can be one of the standard Okta roles, such as `HELP_DESK_ADMIN`, or `CUSTOM`. Using custom requires the `resource_set` and `role` attributes to be set.",
MarkdownDescription: "Role type to assign. This can be one of the standard Okta roles, such as `HELP_DESK_ADMIN`, or `CUSTOM`. Using custom requires the `resource_set` and `role` attributes to be set.",
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"resource_set": schema.StringAttribute{
Description: "Resource set for the custom role to assign, must be the ID of the created resource set.",
MarkdownDescription: "Resource set for the custom role to assign, must be the ID of the created resource set.",
Optional: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"role": schema.StringAttribute{
Description: "Custom Role ID",
MarkdownDescription: "Custom Role ID",
Optional: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"status": schema.StringAttribute{
Description: "Status of the role assignment",
MarkdownDescription: "Status of the role assignment",
Computed: true,
},
"label": schema.StringAttribute{
Description: "Label of the role assignment",
MarkdownDescription: "Label of the role assignment",
Computed: true,
},
},
}
}

func (r *appOAuthRoleAssignmentResource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) {
var data *OAuthRoleAssignmentResourceModel

resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}
if data.Type.ValueString() == "CUSTOM" && (data.ResourceSet.IsNull() || data.Role.IsNull()) {
resp.Diagnostics.AddAttributeError(
path.Root("type"),
"Missing attribute configuration",
"When type is set to 'CUSTOM', the resource_set and role attributes must be set.",
)
}
}

func (r *appOAuthRoleAssignmentResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var data *OAuthRoleAssignmentResourceModel

resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

roleAssignmentRequest := &sdk.ClientRoleAssignment{
Type: data.Type.ValueString(),
ResourceSet: data.ResourceSet.ValueStringPointer(),
Role: data.Role.ValueStringPointer(),
}

role, _, err := r.Config.oktaSDKsupplementClient.AssignClientRole(ctx, data.ClientID.ValueString(), roleAssignmentRequest)
if err != nil {
resp.Diagnostics.AddError("Unable to assign role to client", err.Error())
return
}

data.ID = types.StringPointerValue(role.Id)
data.Status = types.StringPointerValue(role.Status)
data.Label = types.StringPointerValue(role.Label)
data.Type = types.StringPointerValue(role.Type)
data.ResourceSet = types.StringPointerValue(role.ResourceSet)
data.Role = types.StringPointerValue(role.Role)

resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *appOAuthRoleAssignmentResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var data *OAuthRoleAssignmentResourceModel

resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

role, _, err := r.Config.oktaSDKsupplementClient.GetClientRole(ctx, data.ClientID.ValueString(), data.ID.ValueString())
if err != nil {
resp.Diagnostics.AddError("Unable to read role assignment", err.Error())
return
}

data.ID = types.StringPointerValue(role.Id)
data.Status = types.StringPointerValue(role.Status)
data.Label = types.StringPointerValue(role.Label)
data.Type = types.StringPointerValue(role.Type)
data.ResourceSet = types.StringPointerValue(role.ResourceSet)
data.Role = types.StringPointerValue(role.Role)

resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *appOAuthRoleAssignmentResource) Update(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) {
resp.Diagnostics.AddError(
"Update not supported",
"OAuth Role Assignments cannot be updated. If you get to this contact the provider maintainers as this should not be hit.",
)
}

func (r *appOAuthRoleAssignmentResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var data *OAuthRoleAssignmentResourceModel

resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

_, err := r.Config.oktaSDKsupplementClient.UnassignClientRole(ctx, data.ClientID.ValueString(), data.ID.ValueString())
if err != nil {
resp.Diagnostics.AddError("Unable to delete role assignment", err.Error())
return
}
}

func (r *appOAuthRoleAssignmentResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
idParts := strings.Split(req.ID, "/")

if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" {
resp.Diagnostics.AddError("Unexpected Import Identifier", "Expected import identifier with format <client_id>/<role_id>")
return
}
resp.Diagnostics.Append(resp.State.Set(ctx, &OAuthRoleAssignmentResourceModel{
ClientID: types.StringValue(idParts[0]),
ID: types.StringValue(idParts[1]),
})...)
}
Loading

0 comments on commit ba95fa4

Please sign in to comment.