diff --git a/go.mod b/go.mod index 40dfe12a6..556b60167 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,10 @@ require ( github.com/hashicorp/go-hclog v1.5.0 github.com/hashicorp/go-retryablehttp v0.7.4 github.com/hashicorp/terraform-plugin-docs v0.16.0 + github.com/hashicorp/terraform-plugin-framework v1.3.2 + github.com/hashicorp/terraform-plugin-framework-validators v0.10.0 + github.com/hashicorp/terraform-plugin-go v0.18.0 + github.com/hashicorp/terraform-plugin-mux v0.11.2 github.com/hashicorp/terraform-plugin-sdk/v2 v2.27.0 github.com/kelseyhightower/envconfig v1.4.0 github.com/okta/okta-sdk-golang/v3 v3.0.11 @@ -21,27 +25,21 @@ require ( gopkg.in/yaml.v3 v3.0.1 ) -require ( - github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect - github.com/cloudflare/circl v1.3.3 // indirect - github.com/go-jose/go-jose/v3 v3.0.0 // indirect - github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect - github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect - golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect -) - require ( github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.1.1 // indirect github.com/Masterminds/sprig/v3 v3.2.2 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect github.com/agext/levenshtein v1.2.3 // indirect github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect github.com/armon/go-radix v1.0.0 // indirect github.com/beevik/etree v1.1.0 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect + github.com/cloudflare/circl v1.3.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dnaeon/go-vcr v1.2.0 github.com/fatih/color v1.13.0 // indirect + github.com/go-jose/go-jose/v3 v3.0.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/uuid v1.3.0 // indirect @@ -56,7 +54,6 @@ require ( github.com/hashicorp/logutils v1.0.0 // indirect github.com/hashicorp/terraform-exec v0.18.1 // indirect github.com/hashicorp/terraform-json v0.17.1 // indirect - github.com/hashicorp/terraform-plugin-go v0.16.0 // indirect github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect github.com/hashicorp/terraform-registry-address v0.2.1 // indirect github.com/hashicorp/terraform-svchost v0.1.1 // indirect @@ -81,8 +78,11 @@ require ( github.com/shopspring/decimal v1.3.1 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect + github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/zclconf/go-cty v1.13.2 // indirect golang.org/x/crypto v0.10.0 // indirect + golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect golang.org/x/mod v0.11.0 // indirect golang.org/x/net v0.11.0 // indirect golang.org/x/oauth2 v0.7.0 // indirect @@ -90,7 +90,7 @@ require ( golang.org/x/text v0.11.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect - google.golang.org/grpc v1.56.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/grpc v1.56.1 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v2 v2.3.0 // indirect ) diff --git a/go.sum b/go.sum index c6c9f0bce..caaa4c54a 100644 --- a/go.sum +++ b/go.sum @@ -198,10 +198,16 @@ github.com/hashicorp/terraform-json v0.17.1 h1:eMfvh/uWggKmY7Pmb3T85u86E2EQg6EQH github.com/hashicorp/terraform-json v0.17.1/go.mod h1:Huy6zt6euxaY9knPAFKjUITn8QxUFIe9VuSzb4zn/0o= github.com/hashicorp/terraform-plugin-docs v0.16.0 h1:UmxFr3AScl6Wged84jndJIfFccGyBZn52KtMNsS12dI= github.com/hashicorp/terraform-plugin-docs v0.16.0/go.mod h1:M3ZrlKBJAbPMtNOPwHicGi1c+hZUh7/g0ifT/z7TVfA= -github.com/hashicorp/terraform-plugin-go v0.16.0 h1:DSOQ0rz5FUiVO4NUzMs8ln9gsPgHMTsfns7Nk+6gPuE= -github.com/hashicorp/terraform-plugin-go v0.16.0/go.mod h1:4sn8bFuDbt+2+Yztt35IbOrvZc0zyEi87gJzsTgCES8= +github.com/hashicorp/terraform-plugin-framework v1.3.2 h1:aQ6GSD0CTnvoALEWvKAkcH/d8jqSE0Qq56NYEhCexUs= +github.com/hashicorp/terraform-plugin-framework v1.3.2/go.mod h1:oimsRAPJOYkZ4kY6xIGfR0PHjpHLDLaknzuptl6AvnY= +github.com/hashicorp/terraform-plugin-framework-validators v0.10.0 h1:4L0tmy/8esP6OcvocVymw52lY0HyQ5OxB7VNl7k4bS0= +github.com/hashicorp/terraform-plugin-framework-validators v0.10.0/go.mod h1:qdQJCdimB9JeX2YwOpItEu+IrfoJjWQ5PhLpAOMDQAE= +github.com/hashicorp/terraform-plugin-go v0.18.0 h1:IwTkOS9cOW1ehLd/rG0y+u/TGLK9y6fGoBjXVUquzpE= +github.com/hashicorp/terraform-plugin-go v0.18.0/go.mod h1:l7VK+2u5Kf2y+A+742GX0ouLut3gttudmvMgN0PA74Y= github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0= github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow= +github.com/hashicorp/terraform-plugin-mux v0.11.2 h1:XMkAmWQN+6F+l4jwNeqdPom/8Vly6ZNDxHoKjiRHx5c= +github.com/hashicorp/terraform-plugin-mux v0.11.2/go.mod h1:qjoF/pI49rILSNQzKIuDtU+ZX9mpQD0B8YNE1GceLPc= github.com/hashicorp/terraform-plugin-sdk/v2 v2.27.0 h1:I8efBnjuDrgPjNF1MEypHy48VgcTIUY4X6rOFunrR3Y= github.com/hashicorp/terraform-plugin-sdk/v2 v2.27.0/go.mod h1:cUEP4ly/nxlHy5HzD6YRrHydtlheGvGRJDhiWqqVik4= github.com/hashicorp/terraform-registry-address v0.2.1 h1:QuTf6oJ1+WSflJw6WYOHhLgwUiQ0FrROpHPYFtwTYWM= @@ -586,8 +592,8 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.56.0 h1:+y7Bs8rtMd07LeXmL3NxcTLn7mUkbKZqEpPhMNkwJEE= -google.golang.org/grpc v1.56.0/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.56.1 h1:z0dNfjIl0VpaZ9iSVjA6daGatAYwPGstTjt5vkRMFkQ= +google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -600,8 +606,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/main.go b/main.go index 3cf02bce6..56299d6dc 100644 --- a/main.go +++ b/main.go @@ -2,8 +2,13 @@ package main import ( - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/plugin" + "context" + "log" + + "github.com/hashicorp/terraform-plugin-framework/providerserver" + "github.com/hashicorp/terraform-plugin-go/tfprotov5" + "github.com/hashicorp/terraform-plugin-go/tfprotov5/tf5server" + "github.com/hashicorp/terraform-plugin-mux/tf5muxserver" "github.com/okta/terraform-provider-okta/okta" ) @@ -14,11 +19,32 @@ import ( //go:generate go run github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs func main() { - // Set descriptions to support Markdown syntax, - // this will be used in document generation. - schema.DescriptionKind = schema.StringMarkdown + var debug bool + providers := []func() tfprotov5.ProviderServer{ + // v2 plugin + okta.Provider().GRPCProvider, + // v3 plugin + providerserver.NewProtocol5(okta.NewFWProvider(okta.OktaTerraformProviderVersion)), + } + + // use the muxer + muxServer, err := tf5muxserver.NewMuxServer(context.Background(), providers...) + if err != nil { + log.Fatalf(err.Error()) + } + + var serveOpts []tf5server.ServeOpt + + if debug { + serveOpts = append(serveOpts, tf5server.WithManagedDebug()) + } - plugin.Serve(&plugin.ServeOpts{ - ProviderFunc: okta.Provider, - }) + err = tf5server.Serve( + "okta/okta", + muxServer.ProviderServer, + serveOpts..., + ) + if err != nil { + log.Fatal(err) + } } diff --git a/okta/config.go b/okta/config.go index 16ecfc6af..efb1ecc07 100644 --- a/okta/config.go +++ b/okta/config.go @@ -6,12 +6,15 @@ import ( "fmt" "net/http" "os" + "strconv" "strings" "time" "github.com/hashicorp/go-cleanhttp" "github.com/hashicorp/go-hclog" "github.com/hashicorp/go-retryablehttp" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/logging" "github.com/okta/okta-sdk-golang/v3/okta" "github.com/okta/terraform-provider-okta/okta/internal/apimutex" @@ -19,7 +22,8 @@ import ( "github.com/okta/terraform-provider-okta/sdk" ) -const OktaTerraformProviderUserAgent = "okta-terraform/4.1.0" +const OktaTerraformProviderVersion = "4.1.0" +const OktaTerraformProviderUserAgent = "okta-terraform/" + OktaTerraformProviderVersion func (adt *AddHeaderTransport) RoundTrip(req *http.Request) (*http.Response, error) { req.Header.Add("User-Agent", "Okta Terraform Provider") @@ -125,6 +129,69 @@ func (c *Config) loadAndValidate(ctx context.Context) error { return nil } +func (c *Config) handleDefaults(ctx context.Context, data *FrameworkProviderData) error { + var err error + if data.OrgName.IsNull() && os.Getenv("OKTA_ORG_NAME") != "" { + data.OrgName = types.StringValue(os.Getenv("OKTA_ORG_NAME")) + } + if data.AccessToken.IsNull() && os.Getenv("OKTA_ACCESS_TOKEN") != "" { + data.AccessToken = types.StringValue(os.Getenv("OKTA_ACCESS_TOKEN")) + } + if data.APIToken.IsNull() && os.Getenv("OKTA_API_TOKEN") != "" { + data.APIToken = types.StringValue(os.Getenv("OKTA_API_TOKEN")) + } + if data.ClientID.IsNull() && os.Getenv("OKTA_API_CLIENT_ID") != "" { + data.ClientID = types.StringValue(os.Getenv("OKTA_API_CLIENT_ID")) + } + if data.Scopes.IsNull() && os.Getenv("OKTA_API_SCOPES") != "" { + v := os.Getenv("OKTA_API_SCOPES") + scopes := strings.Split(v, ",") + if len(scopes) > 0 { + scopesTF := make([]attr.Value, 0) + for _, scope := range scopes { + scopesTF = append(scopesTF, types.StringValue(scope)) + } + data.Scopes, _ = types.SetValue(types.StringType, scopesTF) + } + } + if data.PrivateKey.IsNull() && os.Getenv("OKTA_API_PRIVATE_KEY") != "" { + data.PrivateKey = types.StringValue(os.Getenv("OKTA_API_PRIVATE_KEY")) + } + if data.PrivateKeyID.IsNull() && os.Getenv("OKTA_API_PRIVATE_KEY_ID") != "" { + data.PrivateKeyID = types.StringValue(os.Getenv("OKTA_API_PRIVATE_KEY_ID")) + } + if data.BaseURL.IsNull() { + if os.Getenv("OKTA_BASE_URL") != "" { + data.BaseURL = types.StringValue(os.Getenv("OKTA_API_PRIVATE_KEY_ID")) + } else { + data.BaseURL = types.StringValue("okta.com") + } + } + if data.HTTPProxy.IsNull() && os.Getenv("OKTA_HTTP_PROXY") != "" { + data.HTTPProxy = types.StringValue(os.Getenv("OKTA_HTTP_PROXY")) + } + if data.MaxAPICapacity.IsNull() { + if os.Getenv("MAX_API_CAPACITY") != "" { + mac, err := strconv.ParseInt(os.Getenv("MAX_API_CAPACITY"), 10, 64) + if err != nil { + return err + } + data.MaxAPICapacity = types.Int64Value(mac) + } else { + data.MaxAPICapacity = types.Int64Value(100) + } + } + data.Backoff = types.BoolValue(true) + data.MinWaitSeconds = types.Int64Value(30) + data.MaxWaitSeconds = types.Int64Value(300) + data.MaxRetries = types.Int64Value(5) + data.Parallelism = types.Int64Value(1) + data.LogLevel = types.Int64Value(int64(hclog.Error)) + data.RequestTimeout = types.Int64Value(0) + + return err +} + func providerLogger(c *Config) hclog.Logger { logLevel := hclog.Level(c.logLevel) if os.Getenv("TF_LOG") != "" { diff --git a/okta/framework_provider.go b/okta/framework_provider.go new file mode 100644 index 000000000..76a5f1769 --- /dev/null +++ b/okta/framework_provider.go @@ -0,0 +1,253 @@ +package okta + +import ( + "context" + "strings" + + "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" + "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/provider" + "github.com/hashicorp/terraform-plugin-framework/provider/schema" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// Ensure the implementation satisfies the expected interfaces. +var ( + _ provider.Provider = &FrameworkProvider{} +) + +// New is a helper function to simplify provider server and testing implementation. +func NewFWProvider(version string) provider.Provider { + return &FrameworkProvider{} +} + +type FrameworkProvider struct { + Config + Version string +} + +type FrameworkProviderData struct { + OrgName types.String `tfsdk:"org_name"` + AccessToken types.String `tfsdk:"access_token"` + APIToken types.String `tfsdk:"api_token"` + ClientID types.String `tfsdk:"client_id"` + Scopes types.Set `tfsdk:"scopes"` + PrivateKey types.String `tfsdk:"private_key"` + PrivateKeyID types.String `tfsdk:"private_key_id"` + BaseURL types.String `tfsdk:"base_url"` + HTTPProxy types.String `tfsdk:"http_proxy"` + Backoff types.Bool `tfsdk:"backoff"` + MinWaitSeconds types.Int64 `tfsdk:"min_wait_seconds"` + MaxWaitSeconds types.Int64 `tfsdk:"max_wait_seconds"` + MaxRetries types.Int64 `tfsdk:"max_retries"` + Parallelism types.Int64 `tfsdk:"parallelism"` + LogLevel types.Int64 `tfsdk:"log_level"` + MaxAPICapacity types.Int64 `tfsdk:"max_api_capacity"` + RequestTimeout types.Int64 `tfsdk:"request_timeout"` +} + +// Metadata returns the provider type name. +func (p *FrameworkProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) { + resp.TypeName = "okta" + resp.Version = p.Version +} + +// Schema defines the provider-level schema for configuration data. +func (p *FrameworkProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "org_name": schema.StringAttribute{ + Optional: true, + Description: "The organization to manage in Okta.", + }, + "access_token": schema.StringAttribute{ + Optional: true, + Description: "Bearer token granting privileges to Okta API.", + Validators: []validator.String{ + stringvalidator.ConflictsWith(path.Expressions{ + path.MatchRoot("api_token"), + path.MatchRoot("client_id"), + path.MatchRoot("scopes"), + path.MatchRoot("private_key"), + }...), + }, + }, + "api_token": schema.StringAttribute{ + Optional: true, + Description: "API Token granting privileges to Okta API.", + Validators: []validator.String{ + stringvalidator.ConflictsWith(path.Expressions{ + path.MatchRoot("access_token"), + path.MatchRoot("client_id"), + path.MatchRoot("scopes"), + path.MatchRoot("private_key"), + }...), + }, + }, + "client_id": schema.StringAttribute{ + Optional: true, + Description: "API Token granting privileges to Okta API.", + Validators: []validator.String{ + stringvalidator.ConflictsWith(path.Expressions{ + path.MatchRoot("access_token"), + path.MatchRoot("api_token"), + }...), + }, + }, + "scopes": schema.SetAttribute{ + Optional: true, + Description: "API Token granting privileges to Okta API.", + ElementType: types.StringType, + Validators: []validator.Set{ + setvalidator.ConflictsWith(path.Expressions{ + path.MatchRoot("access_token"), + path.MatchRoot("api_token"), + }...), + }, + }, + "private_key": schema.StringAttribute{ + Optional: true, + Description: "API Token granting privileges to Okta API.", + Validators: []validator.String{ + stringvalidator.ConflictsWith(path.Expressions{ + path.MatchRoot("access_token"), + path.MatchRoot("api_token"), + }...), + }, + }, + "private_key_id": schema.StringAttribute{ + Optional: true, + Description: "API Token Id granting privileges to Okta API.", + Validators: []validator.String{ + stringvalidator.ConflictsWith(path.Expressions{ + path.MatchRoot("api_token"), + }...), + }, + }, + "base_url": schema.StringAttribute{ + Optional: true, + Description: "The Okta url. (Use 'oktapreview.com' for Okta testing)", + }, + "http_proxy": schema.StringAttribute{ + Optional: true, + Description: "Alternate HTTP proxy of scheme://hostname or scheme://hostname:port format", + }, + "backoff": schema.BoolAttribute{ + Optional: true, + Description: "Use exponential back off strategy for rate limits.", + }, + "min_wait_seconds": schema.Int64Attribute{ + Optional: true, + Description: "minimum seconds to wait when rate limit is hit. We use exponential backoffs when backoff is enabled.", + }, + "max_wait_seconds": schema.Int64Attribute{ + Optional: true, + Description: "maximum seconds to wait when rate limit is hit. We use exponential backoffs when backoff is enabled.", + }, + "max_retries": schema.Int64Attribute{ + Optional: true, + Description: "maximum number of retries to attempt before erroring out.", + Validators: []validator.Int64{ + int64validator.AtMost(100), + }, + }, + "parallelism": schema.Int64Attribute{ + Optional: true, + Description: "Number of concurrent requests to make within a resource where bulk operations are not possible. Take note of https://developer.okta.com/docs/api/getting_started/rate-limits.", + }, + "log_level": schema.Int64Attribute{ + Optional: true, + Description: "providers log level. Minimum is 1 (TRACE), and maximum is 5 (ERROR)", + Validators: []validator.Int64{ + int64validator.AtLeast(1), + int64validator.AtMost(5), + }, + }, + "max_api_capacity": schema.Int64Attribute{ + Optional: true, + Description: "(Experimental) sets what percentage of capacity the provider can use of the total rate limit " + + "capacity while making calls to the Okta management API endpoints. Okta API operates in one minute buckets. " + + "See Okta Management API Rate Limits: https://developer.okta.com/docs/reference/rl-global-mgmt/", + Validators: []validator.Int64{ + int64validator.AtLeast(1), + int64validator.AtMost(100), + }, + }, + "request_timeout": schema.Int64Attribute{ + Optional: true, + Description: "Timeout for single request (in seconds) which is made to Okta, the default is `0` (means no limit is set). The maximum value can be `300`.", + Validators: []validator.Int64{ + int64validator.AtLeast(0), + int64validator.AtMost(300), + }, + }, + }, + } +} + +func (p *FrameworkProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { + // Retrieve provider data from configuration + var data FrameworkProviderData + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + err := p.handleDefaults(ctx, &data) + if err != nil { + resp.Diagnostics.AddError("failed to load default value to provider", err.Error()) + return + } + + p.orgName = data.OrgName.ValueString() + p.accessToken = data.AccessToken.ValueString() + p.apiToken = data.APIToken.ValueString() + p.clientID = data.ClientID.ValueString() + p.privateKey = data.PrivateKey.ValueString() + p.privateKeyId = data.PrivateKeyID.ValueString() + p.domain = data.BaseURL.ValueString() + p.maxAPICapacity = int(data.MaxWaitSeconds.ValueInt64()) + p.backoff = data.Backoff.ValueBool() + p.minWait = int(data.MinWaitSeconds.ValueInt64()) + p.maxWait = int(data.MaxRetries.ValueInt64()) + p.retryCount = int(data.MaxRetries.ValueInt64()) + p.parallelism = int(data.Parallelism.ValueInt64()) + p.logLevel = int(data.LogLevel.ValueInt64()) + p.requestTimeout = int(data.RequestTimeout.ValueInt64()) + scopes := data.Scopes.String() + sanitizeScope := scopes[1 : len(scopes)-1] + p.scopes = strings.Split(sanitizeScope, ",") + if !data.HTTPProxy.IsNull() { + p.httpProxy = data.HTTPProxy.ValueString() + } + + err = p.loadAndValidate(ctx) + if err != nil { + resp.Diagnostics.AddError("failed to load default value to provider", err.Error()) + return + } + + resp.DataSourceData = &p.Config + resp.ResourceData = &p.Config +} + +// DataSources defines the data sources implemented in the provider. +func (p *FrameworkProvider) DataSources(_ context.Context) []func() datasource.DataSource { + return nil +} + +// DataSources defines the data sources implemented in the provider. +func (p *FrameworkProvider) Resources(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + NewPolicyDeviceAssuranceAndroidResource, + NewPolicyDeviceAssuranceIOSResource, + NewPolicyDeviceAssuranceChromeOSResource, + NewPolicyDeviceAssuranceMacOSResource, + NewPolicyDeviceAssuranceWindowsResource, + } +} diff --git a/okta/provider.go b/okta/provider.go index 94b0b57a1..ca8b7f8b4 100644 --- a/okta/provider.go +++ b/okta/provider.go @@ -10,7 +10,6 @@ import ( "time" "github.com/cenkalti/backoff" - "github.com/hashicorp/go-hclog" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -139,27 +138,23 @@ func Provider() *schema.Provider { "org_name": { Type: schema.TypeString, Optional: true, - DefaultFunc: schema.EnvDefaultFunc("OKTA_ORG_NAME", nil), Description: "The organization to manage in Okta.", }, "access_token": { Type: schema.TypeString, Optional: true, - DefaultFunc: schema.EnvDefaultFunc("OKTA_ACCESS_TOKEN", nil), Description: "Bearer token granting privileges to Okta API.", ConflictsWith: []string{"api_token", "client_id", "scopes", "private_key"}, }, "api_token": { Type: schema.TypeString, Optional: true, - DefaultFunc: schema.EnvDefaultFunc("OKTA_API_TOKEN", nil), Description: "API Token granting privileges to Okta API.", ConflictsWith: []string{"access_token", "client_id", "scopes", "private_key"}, }, "client_id": { Type: schema.TypeString, Optional: true, - DefaultFunc: schema.EnvDefaultFunc("OKTA_API_CLIENT_ID", nil), Description: "API Token granting privileges to Okta API.", ConflictsWith: []string{"access_token", "api_token"}, }, @@ -167,71 +162,60 @@ func Provider() *schema.Provider { Type: schema.TypeSet, Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, - DefaultFunc: envDefaultSetFunc("OKTA_API_SCOPES", nil), Description: "API Token granting privileges to Okta API.", ConflictsWith: []string{"access_token", "api_token"}, }, "private_key": { Optional: true, Type: schema.TypeString, - DefaultFunc: schema.EnvDefaultFunc("OKTA_API_PRIVATE_KEY", nil), Description: "API Token granting privileges to Okta API.", ConflictsWith: []string{"access_token", "api_token"}, }, "private_key_id": { Optional: true, Type: schema.TypeString, - DefaultFunc: schema.EnvDefaultFunc("OKTA_API_PRIVATE_KEY_ID", nil), Description: "API Token Id granting privileges to Okta API.", ConflictsWith: []string{"api_token"}, }, "base_url": { Type: schema.TypeString, Optional: true, - DefaultFunc: schema.EnvDefaultFunc("OKTA_BASE_URL", "okta.com"), Description: "The Okta url. (Use 'oktapreview.com' for Okta testing)", }, "http_proxy": { Type: schema.TypeString, Optional: true, - DefaultFunc: schema.EnvDefaultFunc("OKTA_HTTP_PROXY", ""), Description: "Alternate HTTP proxy of scheme://hostname or scheme://hostname:port format", }, "backoff": { Type: schema.TypeBool, Optional: true, - Default: true, Description: "Use exponential back off strategy for rate limits.", }, "min_wait_seconds": { Type: schema.TypeInt, Optional: true, - Default: 30, Description: "minimum seconds to wait when rate limit is hit. We use exponential backoffs when backoff is enabled.", }, "max_wait_seconds": { Type: schema.TypeInt, Optional: true, - Default: 300, Description: "maximum seconds to wait when rate limit is hit. We use exponential backoffs when backoff is enabled.", }, "max_retries": { Type: schema.TypeInt, Optional: true, - Default: 5, ValidateDiagFunc: intAtMost(100), Description: "maximum number of retries to attempt before erroring out.", }, "parallelism": { Type: schema.TypeInt, Optional: true, - Default: 1, Description: "Number of concurrent requests to make within a resource where bulk operations are not possible. Take note of https://developer.okta.com/docs/api/getting_started/rate-limits.", }, "log_level": { Type: schema.TypeInt, Optional: true, - Default: int(hclog.Error), ValidateDiagFunc: intBetween(1, 5), Description: "providers log level. Minimum is 1 (TRACE), and maximum is 5 (ERROR)", }, @@ -239,7 +223,6 @@ func Provider() *schema.Provider { Type: schema.TypeInt, Optional: true, ValidateDiagFunc: intBetween(1, 100), - DefaultFunc: schema.EnvDefaultFunc("MAX_API_CAPACITY", 100), Description: "(Experimental) sets what percentage of capacity the provider can use of the total rate limit " + "capacity while making calls to the Okta management API endpoints. Okta API operates in one minute buckets. " + "See Okta Management API Rate Limits: https://developer.okta.com/docs/reference/rl-global-mgmt/", @@ -247,7 +230,6 @@ func Provider() *schema.Provider { "request_timeout": { Type: schema.TypeInt, Optional: true, - Default: 0, ValidateDiagFunc: intBetween(0, 300), Description: "Timeout for single request (in seconds) which is made to Okta, the default is `0` (means no limit is set). The maximum value can be `300`.", }, @@ -432,20 +414,6 @@ func providerConfigure(ctx context.Context, d *schema.ResourceData) (interface{} // This is a global MutexKV for use within this plugin. var oktaMutexKV = mutexkv.NewMutexKV() -func envDefaultSetFunc(k string, dv interface{}) schema.SchemaDefaultFunc { - return func() (interface{}, error) { - if v := os.Getenv(k); v != "" { - stringList := strings.Split(v, ",") - arr := make([]interface{}, len(stringList)) - for i := range stringList { - arr[i] = stringList[i] - } - return arr, nil - } - return dv, nil - } -} - func isClassicOrg(ctx context.Context, m interface{}) bool { if config, ok := m.(*Config); ok && config.IsClassicOrg(ctx) { return true diff --git a/okta/resource_okta_policy_device_assurance_androi.go b/okta/resource_okta_policy_device_assurance_androi.go new file mode 100644 index 000000000..b88ce050e --- /dev/null +++ b/okta/resource_okta_policy_device_assurance_androi.go @@ -0,0 +1,383 @@ +package okta + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-framework-validators/boolvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/diag" + "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/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/okta/okta-sdk-golang/v3/okta" +) + +// Ensure the implementation satisfies the expected interfaces. +var ( + _ resource.Resource = &policyDeviceAssuranceAndroidResource{} + _ resource.ResourceWithConfigure = &policyDeviceAssuranceAndroidResource{} + // _ resource.ResourceWithImportState = &policyDeviceAssuranceResource{} +) + +func NewPolicyDeviceAssuranceAndroidResource() resource.Resource { + return &policyDeviceAssuranceAndroidResource{} +} + +type policyDeviceAssuranceAndroidResource struct { + *Config +} + +type policyDeviceAssuranceAndroidResourceModel struct { + ID types.String `tfsdk:"id"` + Name types.String `tfsdk:"name"` + Platform types.String `tfsdk:"platform"` + DiskEncryptionType []types.String `tfsdk:"disk_encryption_type"` + JailBreak types.Bool `tfsdk:"jailbreak"` + OsVersion types.String `tfsdk:"os_version"` + SecureHardwarePresent types.Bool `tfsdk:"secure_hardware_present"` + ScreenLockType []types.String `tfsdk:"screenlock_type"` + CreateDate types.String `tfsdk:"created_date"` + CreateBy types.String `tfsdk:"created_by"` + LastUpdate types.String `tfsdk:"last_update"` + LastUpdatedBy types.String `tfsdk:"last_updated_by"` +} + +func (r *policyDeviceAssuranceAndroidResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_policy_device_assurance_android" +} + +func (r *policyDeviceAssuranceAndroidResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Manages device assurance on policy", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "Policy assurance id", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "name": schema.StringAttribute{ + Description: "Policy device assurance name", + Required: true, + }, + "platform": schema.StringAttribute{ + Description: "Policy device assurance platform", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + // use set to avoid order change as v3 does not have diff suppress func + "disk_encryption_type": schema.SetAttribute{ + Description: "List of disk encryption type, can be FULL, USER", + Optional: true, + ElementType: types.StringType, + Validators: []validator.Set{ + setvalidator.AtLeastOneOf(path.Expressions{ + path.MatchRoot("jailbreak"), + path.MatchRoot("os_version"), + path.MatchRoot("secure_hardware_present"), + path.MatchRoot("screenlock_type"), + }...), + }, + }, + "jailbreak": schema.BoolAttribute{ + Description: "The device jailbreak. Only for android and iOS platform", + Optional: true, + Validators: []validator.Bool{ + boolvalidator.AtLeastOneOf(path.Expressions{ + path.MatchRoot("disk_encryption_type"), + path.MatchRoot("os_version"), + path.MatchRoot("secure_hardware_present"), + path.MatchRoot("screenlock_type"), + }...), + }, + }, + "os_version": schema.StringAttribute{ + Description: "The device os minimum version", + Optional: true, + Validators: []validator.String{ + stringvalidator.AtLeastOneOf(path.Expressions{ + path.MatchRoot("disk_encryption_type"), + path.MatchRoot("jailbreak"), + path.MatchRoot("secure_hardware_present"), + path.MatchRoot("screenlock_type"), + }...), + }, + }, + "secure_hardware_present": schema.BoolAttribute{ + Description: "Indicates if the device constains a secure hardware functionality", + Optional: true, + Validators: []validator.Bool{ + boolvalidator.AtLeastOneOf(path.Expressions{ + path.MatchRoot("disk_encryption_type"), + path.MatchRoot("jailbreak"), + path.MatchRoot("os_version"), + path.MatchRoot("screenlock_type"), + }...), + }, + }, + "screenlock_type": schema.SetAttribute{ + Description: "List of screenlock type, can be BIOMETRIC, PASSCODE", + Optional: true, + ElementType: types.StringType, + Validators: []validator.Set{ + setvalidator.AtLeastOneOf(path.Expressions{ + path.MatchRoot("disk_encryption_type"), + path.MatchRoot("jailbreak"), + path.MatchRoot("os_version"), + path.MatchRoot("secure_hardware_present"), + }...), + }, + }, + "created_date": schema.StringAttribute{ + Description: "Created date", + Computed: true, + }, + "created_by": schema.StringAttribute{ + Description: "Created by", + Computed: true, + }, + "last_update": schema.StringAttribute{ + Description: "Last update", + Computed: true, + }, + "last_updated_by": schema.StringAttribute{ + Description: "Last updated by", + Computed: true, + }, + }, + } +} + +// Configure adds the provider configured client to the resource. +func (r *policyDeviceAssuranceAndroidResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + p, 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 = p +} + +func (r *policyDeviceAssuranceAndroidResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var state policyDeviceAssuranceAndroidResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + reqBody, err := buildDeviceAssuranceAndroidPolicyRequest(state) + if err != nil { + resp.Diagnostics.AddError( + "failed to build device assurance request", + err.Error(), + ) + return + } + + deviceAssurance, _, err := r.v3Client.DeviceAssuranceApi.CreateDeviceAssurancePolicy(ctx).DeviceAssurance(reqBody).Execute() + if err != nil { + resp.Diagnostics.AddError( + "failed to create device assurance", + err.Error(), + ) + return + } + + // TODU need to do additional read? + resp.Diagnostics.Append(mapDeviceAssuranceAndroidToState(deviceAssurance, &state)...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } +} + +func (r *policyDeviceAssuranceAndroidResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state policyDeviceAssuranceAndroidResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + deviceAssurance, _, err := r.v3Client.DeviceAssuranceApi.GetDeviceAssurancePolicy(ctx, state.ID.ValueString()).Execute() + if err != nil { + resp.Diagnostics.AddError( + "failed to read device assurance", + err.Error(), + ) + return + } + + resp.Diagnostics.Append(mapDeviceAssuranceAndroidToState(deviceAssurance, &state)...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } +} + +func (r *policyDeviceAssuranceAndroidResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state policyDeviceAssuranceAndroidResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + _, err := r.v3Client.DeviceAssuranceApi.DeleteDeviceAssurancePolicy(ctx, state.ID.ValueString()).Execute() + if err != nil { + resp.Diagnostics.AddError( + "failed to delete device assurance", + err.Error(), + ) + return + } +} + +func (r *policyDeviceAssuranceAndroidResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var state policyDeviceAssuranceAndroidResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + reqBody, err := buildDeviceAssuranceAndroidPolicyRequest(state) + if err != nil { + resp.Diagnostics.AddError( + "failed to build device assurance request", + err.Error(), + ) + return + } + + deviceAssurance, _, err := r.v3Client.DeviceAssuranceApi.ReplaceDeviceAssurancePolicy(ctx, state.ID.ValueString()).DeviceAssurance(reqBody).Execute() + if err != nil { + resp.Diagnostics.AddError( + "failed to create device assurance", + err.Error(), + ) + return + } + + // TODU need to do additional read? + resp.Diagnostics.Append(mapDeviceAssuranceAndroidToState(deviceAssurance, &state)...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } +} + +func buildDeviceAssuranceAndroidPolicyRequest(model policyDeviceAssuranceAndroidResourceModel) (okta.ListDeviceAssurancePolicies200ResponseInner, error) { + var android = &okta.DeviceAssuranceAndroidPlatform{} + android.SetName(model.Name.ValueString()) + android.SetPlatform(okta.PLATFORM_ANDROID) + if len(model.DiskEncryptionType) > 0 { + diskEncryptionType := make([]okta.DiskEncryptionType, 0) + for _, det := range model.DiskEncryptionType { + v, err := okta.NewDiskEncryptionTypeFromValue(det.ValueString()) + if err != nil { + return okta.ListDeviceAssurancePolicies200ResponseInner{DeviceAssuranceAndroidPlatform: android}, err + } + diskEncryptionType = append(diskEncryptionType, *v) + } + android.DiskEncryptionType = &okta.DeviceAssuranceAndroidPlatformAllOfDiskEncryptionType{Include: diskEncryptionType} + } + android.Jailbreak = model.JailBreak.ValueBoolPointer() + if !model.OsVersion.IsNull() { + android.OsVersion = &okta.OSVersion{Minimum: model.OsVersion.ValueStringPointer()} + } + if len(model.ScreenLockType) > 0 { + screenlockType := make([]okta.ScreenLockType, 0) + for _, det := range model.ScreenLockType { + v, err := okta.NewScreenLockTypeFromValue(det.ValueString()) + if err != nil { + return okta.ListDeviceAssurancePolicies200ResponseInner{DeviceAssuranceAndroidPlatform: android}, err + } + screenlockType = append(screenlockType, *v) + } + android.ScreenLockType = &okta.DeviceAssuranceAndroidPlatformAllOfScreenLockType{Include: screenlockType} + } + android.SecureHardwarePresent = model.SecureHardwarePresent.ValueBoolPointer() + return okta.ListDeviceAssurancePolicies200ResponseInner{DeviceAssuranceAndroidPlatform: android}, nil +} + +// Map response body to schema +func mapDeviceAssuranceAndroidToState(data *okta.ListDeviceAssurancePolicies200ResponseInner, state *policyDeviceAssuranceAndroidResourceModel) diag.Diagnostics { + var diags diag.Diagnostics + state.ID = types.StringValue(data.DeviceAssuranceAndroidPlatform.GetId()) + state.Name = types.StringValue(data.DeviceAssuranceAndroidPlatform.GetName()) + state.Platform = types.StringValue(string(data.DeviceAssuranceAndroidPlatform.GetPlatform())) + + if _, ok := data.DeviceAssuranceAndroidPlatform.GetJailbreakOk(); ok { + state.JailBreak = types.BoolValue(data.DeviceAssuranceAndroidPlatform.GetJailbreak()) + } + if _, ok := data.DeviceAssuranceAndroidPlatform.GetSecureHardwarePresentOk(); ok { + state.SecureHardwarePresent = types.BoolValue(data.DeviceAssuranceAndroidPlatform.GetSecureHardwarePresent()) + } + if _, ok := data.DeviceAssuranceAndroidPlatform.GetOsVersionOk(); ok { + state.OsVersion = types.StringValue(data.DeviceAssuranceAndroidPlatform.OsVersion.GetMinimum()) + } + if _, ok := data.DeviceAssuranceAndroidPlatform.DiskEncryptionType.GetIncludeOk(); ok { + diskEncryptionType := make([]types.String, 0) + for _, det := range data.DeviceAssuranceAndroidPlatform.DiskEncryptionType.GetInclude() { + diskEncryptionType = append(diskEncryptionType, types.StringValue(string(det))) + } + state.DiskEncryptionType = diskEncryptionType + } + if _, ok := data.DeviceAssuranceAndroidPlatform.ScreenLockType.GetIncludeOk(); ok { + screenLockType := make([]types.String, 0) + for _, slt := range data.DeviceAssuranceAndroidPlatform.ScreenLockType.GetInclude() { + screenLockType = append(screenLockType, types.StringValue(string(slt))) + } + state.ScreenLockType = screenLockType + } + + state.CreateDate = types.StringValue(string(data.DeviceAssuranceAndroidPlatform.GetCreatedDate())) + state.CreateBy = types.StringValue(string(data.DeviceAssuranceAndroidPlatform.GetCreatedBy())) + state.LastUpdate = types.StringValue(string(data.DeviceAssuranceAndroidPlatform.GetLastUpdate())) + state.LastUpdatedBy = types.StringValue(string(data.DeviceAssuranceAndroidPlatform.GetLastUpdatedBy())) + return diags +} + +// // TODU types.List +// res := model.ScreenLockType.Elements() +// z := make([]string, 0) +// for _, r := range res { +// z = append(z, r.String()) +// } +// // TODU []types.String +// z := make([]string, 0) +// for _, r := range model.ScreenLockType { +// z = append(z, r.ValueString()) +// } +// // TODU []string +// z := make([]string, 0) +// for _, r := range model.ScreenLockType { +// z = append(z, r) +// } diff --git a/okta/resource_okta_policy_device_assurance_androi_test.go b/okta/resource_okta_policy_device_assurance_androi_test.go new file mode 100644 index 000000000..d59cbc533 --- /dev/null +++ b/okta/resource_okta_policy_device_assurance_androi_test.go @@ -0,0 +1,69 @@ +package okta + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-framework/providerserver" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +const ( + // providerConfig is a shared configuration to combine with the actual + // test configuration so the HashiCups client is properly configured. + // It is also possible to use the HASHICUPS_ environment variables instead, + // such as updating the Makefile and running the testing through that tool. + providerConfig = ` +` +) + +var ( + // testAccProtoV6ProviderFactories are used to instantiate a provider during + // acceptance testing. The factory function will be invoked for every Terraform + // CLI command executed to create a provider server to which the CLI can + // reattach. + testAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){ + "okta": providerserver.NewProtocol6WithError(NewFWProvider("test")), + } +) + +func TestAccPolicyDeviceAssuranceAndroid(t *testing.T) { + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: providerConfig + ` + resource okta_policy_device_assurance_android test{ + name = "test" + os_version = "12" + disk_encryption_type = toset(["FULL", "USER"]) + jailbreak = false + secure_hardware_present = true + screenlock_type = toset(["BIOMETRIC"]) + }`, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("okta_policy_device_assurance_android.test", "name", "test"), + resource.TestCheckResourceAttr("okta_policy_device_assurance_android.test", "os_version", "12"), + resource.TestCheckResourceAttr("okta_policy_device_assurance_android.test", "jailbreak", "false"), + resource.TestCheckResourceAttr("okta_policy_device_assurance_android.test", "secure_hardware_present", "true"), + resource.TestCheckResourceAttr("okta_policy_device_assurance_android.test", "disk_encryption_type.#", "2"), + ), + }, + { + Config: providerConfig + ` + resource okta_policy_device_assurance_android test{ + name = "test" + os_version = "13" + disk_encryption_type = toset(["FULL", "USER"]) + jailbreak = false + secure_hardware_present = true + screenlock_type = toset(["BIOMETRIC"]) + }`, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("okta_policy_device_assurance_android.test", "name", "test"), + resource.TestCheckResourceAttr("okta_policy_device_assurance_android.test", "os_version", "13"), + ), + }, + }, + }) +} diff --git a/okta/resource_okta_policy_device_assurance_chromeOS.go b/okta/resource_okta_policy_device_assurance_chromeOS.go new file mode 100644 index 000000000..f8993868c --- /dev/null +++ b/okta/resource_okta_policy_device_assurance_chromeOS.go @@ -0,0 +1,439 @@ +package okta + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework-validators/boolvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "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/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/okta/okta-sdk-golang/v3/okta" +) + +// Ensure the implementation satisfies the expected interfaces. +var ( + _ resource.Resource = &policyDeviceAssuranceChromeOSResource{} + // _ resource.ResourceWithConfigure = &policyDeviceAssuranceResource{} + // _ resource.ResourceWithImportState = &policyDeviceAssuranceResource{} +) + +func NewPolicyDeviceAssuranceChromeOSResource() resource.Resource { + return &policyDeviceAssuranceChromeOSResource{} +} + +type policyDeviceAssuranceChromeOSResource struct { + v3Client *okta.APIClient +} + +type policyDeviceAssuranceChromeOSResourceModel struct { + ID types.String `tfsdk:"id"` + Name types.String `tfsdk:"name"` + Platform types.String `tfsdk:"platform"` + DiskEncryptionType types.List `tfsdk:"disk_encryption_type"` + JailBreak types.Bool `tfsdk:"jailbreak"` + OsVersion types.String `tfsdk:"os_version"` + SecureHardwarePresent types.Bool `tfsdk:"secure_hardware_present"` + ScreenLockType types.List `tfsdk:"screenlock_type"` + // TODU + ThirdPartySignalProviders thirdPartySignalProvidersChromeOS `tfsdk:"third_party_signal_providers"` + CreateDate types.String `tfsdk:"created_date"` + CreateBy types.String `tfsdk:"created_by"` + LastUpdate types.String `tfsdk:"last_update"` + LastUpdatedBy types.String `tfsdk:"last_updated_by"` +} + +type thirdPartySignalProvidersChromeOS struct { + AllowScreenLock types.Bool `tfsdk:"allow_screen_lock"` + BrowserVersion types.String `tfsdk:"browser_version, omitempty"` + BuiltInDNSClientEnabled types.Bool `tfsdk:"builtin_dns_client_enabled"` + ChromeRemoteDesktopAppBlocked types.Bool `tfsdk:"chrome_remote_desktop_app_blocked"` + CrowdStrikeAgentID types.String `tfsdk:"crowd_strike_agent_id"` + CrowdStrikeCustomerID types.String `tfsdk:"crowd_strike_customer_id"` + DeviceEnrollementDomain types.String `tfsdk:"device_enrollement_domain"` + DiskEncrypted types.Bool `tfsdk:"disk_encrypted"` + KeyTrustLevel types.String `tfsdk:"key_trust_level"` + OsFirewall types.Bool `tfsdk:"os_firewall"` + OsVersion types.String `tfsdk:"os_version"` + PasswordProctectionWarningTrigger types.String `tfsdk:"password_proctection_warning_trigger"` + RealtimeURLCheckMode types.Bool `tfsdk:"realtime_url_check_mode"` + SafeBrowsingProtectionLevel types.String `tfsdk:"safe_browsing_protection_level"` + ScreenLockSecured types.Bool `tfsdk:"screen_lock_secured"` + SecureBootEnabled types.Bool `tfsdk:"secure_boot_enabled"` + SiteIsolationEnabled types.Bool `tfsdk:"site_isolation_enabled"` + ThirdPartyBlockingEnabled types.Bool `tfsdk:"third_party_blocking_enabled"` + WindowMachineDomain types.String `tfsdk:"window_machine_domain"` + WindowUserDomain types.String `tfsdk:"window_user_domain"` +} + +func (r *policyDeviceAssuranceChromeOSResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_policy_device_assurance_chromeOS" +} + +// TODU different requirement for request and response? +// TODU validation +func (r *policyDeviceAssuranceChromeOSResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Manages device assurance on policy", + Attributes: map[string]schema.Attribute{ + // TODU needed? + "id": schema.StringAttribute{ + Description: "Policy assurance id", + Computed: true, + PlanModifiers: []planmodifier.String{ + // TODU + stringplanmodifier.UseStateForUnknown(), + }, + }, + "name": schema.StringAttribute{ + Description: "Policy device assurance name", + Required: true, + }, + "platform": schema.StringAttribute{ + Description: "Policy device assurance platform, can be ANDROID, CHROMEOS, IOS, MACOS or WINDOWS", + Required: true, + }, + "disk_encryption_type": schema.ListAttribute{ + Description: "List of disk encryption type, can be ALL_INTERNAL_VOLUMES, FULL, or USER", + Optional: true, + ElementType: types.StringType, + Validators: []validator.List{ + listvalidator.AtLeastOneOf(path.Expressions{ + path.MatchRoot("jail_break"), + path.MatchRoot("os_version"), + path.MatchRoot("secure_hardware_present"), + path.MatchRoot("screenlock_type"), + }...), + }, + }, + "jail_break": schema.BoolAttribute{ + Description: "The device jailbreak. Only for android and iOS platform", + Optional: true, + Validators: []validator.Bool{ + boolvalidator.AtLeastOneOf(path.Expressions{ + path.MatchRoot("disk_encryption_type"), + path.MatchRoot("os_version"), + path.MatchRoot("secure_hardware_present"), + path.MatchRoot("screenlock_type"), + }...), + }, + }, + "os_version": schema.StringAttribute{ + Description: "The device os version", + Optional: true, + Validators: []validator.String{ + stringvalidator.AtLeastOneOf(path.Expressions{ + path.MatchRoot("disk_encryption_type"), + path.MatchRoot("jail_break"), + path.MatchRoot("secure_hardware_present"), + path.MatchRoot("screenlock_type"), + }...), + }, + }, + "secure_hardware_present": schema.BoolAttribute{ + Description: "Indicates if the device constains a secure hardware functionality", + Optional: true, + Validators: []validator.Bool{ + boolvalidator.AtLeastOneOf(path.Expressions{ + path.MatchRoot("disk_encryption_type"), + path.MatchRoot("jail_break"), + path.MatchRoot("os_version"), + path.MatchRoot("screenlock_type"), + }...), + }, + }, + "screenlock_type": schema.ListAttribute{ + Description: "List of screenlock type", + Optional: true, + ElementType: types.StringType, + Validators: []validator.List{ + listvalidator.AtLeastOneOf(path.Expressions{ + path.MatchRoot("disk_encryption_type"), + path.MatchRoot("jail_break"), + path.MatchRoot("os_version"), + path.MatchRoot("secure_hardware_present"), + }...), + }, + }, + "third_party_signal_providers": schema.ObjectAttribute{ + Description: "Settings for third-party signal providers. Required for ChromeOS platform, optional for others", + Optional: true, + AttributeTypes: map[string]attr.Type{ + // TODU chromeOS only + "allow_screen_lock": types.BoolType, + "browser_version": types.StringType, + "builtin_dns_client_enabled": types.BoolType, + "chrome_remote_desktop_app_blocked": types.BoolType, + // TODU window only + "crowd_strike_agent_id": types.StringType, + // TODU window only + "crowd_strike_customer_id": types.StringType, + "device_enrollement_domain": types.StringType, + "disk_encrypted": types.BoolType, + "key_trust_level": types.StringType, + "os_firewall": types.BoolType, + "os_version": types.StringType, + "password_proctection_warning_trigger": types.StringType, + "realtime_url_check_mode": types.BoolType, + "safe_browsing_protection_level": types.StringType, + "screen_lock_secured": types.BoolType, + // TODU window only + "secure_boot_enabled": types.BoolType, + "site_isolation_enabled": types.BoolType, + // TODU window only + "third_party_blocking_enabled": types.BoolType, + // TODU window only + "window_machine_domain": types.StringType, + // TODU window only + "window_user_domain": types.StringType, + }, + }, + "created_date": schema.StringAttribute{ + Description: "Created date", + Computed: true, + }, + "created_by": schema.StringAttribute{ + Description: "Created by", + Computed: true, + }, + "last_update": schema.StringAttribute{ + Description: "Last update", + Computed: true, + }, + "last_updated_by": schema.StringAttribute{ + Description: "Last updated by", + Computed: true, + }, + }, + } +} + +// TODU +func (r *policyDeviceAssuranceChromeOSResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var state policyDeviceAssuranceChromeOSResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + // reqBody, err := buildDeviceAssurancePolicyRequest(state) + // if err != nil { + // resp.Diagnostics.AddError( + // "failed to build device assurance request", + // err.Error(), + // ) + // return + // } + reqBody, diag := buildDeviceAssuranceChromeOSPolicyRequest(state) + resp.Diagnostics.Append(diag) + + deviceAssurance, _, err := r.v3Client.DeviceAssuranceApi.CreateDeviceAssurancePolicy(ctx).DeviceAssurance(reqBody).Execute() + if err != nil { + resp.Diagnostics.AddError( + "failed to create device assurance", + err.Error(), + ) + return + } + // TODU need to do additional read? + resp.Diagnostics.Append(mapDeviceAssuranceChromeOSToState(deviceAssurance, state)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } +} + +// TODU +func (r *policyDeviceAssuranceChromeOSResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state policyDeviceAssuranceChromeOSResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + _, err := r.v3Client.DeviceAssuranceApi.DeleteDeviceAssurancePolicy(ctx, state.ID.String()).Execute() + if err != nil { + resp.Diagnostics.AddError( + "failed to delete device assurance", + err.Error(), + ) + return + } +} + +// TODU +func (r *policyDeviceAssuranceChromeOSResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state policyDeviceAssuranceChromeOSResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + deviceAssurance, _, err := r.v3Client.DeviceAssuranceApi.GetDeviceAssurancePolicy(ctx, state.ID.String()).Execute() + if err != nil { + resp.Diagnostics.AddError( + "failed to read device assurance", + err.Error(), + ) + return + } + resp.Diagnostics.Append(mapDeviceAssuranceChromeOSToState(deviceAssurance, state)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } +} + +// TODU +func (r *policyDeviceAssuranceChromeOSResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var state policyDeviceAssuranceChromeOSResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + // reqBody, err := buildDeviceAssurancePolicyRequest(state) + // if err != nil { + // resp.Diagnostics.AddError( + // "failed to build device assurance request", + // err.Error(), + // ) + // return + // } + reqBody, diag := buildDeviceAssuranceChromeOSPolicyRequest(state) + resp.Diagnostics.Append(diag) + + deviceAssurance, _, err := r.v3Client.DeviceAssuranceApi.ReplaceDeviceAssurancePolicy(ctx, state.ID.String()).DeviceAssurance(reqBody).Execute() + if err != nil { + resp.Diagnostics.AddError( + "failed to create device assurance", + err.Error(), + ) + return + } + // TODU need to do additional read? + resp.Diagnostics.Append(mapDeviceAssuranceChromeOSToState(deviceAssurance, state)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } +} + +// TODU +// func buildDeviceAssurancePolicyRequest(model policyDeviceAssuranceResourceModel) (okta.ListDeviceAssurancePolicies200ResponseInner, error) { +// var android = &okta.DeviceAssuranceAndroidPlatform{} +// var iOS = &okta.DeviceAssuranceIOSPlatform{} +// var chromeOS = &okta.DeviceAssuranceChromeOSPlatform{} +// var macOS = &okta.DeviceAssuranceMacOSPlatform{} +// var windows = &okta.DeviceAssuranceWindowsPlatform{} +// switch model.Platform.ValueString() { +// case string(okta.PLATFORM_ANDROID): +// android.SetName(model.Name.ValueString()) +// android.SetPlatform(okta.Platform(model.Platform.ValueString())) +// case string(okta.PLATFORM_IOS): +// iOS.SetName(model.Name.String()) +// iOS.SetPlatform(okta.Platform(model.Platform.String())) +// case string(okta.PLATFORM_CHROMEOS): +// chromeOS.SetName(model.Name.String()) +// chromeOS.SetPlatform(okta.Platform(model.Platform.String())) +// tsp := okta.DeviceAssuranceChromeOSPlatformAllOfThirdPartySignalProviders{} +// tsp.Dtc.SetAllowScreenLock(model.ThirdPartySignalProviders.AllowScreenLock.ValueBool()) +// tsp.Dtc.SetBrowserVersion(okta.ChromeBrowserVersion{Minimum: model.ThirdPartySignalProviders.BrowserVersion.ValueStringPointer()}) +// tsp.Dtc.SetBuiltInDnsClientEnabled(model.ThirdPartySignalProviders.BuiltInDNSClientEnabled.ValueBool()) +// tsp.Dtc.SetChromeRemoteDesktopAppBlocked(model.ThirdPartySignalProviders.ChromeRemoteDesktopAppBlocked.ValueBool()) +// tsp.Dtc.SetDeviceEnrollmentDomain(model.ThirdPartySignalProviders.DeviceEnrollementDomain.ValueString()) +// tsp.Dtc.SetDiskEnrypted(model.ThirdPartySignalProviders.DiskEncrypted.ValueBool()) +// tsp.Dtc.SetKeyTrustLevel(okta.KeyTrustLevelOSMode(model.ThirdPartySignalProviders.KeyTrustLevel.ValueString())) +// tsp.Dtc.SetOsFirewall(model.ThirdPartySignalProviders.OsFirewall.ValueBool()) +// tsp.Dtc.SetOsVersion(okta.OSVersion{Minimum: model.ThirdPartySignalProviders.OsVersion.ValueStringPointer()}) +// tsp.Dtc.SetPasswordProtectionWarningTrigger(okta.PasswordProtectionWarningTrigger(model.ThirdPartySignalProviders.PasswordProctectionWarningTrigger.ValueString())) +// tsp.Dtc.SetRealtimeUrlCheckMode(model.ThirdPartySignalProviders.RealtimeURLCheckMode.ValueBool()) +// tsp.Dtc.SetSafeBrowsingProtectionLevel(okta.SafeBrowsingProtectionLevel(model.ThirdPartySignalProviders.SafeBrowsingProtectionLevel.ValueString())) +// tsp.Dtc.SetScreenLockSecured(model.ThirdPartySignalProviders.ScreenLockSecured.ValueBool()) +// tsp.Dtc.SetSiteIsolationEnabled(model.ThirdPartySignalProviders.SiteIsolationEnabled.ValueBool()) +// chromeOS.SetThirdPartySignalProviders(tsp) +// case string(okta.PLATFORM_MACOS): +// macOS.SetName(model.Name.String()) +// macOS.SetPlatform(okta.Platform(model.Platform.String())) +// case string(okta.PLATFORM_WINDOWS): +// windows.SetName(model.Name.String()) +// windows.SetPlatform(okta.Platform(model.Platform.String())) +// default: +// return okta.ListDeviceAssurancePolicies200ResponseInner{}, errors.New("unidentified platform") +// } +// return okta.ListDeviceAssurancePolicies200ResponseInner{ +// DeviceAssuranceAndroidPlatform: android, +// DeviceAssuranceIOSPlatform: iOS, +// DeviceAssuranceChromeOSPlatform: chromeOS, +// DeviceAssuranceMacOSPlatform: macOS, +// DeviceAssuranceWindowsPlatform: windows, +// }, nil +// } + +func buildDeviceAssuranceChromeOSPolicyRequest(model policyDeviceAssuranceChromeOSResourceModel) (okta.ListDeviceAssurancePolicies200ResponseInner, diag.Diagnostic) { + var android = &okta.DeviceAssuranceAndroidPlatform{} + var iOS = &okta.DeviceAssuranceIOSPlatform{} + var chromeOS = &okta.DeviceAssuranceChromeOSPlatform{} + var macOS = &okta.DeviceAssuranceMacOSPlatform{} + var windows = &okta.DeviceAssuranceWindowsPlatform{} + switch model.Platform.ValueString() { + case string(okta.PLATFORM_ANDROID): + android.SetName(model.Name.ValueString()) + android.SetPlatform(okta.Platform(model.Platform.ValueString())) + case string(okta.PLATFORM_IOS): + iOS.SetName(model.Name.String()) + iOS.SetPlatform(okta.Platform(model.Platform.String())) + case string(okta.PLATFORM_CHROMEOS): + chromeOS.SetName(model.Name.String()) + chromeOS.SetPlatform(okta.Platform(model.Platform.String())) + tsp := okta.DeviceAssuranceChromeOSPlatformAllOfThirdPartySignalProviders{} + tsp.Dtc.SetAllowScreenLock(model.ThirdPartySignalProviders.AllowScreenLock.ValueBool()) + tsp.Dtc.SetBrowserVersion(okta.ChromeBrowserVersion{Minimum: model.ThirdPartySignalProviders.BrowserVersion.ValueStringPointer()}) + tsp.Dtc.SetBuiltInDnsClientEnabled(model.ThirdPartySignalProviders.BuiltInDNSClientEnabled.ValueBool()) + tsp.Dtc.SetChromeRemoteDesktopAppBlocked(model.ThirdPartySignalProviders.ChromeRemoteDesktopAppBlocked.ValueBool()) + tsp.Dtc.SetDeviceEnrollmentDomain(model.ThirdPartySignalProviders.DeviceEnrollementDomain.ValueString()) + tsp.Dtc.SetDiskEnrypted(model.ThirdPartySignalProviders.DiskEncrypted.ValueBool()) + tsp.Dtc.SetKeyTrustLevel(okta.KeyTrustLevelOSMode(model.ThirdPartySignalProviders.KeyTrustLevel.ValueString())) + tsp.Dtc.SetOsFirewall(model.ThirdPartySignalProviders.OsFirewall.ValueBool()) + tsp.Dtc.SetOsVersion(okta.OSVersion{Minimum: model.ThirdPartySignalProviders.OsVersion.ValueStringPointer()}) + tsp.Dtc.SetPasswordProtectionWarningTrigger(okta.PasswordProtectionWarningTrigger(model.ThirdPartySignalProviders.PasswordProctectionWarningTrigger.ValueString())) + tsp.Dtc.SetRealtimeUrlCheckMode(model.ThirdPartySignalProviders.RealtimeURLCheckMode.ValueBool()) + tsp.Dtc.SetSafeBrowsingProtectionLevel(okta.SafeBrowsingProtectionLevel(model.ThirdPartySignalProviders.SafeBrowsingProtectionLevel.ValueString())) + tsp.Dtc.SetScreenLockSecured(model.ThirdPartySignalProviders.ScreenLockSecured.ValueBool()) + tsp.Dtc.SetSiteIsolationEnabled(model.ThirdPartySignalProviders.SiteIsolationEnabled.ValueBool()) + chromeOS.SetThirdPartySignalProviders(tsp) + case string(okta.PLATFORM_MACOS): + macOS.SetName(model.Name.String()) + macOS.SetPlatform(okta.Platform(model.Platform.String())) + case string(okta.PLATFORM_WINDOWS): + windows.SetName(model.Name.String()) + windows.SetPlatform(okta.Platform(model.Platform.String())) + default: + return okta.ListDeviceAssurancePolicies200ResponseInner{}, diag.NewErrorDiagnostic("unidentified platform ", model.Platform.ValueString()) + } + return okta.ListDeviceAssurancePolicies200ResponseInner{ + DeviceAssuranceAndroidPlatform: android, + DeviceAssuranceIOSPlatform: iOS, + DeviceAssuranceChromeOSPlatform: chromeOS, + DeviceAssuranceMacOSPlatform: macOS, + DeviceAssuranceWindowsPlatform: windows, + }, nil +} + +// Map response body to schema +func mapDeviceAssuranceChromeOSToState(data *okta.ListDeviceAssurancePolicies200ResponseInner, state policyDeviceAssuranceChromeOSResourceModel) diag.Diagnostics { + var diags diag.Diagnostics + return diags +} diff --git a/okta/resource_okta_policy_device_assurance_iOS.go b/okta/resource_okta_policy_device_assurance_iOS.go new file mode 100644 index 000000000..9f47470b6 --- /dev/null +++ b/okta/resource_okta_policy_device_assurance_iOS.go @@ -0,0 +1,308 @@ +package okta + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-framework-validators/boolvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/diag" + "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/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/okta/okta-sdk-golang/v3/okta" +) + +// Ensure the implementation satisfies the expected interfaces. +var ( + _ resource.Resource = &policyDeviceAssuranceIOSResource{} + _ resource.ResourceWithConfigure = &policyDeviceAssuranceIOSResource{} + // _ resource.ResourceWithImportState = &policyDeviceAssuranceResource{} +) + +func NewPolicyDeviceAssuranceIOSResource() resource.Resource { + return &policyDeviceAssuranceIOSResource{} +} + +type policyDeviceAssuranceIOSResource struct { + *Config +} + +type policyDeviceAssuranceIOSResourceModel struct { + ID types.String `tfsdk:"id"` + Name types.String `tfsdk:"name"` + Platform types.String `tfsdk:"platform"` + JailBreak types.Bool `tfsdk:"jailbreak"` + OsVersion types.String `tfsdk:"os_version"` + ScreenLockType []types.String `tfsdk:"screenlock_type"` + CreateDate types.String `tfsdk:"created_date"` + CreateBy types.String `tfsdk:"created_by"` + LastUpdate types.String `tfsdk:"last_update"` + LastUpdatedBy types.String `tfsdk:"last_updated_by"` +} + +func (r *policyDeviceAssuranceIOSResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_policy_device_assurance_ios" +} + +func (r *policyDeviceAssuranceIOSResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Manages device assurance on policy", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "Policy assurance id", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "name": schema.StringAttribute{ + Description: "Policy device assurance name", + Required: true, + }, + "platform": schema.StringAttribute{ + Description: "Policy device assurance platform", + Computed: true, + }, + "jailbreak": schema.BoolAttribute{ + Description: "The device jailbreak. Only for android and iOS platform", + Optional: true, + Validators: []validator.Bool{ + boolvalidator.AtLeastOneOf(path.Expressions{ + path.MatchRoot("os_version"), + path.MatchRoot("screenlock_type"), + }...), + }, + }, + "os_version": schema.StringAttribute{ + Description: "The device os minimum version", + Optional: true, + Validators: []validator.String{ + stringvalidator.AtLeastOneOf(path.Expressions{ + path.MatchRoot("jailbreak"), + path.MatchRoot("screenlock_type"), + }...), + }, + }, + "screenlock_type": schema.SetAttribute{ + Description: "List of screenlock type, can be BIOMETRIC and PASSCODE", + Optional: true, + ElementType: types.StringType, + Validators: []validator.Set{ + setvalidator.AtLeastOneOf(path.Expressions{ + path.MatchRoot("jailbreak"), + path.MatchRoot("os_version"), + }...), + }, + }, + "created_date": schema.StringAttribute{ + Description: "Created date", + Computed: true, + }, + "created_by": schema.StringAttribute{ + Description: "Created by", + Computed: true, + }, + "last_update": schema.StringAttribute{ + Description: "Last update", + Computed: true, + }, + "last_updated_by": schema.StringAttribute{ + Description: "Last updated by", + Computed: true, + }, + }, + } +} + +// Configure adds the provider configured client to the resource. +func (r *policyDeviceAssuranceIOSResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + p, 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 = p +} + +func (r *policyDeviceAssuranceIOSResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var state policyDeviceAssuranceIOSResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + reqBody, err := buildDeviceAssuranceIOSPolicyRequest(state) + if err != nil { + resp.Diagnostics.AddError( + "failed to build device assurance request", + err.Error(), + ) + return + } + + deviceAssurance, _, err := r.v3Client.DeviceAssuranceApi.CreateDeviceAssurancePolicy(ctx).DeviceAssurance(reqBody).Execute() + if err != nil { + resp.Diagnostics.AddError( + "failed to create device assurance", + err.Error(), + ) + return + } + + // TODU need to do additional read? + resp.Diagnostics.Append(mapDeviceAssuranceIOSToState(deviceAssurance, &state)...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } +} + +func (r *policyDeviceAssuranceIOSResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state policyDeviceAssuranceIOSResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + deviceAssurance, _, err := r.v3Client.DeviceAssuranceApi.GetDeviceAssurancePolicy(ctx, state.ID.ValueString()).Execute() + if err != nil { + resp.Diagnostics.AddError( + "failed to read device assurance", + err.Error(), + ) + return + } + + resp.Diagnostics.Append(mapDeviceAssuranceIOSToState(deviceAssurance, &state)...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } +} + +func (r *policyDeviceAssuranceIOSResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state policyDeviceAssuranceIOSResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + _, err := r.v3Client.DeviceAssuranceApi.DeleteDeviceAssurancePolicy(ctx, state.ID.ValueString()).Execute() + if err != nil { + resp.Diagnostics.AddError( + "failed to delete device assurance", + err.Error(), + ) + return + } +} + +func (r *policyDeviceAssuranceIOSResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var state policyDeviceAssuranceIOSResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + reqBody, err := buildDeviceAssuranceIOSPolicyRequest(state) + if err != nil { + resp.Diagnostics.AddError( + "failed to build device assurance request", + err.Error(), + ) + return + } + + deviceAssurance, _, err := r.v3Client.DeviceAssuranceApi.ReplaceDeviceAssurancePolicy(ctx, state.ID.ValueString()).DeviceAssurance(reqBody).Execute() + if err != nil { + resp.Diagnostics.AddError( + "failed to create device assurance", + err.Error(), + ) + return + } + + // TODU need to do additional read? + resp.Diagnostics.Append(mapDeviceAssuranceIOSToState(deviceAssurance, &state)...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } +} + +func buildDeviceAssuranceIOSPolicyRequest(model policyDeviceAssuranceIOSResourceModel) (okta.ListDeviceAssurancePolicies200ResponseInner, error) { + var iOS = &okta.DeviceAssuranceIOSPlatform{} + iOS.SetName(model.Name.ValueString()) + iOS.SetPlatform(okta.PLATFORM_IOS) + + iOS.Jailbreak = model.JailBreak.ValueBoolPointer() + if !model.OsVersion.IsNull() { + iOS.OsVersion = &okta.OSVersion{Minimum: model.OsVersion.ValueStringPointer()} + } + if len(model.ScreenLockType) > 0 { + screenlockType := make([]okta.ScreenLockType, 0) + for _, det := range model.ScreenLockType { + v, err := okta.NewScreenLockTypeFromValue(det.ValueString()) + if err != nil { + return okta.ListDeviceAssurancePolicies200ResponseInner{DeviceAssuranceIOSPlatform: iOS}, err + } + screenlockType = append(screenlockType, *v) + } + iOS.ScreenLockType = &okta.DeviceAssuranceAndroidPlatformAllOfScreenLockType{Include: screenlockType} + } + return okta.ListDeviceAssurancePolicies200ResponseInner{DeviceAssuranceIOSPlatform: iOS}, nil +} + +// Map response body to schema +func mapDeviceAssuranceIOSToState(data *okta.ListDeviceAssurancePolicies200ResponseInner, state *policyDeviceAssuranceIOSResourceModel) diag.Diagnostics { + var diags diag.Diagnostics + state.ID = types.StringValue(data.DeviceAssuranceIOSPlatform.GetId()) + state.Name = types.StringValue(data.DeviceAssuranceIOSPlatform.GetName()) + state.Platform = types.StringValue(string(data.DeviceAssuranceIOSPlatform.GetPlatform())) + + if _, ok := data.DeviceAssuranceIOSPlatform.GetJailbreakOk(); ok { + state.JailBreak = types.BoolValue(data.DeviceAssuranceIOSPlatform.GetJailbreak()) + } + if _, ok := data.DeviceAssuranceIOSPlatform.GetOsVersionOk(); ok { + state.OsVersion = types.StringValue(data.DeviceAssuranceIOSPlatform.OsVersion.GetMinimum()) + } + if _, ok := data.DeviceAssuranceIOSPlatform.ScreenLockType.GetIncludeOk(); ok { + screenLockType := make([]types.String, 0) + for _, slt := range data.DeviceAssuranceIOSPlatform.ScreenLockType.GetInclude() { + screenLockType = append(screenLockType, types.StringValue(string(slt))) + } + state.ScreenLockType = screenLockType + } + + state.CreateDate = types.StringValue(string(data.DeviceAssuranceIOSPlatform.GetCreatedDate())) + state.CreateBy = types.StringValue(string(data.DeviceAssuranceIOSPlatform.GetCreatedBy())) + state.LastUpdate = types.StringValue(string(data.DeviceAssuranceIOSPlatform.GetLastUpdate())) + state.LastUpdatedBy = types.StringValue(string(data.DeviceAssuranceIOSPlatform.GetLastUpdatedBy())) + return diags +} diff --git a/okta/resource_okta_policy_device_assurance_iOS_test.go b/okta/resource_okta_policy_device_assurance_iOS_test.go new file mode 100644 index 000000000..3356ea56e --- /dev/null +++ b/okta/resource_okta_policy_device_assurance_iOS_test.go @@ -0,0 +1,45 @@ +package okta + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccPolicyDeviceAssuranceIOS(t *testing.T) { + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: providerConfig + ` + resource okta_policy_device_assurance_ios test{ + name = "test" + os_version = "12.4.5" + jailbreak = false + screenlock_type = toset(["BIOMETRIC"]) + }`, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("okta_policy_device_assurance_ios.test", "name", "test"), + resource.TestCheckResourceAttr("okta_policy_device_assurance_ios.test", "os_version", "12.4.5"), + resource.TestCheckResourceAttr("okta_policy_device_assurance_ios.test", "jailbreak", "false"), + resource.TestCheckResourceAttr("okta_policy_device_assurance_ios.test", "screenlock_type.#", "1"), + ), + }, + { + Config: providerConfig + ` + resource okta_policy_device_assurance_ios test{ + name = "test" + os_version = "12.4.6" + jailbreak = false + screenlock_type = toset(["BIOMETRIC", "PASSCODE"]) + }`, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("okta_policy_device_assurance_ios.test", "name", "test"), + resource.TestCheckResourceAttr("okta_policy_device_assurance_ios.test", "os_version", "12.4.6"), + resource.TestCheckResourceAttr("okta_policy_device_assurance_ios.test", "screenlock_type.#", "2"), + resource.TestCheckResourceAttrSet("okta_policy_device_assurance_ios.test", "jailbreak"), + ), + }, + }, + }) +} diff --git a/okta/resource_okta_policy_device_assurance_macOS.go b/okta/resource_okta_policy_device_assurance_macOS.go new file mode 100644 index 000000000..abb5bcc61 --- /dev/null +++ b/okta/resource_okta_policy_device_assurance_macOS.go @@ -0,0 +1,439 @@ +package okta + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework-validators/boolvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "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/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/okta/okta-sdk-golang/v3/okta" +) + +// Ensure the implementation satisfies the expected interfaces. +var ( + _ resource.Resource = &policyDeviceAssuranceMacOSResource{} + // _ resource.ResourceWithConfigure = &policyDeviceAssuranceResource{} + // _ resource.ResourceWithImportState = &policyDeviceAssuranceResource{} +) + +func NewPolicyDeviceAssuranceMacOSResource() resource.Resource { + return &policyDeviceAssuranceMacOSResource{} +} + +type policyDeviceAssuranceMacOSResource struct { + v3Client *okta.APIClient +} + +type policyDeviceAssuranceMacOSResourceModel struct { + ID types.String `tfsdk:"id"` + Name types.String `tfsdk:"name"` + Platform types.String `tfsdk:"platform"` + DiskEncryptionType types.List `tfsdk:"disk_encryption_type"` + JailBreak types.Bool `tfsdk:"jailbreak"` + OsVersion types.String `tfsdk:"os_version"` + SecureHardwarePresent types.Bool `tfsdk:"secure_hardware_present"` + ScreenLockType types.List `tfsdk:"screenlock_type"` + // TODU + ThirdPartySignalProviders thirdPartySignalProviders `tfsdk:"third_party_signal_providers"` + CreateDate types.String `tfsdk:"created_date"` + CreateBy types.String `tfsdk:"created_by"` + LastUpdate types.String `tfsdk:"last_update"` + LastUpdatedBy types.String `tfsdk:"last_updated_by"` +} + +type thirdPartySignalProviders struct { + AllowScreenLock types.Bool `tfsdk:"allow_screen_lock"` + BrowserVersion types.String `tfsdk:"browser_version, omitempty"` + BuiltInDNSClientEnabled types.Bool `tfsdk:"builtin_dns_client_enabled"` + ChromeRemoteDesktopAppBlocked types.Bool `tfsdk:"chrome_remote_desktop_app_blocked"` + CrowdStrikeAgentID types.String `tfsdk:"crowd_strike_agent_id"` + CrowdStrikeCustomerID types.String `tfsdk:"crowd_strike_customer_id"` + DeviceEnrollementDomain types.String `tfsdk:"device_enrollement_domain"` + DiskEncrypted types.Bool `tfsdk:"disk_encrypted"` + KeyTrustLevel types.String `tfsdk:"key_trust_level"` + OsFirewall types.Bool `tfsdk:"os_firewall"` + OsVersion types.String `tfsdk:"os_version"` + PasswordProctectionWarningTrigger types.String `tfsdk:"password_proctection_warning_trigger"` + RealtimeURLCheckMode types.Bool `tfsdk:"realtime_url_check_mode"` + SafeBrowsingProtectionLevel types.String `tfsdk:"safe_browsing_protection_level"` + ScreenLockSecured types.Bool `tfsdk:"screen_lock_secured"` + SecureBootEnabled types.Bool `tfsdk:"secure_boot_enabled"` + SiteIsolationEnabled types.Bool `tfsdk:"site_isolation_enabled"` + ThirdPartyBlockingEnabled types.Bool `tfsdk:"third_party_blocking_enabled"` + WindowMachineDomain types.String `tfsdk:"window_machine_domain"` + WindowUserDomain types.String `tfsdk:"window_user_domain"` +} + +func (r *policyDeviceAssuranceMacOSResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_policy_device_assurance_macOS" +} + +// TODU different requirement for request and response? +// TODU validation +func (r *policyDeviceAssuranceMacOSResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Manages device assurance on policy", + Attributes: map[string]schema.Attribute{ + // TODU needed? + "id": schema.StringAttribute{ + Description: "Policy assurance id", + Computed: true, + PlanModifiers: []planmodifier.String{ + // TODU + stringplanmodifier.UseStateForUnknown(), + }, + }, + "name": schema.StringAttribute{ + Description: "Policy device assurance name", + Required: true, + }, + "platform": schema.StringAttribute{ + Description: "Policy device assurance platform, can be ANDROID, CHROMEOS, IOS, MACOS or WINDOWS", + Required: true, + }, + "disk_encryption_type": schema.ListAttribute{ + Description: "List of disk encryption type, can be ALL_INTERNAL_VOLUMES, FULL, or USER", + Optional: true, + ElementType: types.StringType, + Validators: []validator.List{ + listvalidator.AtLeastOneOf(path.Expressions{ + path.MatchRoot("jail_break"), + path.MatchRoot("os_version"), + path.MatchRoot("secure_hardware_present"), + path.MatchRoot("screenlock_type"), + }...), + }, + }, + "jail_break": schema.BoolAttribute{ + Description: "The device jailbreak. Only for android and iOS platform", + Optional: true, + Validators: []validator.Bool{ + boolvalidator.AtLeastOneOf(path.Expressions{ + path.MatchRoot("disk_encryption_type"), + path.MatchRoot("os_version"), + path.MatchRoot("secure_hardware_present"), + path.MatchRoot("screenlock_type"), + }...), + }, + }, + "os_version": schema.StringAttribute{ + Description: "The device os version", + Optional: true, + Validators: []validator.String{ + stringvalidator.AtLeastOneOf(path.Expressions{ + path.MatchRoot("disk_encryption_type"), + path.MatchRoot("jail_break"), + path.MatchRoot("secure_hardware_present"), + path.MatchRoot("screenlock_type"), + }...), + }, + }, + "secure_hardware_present": schema.BoolAttribute{ + Description: "Indicates if the device constains a secure hardware functionality", + Optional: true, + Validators: []validator.Bool{ + boolvalidator.AtLeastOneOf(path.Expressions{ + path.MatchRoot("disk_encryption_type"), + path.MatchRoot("jail_break"), + path.MatchRoot("os_version"), + path.MatchRoot("screenlock_type"), + }...), + }, + }, + "screenlock_type": schema.ListAttribute{ + Description: "List of screenlock type", + Optional: true, + ElementType: types.StringType, + Validators: []validator.List{ + listvalidator.AtLeastOneOf(path.Expressions{ + path.MatchRoot("disk_encryption_type"), + path.MatchRoot("jail_break"), + path.MatchRoot("os_version"), + path.MatchRoot("secure_hardware_present"), + }...), + }, + }, + "third_party_signal_providers": schema.ObjectAttribute{ + Description: "Settings for third-party signal providers. Required for ChromeOS platform, optional for others", + Optional: true, + AttributeTypes: map[string]attr.Type{ + // TODU chromeOS only + "allow_screen_lock": types.BoolType, + "browser_version": types.StringType, + "builtin_dns_client_enabled": types.BoolType, + "chrome_remote_desktop_app_blocked": types.BoolType, + // TODU window only + "crowd_strike_agent_id": types.StringType, + // TODU window only + "crowd_strike_customer_id": types.StringType, + "device_enrollement_domain": types.StringType, + "disk_encrypted": types.BoolType, + "key_trust_level": types.StringType, + "os_firewall": types.BoolType, + "os_version": types.StringType, + "password_proctection_warning_trigger": types.StringType, + "realtime_url_check_mode": types.BoolType, + "safe_browsing_protection_level": types.StringType, + "screen_lock_secured": types.BoolType, + // TODU window only + "secure_boot_enabled": types.BoolType, + "site_isolation_enabled": types.BoolType, + // TODU window only + "third_party_blocking_enabled": types.BoolType, + // TODU window only + "window_machine_domain": types.StringType, + // TODU window only + "window_user_domain": types.StringType, + }, + }, + "created_date": schema.StringAttribute{ + Description: "Created date", + Computed: true, + }, + "created_by": schema.StringAttribute{ + Description: "Created by", + Computed: true, + }, + "last_update": schema.StringAttribute{ + Description: "Last update", + Computed: true, + }, + "last_updated_by": schema.StringAttribute{ + Description: "Last updated by", + Computed: true, + }, + }, + } +} + +// TODU +func (r *policyDeviceAssuranceMacOSResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var state policyDeviceAssuranceMacOSResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + // reqBody, err := buildDeviceAssurancePolicyRequest(state) + // if err != nil { + // resp.Diagnostics.AddError( + // "failed to build device assurance request", + // err.Error(), + // ) + // return + // } + reqBody, diag := buildDeviceAssuranceMacOSPolicyRequest(state) + resp.Diagnostics.Append(diag) + + deviceAssurance, _, err := r.v3Client.DeviceAssuranceApi.CreateDeviceAssurancePolicy(ctx).DeviceAssurance(reqBody).Execute() + if err != nil { + resp.Diagnostics.AddError( + "failed to create device assurance", + err.Error(), + ) + return + } + // TODU need to do additional read? + resp.Diagnostics.Append(mapDeviceAssuranceMacOSToState(deviceAssurance, state)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } +} + +// TODU +func (r *policyDeviceAssuranceMacOSResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state policyDeviceAssuranceMacOSResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + _, err := r.v3Client.DeviceAssuranceApi.DeleteDeviceAssurancePolicy(ctx, state.ID.String()).Execute() + if err != nil { + resp.Diagnostics.AddError( + "failed to delete device assurance", + err.Error(), + ) + return + } +} + +// TODU +func (r *policyDeviceAssuranceMacOSResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state policyDeviceAssuranceMacOSResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + deviceAssurance, _, err := r.v3Client.DeviceAssuranceApi.GetDeviceAssurancePolicy(ctx, state.ID.String()).Execute() + if err != nil { + resp.Diagnostics.AddError( + "failed to read device assurance", + err.Error(), + ) + return + } + resp.Diagnostics.Append(mapDeviceAssuranceMacOSToState(deviceAssurance, state)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } +} + +// TODU +func (r *policyDeviceAssuranceMacOSResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var state policyDeviceAssuranceMacOSResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + // reqBody, err := buildDeviceAssurancePolicyRequest(state) + // if err != nil { + // resp.Diagnostics.AddError( + // "failed to build device assurance request", + // err.Error(), + // ) + // return + // } + reqBody, diag := buildDeviceAssuranceMacOSPolicyRequest(state) + resp.Diagnostics.Append(diag) + + deviceAssurance, _, err := r.v3Client.DeviceAssuranceApi.ReplaceDeviceAssurancePolicy(ctx, state.ID.String()).DeviceAssurance(reqBody).Execute() + if err != nil { + resp.Diagnostics.AddError( + "failed to create device assurance", + err.Error(), + ) + return + } + // TODU need to do additional read? + resp.Diagnostics.Append(mapDeviceAssuranceMacOSToState(deviceAssurance, state)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } +} + +// TODU +// func buildDeviceAssurancePolicyRequest(model policyDeviceAssuranceResourceModel) (okta.ListDeviceAssurancePolicies200ResponseInner, error) { +// var android = &okta.DeviceAssuranceAndroidPlatform{} +// var iOS = &okta.DeviceAssuranceIOSPlatform{} +// var chromeOS = &okta.DeviceAssuranceChromeOSPlatform{} +// var macOS = &okta.DeviceAssuranceMacOSPlatform{} +// var windows = &okta.DeviceAssuranceWindowsPlatform{} +// switch model.Platform.ValueString() { +// case string(okta.PLATFORM_ANDROID): +// android.SetName(model.Name.ValueString()) +// android.SetPlatform(okta.Platform(model.Platform.ValueString())) +// case string(okta.PLATFORM_IOS): +// iOS.SetName(model.Name.String()) +// iOS.SetPlatform(okta.Platform(model.Platform.String())) +// case string(okta.PLATFORM_CHROMEOS): +// chromeOS.SetName(model.Name.String()) +// chromeOS.SetPlatform(okta.Platform(model.Platform.String())) +// tsp := okta.DeviceAssuranceChromeOSPlatformAllOfThirdPartySignalProviders{} +// tsp.Dtc.SetAllowScreenLock(model.ThirdPartySignalProviders.AllowScreenLock.ValueBool()) +// tsp.Dtc.SetBrowserVersion(okta.ChromeBrowserVersion{Minimum: model.ThirdPartySignalProviders.BrowserVersion.ValueStringPointer()}) +// tsp.Dtc.SetBuiltInDnsClientEnabled(model.ThirdPartySignalProviders.BuiltInDNSClientEnabled.ValueBool()) +// tsp.Dtc.SetChromeRemoteDesktopAppBlocked(model.ThirdPartySignalProviders.ChromeRemoteDesktopAppBlocked.ValueBool()) +// tsp.Dtc.SetDeviceEnrollmentDomain(model.ThirdPartySignalProviders.DeviceEnrollementDomain.ValueString()) +// tsp.Dtc.SetDiskEnrypted(model.ThirdPartySignalProviders.DiskEncrypted.ValueBool()) +// tsp.Dtc.SetKeyTrustLevel(okta.KeyTrustLevelOSMode(model.ThirdPartySignalProviders.KeyTrustLevel.ValueString())) +// tsp.Dtc.SetOsFirewall(model.ThirdPartySignalProviders.OsFirewall.ValueBool()) +// tsp.Dtc.SetOsVersion(okta.OSVersion{Minimum: model.ThirdPartySignalProviders.OsVersion.ValueStringPointer()}) +// tsp.Dtc.SetPasswordProtectionWarningTrigger(okta.PasswordProtectionWarningTrigger(model.ThirdPartySignalProviders.PasswordProctectionWarningTrigger.ValueString())) +// tsp.Dtc.SetRealtimeUrlCheckMode(model.ThirdPartySignalProviders.RealtimeURLCheckMode.ValueBool()) +// tsp.Dtc.SetSafeBrowsingProtectionLevel(okta.SafeBrowsingProtectionLevel(model.ThirdPartySignalProviders.SafeBrowsingProtectionLevel.ValueString())) +// tsp.Dtc.SetScreenLockSecured(model.ThirdPartySignalProviders.ScreenLockSecured.ValueBool()) +// tsp.Dtc.SetSiteIsolationEnabled(model.ThirdPartySignalProviders.SiteIsolationEnabled.ValueBool()) +// chromeOS.SetThirdPartySignalProviders(tsp) +// case string(okta.PLATFORM_MACOS): +// macOS.SetName(model.Name.String()) +// macOS.SetPlatform(okta.Platform(model.Platform.String())) +// case string(okta.PLATFORM_WINDOWS): +// windows.SetName(model.Name.String()) +// windows.SetPlatform(okta.Platform(model.Platform.String())) +// default: +// return okta.ListDeviceAssurancePolicies200ResponseInner{}, errors.New("unidentified platform") +// } +// return okta.ListDeviceAssurancePolicies200ResponseInner{ +// DeviceAssuranceAndroidPlatform: android, +// DeviceAssuranceIOSPlatform: iOS, +// DeviceAssuranceChromeOSPlatform: chromeOS, +// DeviceAssuranceMacOSPlatform: macOS, +// DeviceAssuranceWindowsPlatform: windows, +// }, nil +// } + +func buildDeviceAssuranceMacOSPolicyRequest(model policyDeviceAssuranceMacOSResourceModel) (okta.ListDeviceAssurancePolicies200ResponseInner, diag.Diagnostic) { + var android = &okta.DeviceAssuranceAndroidPlatform{} + var iOS = &okta.DeviceAssuranceIOSPlatform{} + var chromeOS = &okta.DeviceAssuranceChromeOSPlatform{} + var macOS = &okta.DeviceAssuranceMacOSPlatform{} + var windows = &okta.DeviceAssuranceWindowsPlatform{} + switch model.Platform.ValueString() { + case string(okta.PLATFORM_ANDROID): + android.SetName(model.Name.ValueString()) + android.SetPlatform(okta.Platform(model.Platform.ValueString())) + case string(okta.PLATFORM_IOS): + iOS.SetName(model.Name.String()) + iOS.SetPlatform(okta.Platform(model.Platform.String())) + case string(okta.PLATFORM_CHROMEOS): + chromeOS.SetName(model.Name.String()) + chromeOS.SetPlatform(okta.Platform(model.Platform.String())) + tsp := okta.DeviceAssuranceChromeOSPlatformAllOfThirdPartySignalProviders{} + tsp.Dtc.SetAllowScreenLock(model.ThirdPartySignalProviders.AllowScreenLock.ValueBool()) + tsp.Dtc.SetBrowserVersion(okta.ChromeBrowserVersion{Minimum: model.ThirdPartySignalProviders.BrowserVersion.ValueStringPointer()}) + tsp.Dtc.SetBuiltInDnsClientEnabled(model.ThirdPartySignalProviders.BuiltInDNSClientEnabled.ValueBool()) + tsp.Dtc.SetChromeRemoteDesktopAppBlocked(model.ThirdPartySignalProviders.ChromeRemoteDesktopAppBlocked.ValueBool()) + tsp.Dtc.SetDeviceEnrollmentDomain(model.ThirdPartySignalProviders.DeviceEnrollementDomain.ValueString()) + tsp.Dtc.SetDiskEnrypted(model.ThirdPartySignalProviders.DiskEncrypted.ValueBool()) + tsp.Dtc.SetKeyTrustLevel(okta.KeyTrustLevelOSMode(model.ThirdPartySignalProviders.KeyTrustLevel.ValueString())) + tsp.Dtc.SetOsFirewall(model.ThirdPartySignalProviders.OsFirewall.ValueBool()) + tsp.Dtc.SetOsVersion(okta.OSVersion{Minimum: model.ThirdPartySignalProviders.OsVersion.ValueStringPointer()}) + tsp.Dtc.SetPasswordProtectionWarningTrigger(okta.PasswordProtectionWarningTrigger(model.ThirdPartySignalProviders.PasswordProctectionWarningTrigger.ValueString())) + tsp.Dtc.SetRealtimeUrlCheckMode(model.ThirdPartySignalProviders.RealtimeURLCheckMode.ValueBool()) + tsp.Dtc.SetSafeBrowsingProtectionLevel(okta.SafeBrowsingProtectionLevel(model.ThirdPartySignalProviders.SafeBrowsingProtectionLevel.ValueString())) + tsp.Dtc.SetScreenLockSecured(model.ThirdPartySignalProviders.ScreenLockSecured.ValueBool()) + tsp.Dtc.SetSiteIsolationEnabled(model.ThirdPartySignalProviders.SiteIsolationEnabled.ValueBool()) + chromeOS.SetThirdPartySignalProviders(tsp) + case string(okta.PLATFORM_MACOS): + macOS.SetName(model.Name.String()) + macOS.SetPlatform(okta.Platform(model.Platform.String())) + case string(okta.PLATFORM_WINDOWS): + windows.SetName(model.Name.String()) + windows.SetPlatform(okta.Platform(model.Platform.String())) + default: + return okta.ListDeviceAssurancePolicies200ResponseInner{}, diag.NewErrorDiagnostic("unidentified platform ", model.Platform.ValueString()) + } + return okta.ListDeviceAssurancePolicies200ResponseInner{ + DeviceAssuranceAndroidPlatform: android, + DeviceAssuranceIOSPlatform: iOS, + DeviceAssuranceChromeOSPlatform: chromeOS, + DeviceAssuranceMacOSPlatform: macOS, + DeviceAssuranceWindowsPlatform: windows, + }, nil +} + +// Map response body to schema +func mapDeviceAssuranceMacOSToState(data *okta.ListDeviceAssurancePolicies200ResponseInner, state policyDeviceAssuranceMacOSResourceModel) diag.Diagnostics { + var diags diag.Diagnostics + return diags +} diff --git a/okta/resource_okta_policy_device_assurance_window.go b/okta/resource_okta_policy_device_assurance_window.go new file mode 100644 index 000000000..ca19fac82 --- /dev/null +++ b/okta/resource_okta_policy_device_assurance_window.go @@ -0,0 +1,416 @@ +package okta + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework-validators/boolvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "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/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/okta/okta-sdk-golang/v3/okta" +) + +// Ensure the implementation satisfies the expected interfaces. +var ( + _ resource.Resource = &policyDeviceAssuranceWindowsResource{} + // _ resource.ResourceWithConfigure = &policyDeviceAssuranceResource{} + // _ resource.ResourceWithImportState = &policyDeviceAssuranceResource{} +) + +func NewPolicyDeviceAssuranceWindowsResource() resource.Resource { + return &policyDeviceAssuranceWindowsResource{} +} + +type policyDeviceAssuranceWindowsResource struct { + v3Client *okta.APIClient +} + +type policyDeviceAssuranceWindowsResourceModel struct { + ID types.String `tfsdk:"id"` + Name types.String `tfsdk:"name"` + Platform types.String `tfsdk:"platform"` + DiskEncryptionType types.List `tfsdk:"disk_encryption_type"` + JailBreak types.Bool `tfsdk:"jailbreak"` + OsVersion types.String `tfsdk:"os_version"` + SecureHardwarePresent types.Bool `tfsdk:"secure_hardware_present"` + ScreenLockType types.List `tfsdk:"screenlock_type"` + // TODU + ThirdPartySignalProviders thirdPartySignalProviders `tfsdk:"third_party_signal_providers"` + CreateDate types.String `tfsdk:"created_date"` + CreateBy types.String `tfsdk:"created_by"` + LastUpdate types.String `tfsdk:"last_update"` + LastUpdatedBy types.String `tfsdk:"last_updated_by"` +} + +func (r *policyDeviceAssuranceWindowsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_policy_device_assurance_windows" +} + +// TODU different requirement for request and response? +// TODU validation +func (r *policyDeviceAssuranceWindowsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Manages device assurance on policy", + Attributes: map[string]schema.Attribute{ + // TODU needed? + "id": schema.StringAttribute{ + Description: "Policy assurance id", + Computed: true, + PlanModifiers: []planmodifier.String{ + // TODU + stringplanmodifier.UseStateForUnknown(), + }, + }, + "name": schema.StringAttribute{ + Description: "Policy device assurance name", + Required: true, + }, + "platform": schema.StringAttribute{ + Description: "Policy device assurance platform, can be ANDROID, CHROMEOS, IOS, MACOS or WINDOWS", + Required: true, + }, + "disk_encryption_type": schema.ListAttribute{ + Description: "List of disk encryption type, can be ALL_INTERNAL_VOLUMES, FULL, or USER", + Optional: true, + ElementType: types.StringType, + Validators: []validator.List{ + listvalidator.AtLeastOneOf(path.Expressions{ + path.MatchRoot("jail_break"), + path.MatchRoot("os_version"), + path.MatchRoot("secure_hardware_present"), + path.MatchRoot("screenlock_type"), + }...), + }, + }, + "jail_break": schema.BoolAttribute{ + Description: "The device jailbreak. Only for android and iOS platform", + Optional: true, + Validators: []validator.Bool{ + boolvalidator.AtLeastOneOf(path.Expressions{ + path.MatchRoot("disk_encryption_type"), + path.MatchRoot("os_version"), + path.MatchRoot("secure_hardware_present"), + path.MatchRoot("screenlock_type"), + }...), + }, + }, + "os_version": schema.StringAttribute{ + Description: "The device os version", + Optional: true, + Validators: []validator.String{ + stringvalidator.AtLeastOneOf(path.Expressions{ + path.MatchRoot("disk_encryption_type"), + path.MatchRoot("jail_break"), + path.MatchRoot("secure_hardware_present"), + path.MatchRoot("screenlock_type"), + }...), + }, + }, + "secure_hardware_present": schema.BoolAttribute{ + Description: "Indicates if the device constains a secure hardware functionality", + Optional: true, + Validators: []validator.Bool{ + boolvalidator.AtLeastOneOf(path.Expressions{ + path.MatchRoot("disk_encryption_type"), + path.MatchRoot("jail_break"), + path.MatchRoot("os_version"), + path.MatchRoot("screenlock_type"), + }...), + }, + }, + "screenlock_type": schema.ListAttribute{ + Description: "List of screenlock type", + Optional: true, + ElementType: types.StringType, + Validators: []validator.List{ + listvalidator.AtLeastOneOf(path.Expressions{ + path.MatchRoot("disk_encryption_type"), + path.MatchRoot("jail_break"), + path.MatchRoot("os_version"), + path.MatchRoot("secure_hardware_present"), + }...), + }, + }, + "third_party_signal_providers": schema.ObjectAttribute{ + Description: "Settings for third-party signal providers. Required for ChromeOS platform, optional for others", + Optional: true, + AttributeTypes: map[string]attr.Type{ + // TODU chromeOS only + "allow_screen_lock": types.BoolType, + "browser_version": types.StringType, + "builtin_dns_client_enabled": types.BoolType, + "chrome_remote_desktop_app_blocked": types.BoolType, + // TODU window only + "crowd_strike_agent_id": types.StringType, + // TODU window only + "crowd_strike_customer_id": types.StringType, + "device_enrollement_domain": types.StringType, + "disk_encrypted": types.BoolType, + "key_trust_level": types.StringType, + "os_firewall": types.BoolType, + "os_version": types.StringType, + "password_proctection_warning_trigger": types.StringType, + "realtime_url_check_mode": types.BoolType, + "safe_browsing_protection_level": types.StringType, + "screen_lock_secured": types.BoolType, + // TODU window only + "secure_boot_enabled": types.BoolType, + "site_isolation_enabled": types.BoolType, + // TODU window only + "third_party_blocking_enabled": types.BoolType, + // TODU window only + "window_machine_domain": types.StringType, + // TODU window only + "window_user_domain": types.StringType, + }, + }, + "created_date": schema.StringAttribute{ + Description: "Created date", + Computed: true, + }, + "created_by": schema.StringAttribute{ + Description: "Created by", + Computed: true, + }, + "last_update": schema.StringAttribute{ + Description: "Last update", + Computed: true, + }, + "last_updated_by": schema.StringAttribute{ + Description: "Last updated by", + Computed: true, + }, + }, + } +} + +// TODU +func (r *policyDeviceAssuranceWindowsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var state policyDeviceAssuranceWindowsResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + // reqBody, err := buildDeviceAssurancePolicyRequest(state) + // if err != nil { + // resp.Diagnostics.AddError( + // "failed to build device assurance request", + // err.Error(), + // ) + // return + // } + reqBody, diag := buildDeviceAssuranceWindowsPolicyRequest(state) + resp.Diagnostics.Append(diag) + + deviceAssurance, _, err := r.v3Client.DeviceAssuranceApi.CreateDeviceAssurancePolicy(ctx).DeviceAssurance(reqBody).Execute() + if err != nil { + resp.Diagnostics.AddError( + "failed to create device assurance", + err.Error(), + ) + return + } + // TODU need to do additional read? + resp.Diagnostics.Append(mapDeviceAssuranceWindowsToState(deviceAssurance, state)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } +} + +// TODU +func (r *policyDeviceAssuranceWindowsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state policyDeviceAssuranceWindowsResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + _, err := r.v3Client.DeviceAssuranceApi.DeleteDeviceAssurancePolicy(ctx, state.ID.String()).Execute() + if err != nil { + resp.Diagnostics.AddError( + "failed to delete device assurance", + err.Error(), + ) + return + } +} + +// TODU +func (r *policyDeviceAssuranceWindowsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state policyDeviceAssuranceWindowsResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + deviceAssurance, _, err := r.v3Client.DeviceAssuranceApi.GetDeviceAssurancePolicy(ctx, state.ID.String()).Execute() + if err != nil { + resp.Diagnostics.AddError( + "failed to read device assurance", + err.Error(), + ) + return + } + resp.Diagnostics.Append(mapDeviceAssuranceWindowsToState(deviceAssurance, state)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } +} + +// TODU +func (r *policyDeviceAssuranceWindowsResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var state policyDeviceAssuranceWindowsResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + // reqBody, err := buildDeviceAssurancePolicyRequest(state) + // if err != nil { + // resp.Diagnostics.AddError( + // "failed to build device assurance request", + // err.Error(), + // ) + // return + // } + reqBody, diag := buildDeviceAssuranceWindowsPolicyRequest(state) + resp.Diagnostics.Append(diag) + + deviceAssurance, _, err := r.v3Client.DeviceAssuranceApi.ReplaceDeviceAssurancePolicy(ctx, state.ID.String()).DeviceAssurance(reqBody).Execute() + if err != nil { + resp.Diagnostics.AddError( + "failed to create device assurance", + err.Error(), + ) + return + } + // TODU need to do additional read? + resp.Diagnostics.Append(mapDeviceAssuranceWindowsToState(deviceAssurance, state)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } +} + +// TODU +// func buildDeviceAssurancePolicyRequest(model policyDeviceAssuranceResourceModel) (okta.ListDeviceAssurancePolicies200ResponseInner, error) { +// var android = &okta.DeviceAssuranceAndroidPlatform{} +// var iOS = &okta.DeviceAssuranceIOSPlatform{} +// var chromeOS = &okta.DeviceAssuranceChromeOSPlatform{} +// var macOS = &okta.DeviceAssuranceMacOSPlatform{} +// var windows = &okta.DeviceAssuranceWindowsPlatform{} +// switch model.Platform.ValueString() { +// case string(okta.PLATFORM_ANDROID): +// android.SetName(model.Name.ValueString()) +// android.SetPlatform(okta.Platform(model.Platform.ValueString())) +// case string(okta.PLATFORM_IOS): +// iOS.SetName(model.Name.String()) +// iOS.SetPlatform(okta.Platform(model.Platform.String())) +// case string(okta.PLATFORM_CHROMEOS): +// chromeOS.SetName(model.Name.String()) +// chromeOS.SetPlatform(okta.Platform(model.Platform.String())) +// tsp := okta.DeviceAssuranceChromeOSPlatformAllOfThirdPartySignalProviders{} +// tsp.Dtc.SetAllowScreenLock(model.ThirdPartySignalProviders.AllowScreenLock.ValueBool()) +// tsp.Dtc.SetBrowserVersion(okta.ChromeBrowserVersion{Minimum: model.ThirdPartySignalProviders.BrowserVersion.ValueStringPointer()}) +// tsp.Dtc.SetBuiltInDnsClientEnabled(model.ThirdPartySignalProviders.BuiltInDNSClientEnabled.ValueBool()) +// tsp.Dtc.SetChromeRemoteDesktopAppBlocked(model.ThirdPartySignalProviders.ChromeRemoteDesktopAppBlocked.ValueBool()) +// tsp.Dtc.SetDeviceEnrollmentDomain(model.ThirdPartySignalProviders.DeviceEnrollementDomain.ValueString()) +// tsp.Dtc.SetDiskEnrypted(model.ThirdPartySignalProviders.DiskEncrypted.ValueBool()) +// tsp.Dtc.SetKeyTrustLevel(okta.KeyTrustLevelOSMode(model.ThirdPartySignalProviders.KeyTrustLevel.ValueString())) +// tsp.Dtc.SetOsFirewall(model.ThirdPartySignalProviders.OsFirewall.ValueBool()) +// tsp.Dtc.SetOsVersion(okta.OSVersion{Minimum: model.ThirdPartySignalProviders.OsVersion.ValueStringPointer()}) +// tsp.Dtc.SetPasswordProtectionWarningTrigger(okta.PasswordProtectionWarningTrigger(model.ThirdPartySignalProviders.PasswordProctectionWarningTrigger.ValueString())) +// tsp.Dtc.SetRealtimeUrlCheckMode(model.ThirdPartySignalProviders.RealtimeURLCheckMode.ValueBool()) +// tsp.Dtc.SetSafeBrowsingProtectionLevel(okta.SafeBrowsingProtectionLevel(model.ThirdPartySignalProviders.SafeBrowsingProtectionLevel.ValueString())) +// tsp.Dtc.SetScreenLockSecured(model.ThirdPartySignalProviders.ScreenLockSecured.ValueBool()) +// tsp.Dtc.SetSiteIsolationEnabled(model.ThirdPartySignalProviders.SiteIsolationEnabled.ValueBool()) +// chromeOS.SetThirdPartySignalProviders(tsp) +// case string(okta.PLATFORM_MACOS): +// macOS.SetName(model.Name.String()) +// macOS.SetPlatform(okta.Platform(model.Platform.String())) +// case string(okta.PLATFORM_WINDOWS): +// windows.SetName(model.Name.String()) +// windows.SetPlatform(okta.Platform(model.Platform.String())) +// default: +// return okta.ListDeviceAssurancePolicies200ResponseInner{}, errors.New("unidentified platform") +// } +// return okta.ListDeviceAssurancePolicies200ResponseInner{ +// DeviceAssuranceAndroidPlatform: android, +// DeviceAssuranceIOSPlatform: iOS, +// DeviceAssuranceChromeOSPlatform: chromeOS, +// DeviceAssuranceMacOSPlatform: macOS, +// DeviceAssuranceWindowsPlatform: windows, +// }, nil +// } + +func buildDeviceAssuranceWindowsPolicyRequest(model policyDeviceAssuranceWindowsResourceModel) (okta.ListDeviceAssurancePolicies200ResponseInner, diag.Diagnostic) { + var android = &okta.DeviceAssuranceAndroidPlatform{} + var iOS = &okta.DeviceAssuranceIOSPlatform{} + var chromeOS = &okta.DeviceAssuranceChromeOSPlatform{} + var macOS = &okta.DeviceAssuranceMacOSPlatform{} + var windows = &okta.DeviceAssuranceWindowsPlatform{} + switch model.Platform.ValueString() { + case string(okta.PLATFORM_ANDROID): + android.SetName(model.Name.ValueString()) + android.SetPlatform(okta.Platform(model.Platform.ValueString())) + case string(okta.PLATFORM_IOS): + iOS.SetName(model.Name.String()) + iOS.SetPlatform(okta.Platform(model.Platform.String())) + case string(okta.PLATFORM_CHROMEOS): + chromeOS.SetName(model.Name.String()) + chromeOS.SetPlatform(okta.Platform(model.Platform.String())) + tsp := okta.DeviceAssuranceChromeOSPlatformAllOfThirdPartySignalProviders{} + tsp.Dtc.SetAllowScreenLock(model.ThirdPartySignalProviders.AllowScreenLock.ValueBool()) + tsp.Dtc.SetBrowserVersion(okta.ChromeBrowserVersion{Minimum: model.ThirdPartySignalProviders.BrowserVersion.ValueStringPointer()}) + tsp.Dtc.SetBuiltInDnsClientEnabled(model.ThirdPartySignalProviders.BuiltInDNSClientEnabled.ValueBool()) + tsp.Dtc.SetChromeRemoteDesktopAppBlocked(model.ThirdPartySignalProviders.ChromeRemoteDesktopAppBlocked.ValueBool()) + tsp.Dtc.SetDeviceEnrollmentDomain(model.ThirdPartySignalProviders.DeviceEnrollementDomain.ValueString()) + tsp.Dtc.SetDiskEnrypted(model.ThirdPartySignalProviders.DiskEncrypted.ValueBool()) + tsp.Dtc.SetKeyTrustLevel(okta.KeyTrustLevelOSMode(model.ThirdPartySignalProviders.KeyTrustLevel.ValueString())) + tsp.Dtc.SetOsFirewall(model.ThirdPartySignalProviders.OsFirewall.ValueBool()) + tsp.Dtc.SetOsVersion(okta.OSVersion{Minimum: model.ThirdPartySignalProviders.OsVersion.ValueStringPointer()}) + tsp.Dtc.SetPasswordProtectionWarningTrigger(okta.PasswordProtectionWarningTrigger(model.ThirdPartySignalProviders.PasswordProctectionWarningTrigger.ValueString())) + tsp.Dtc.SetRealtimeUrlCheckMode(model.ThirdPartySignalProviders.RealtimeURLCheckMode.ValueBool()) + tsp.Dtc.SetSafeBrowsingProtectionLevel(okta.SafeBrowsingProtectionLevel(model.ThirdPartySignalProviders.SafeBrowsingProtectionLevel.ValueString())) + tsp.Dtc.SetScreenLockSecured(model.ThirdPartySignalProviders.ScreenLockSecured.ValueBool()) + tsp.Dtc.SetSiteIsolationEnabled(model.ThirdPartySignalProviders.SiteIsolationEnabled.ValueBool()) + chromeOS.SetThirdPartySignalProviders(tsp) + case string(okta.PLATFORM_MACOS): + macOS.SetName(model.Name.String()) + macOS.SetPlatform(okta.Platform(model.Platform.String())) + case string(okta.PLATFORM_WINDOWS): + windows.SetName(model.Name.String()) + windows.SetPlatform(okta.Platform(model.Platform.String())) + default: + return okta.ListDeviceAssurancePolicies200ResponseInner{}, diag.NewErrorDiagnostic("unidentified platform ", model.Platform.ValueString()) + } + return okta.ListDeviceAssurancePolicies200ResponseInner{ + DeviceAssuranceAndroidPlatform: android, + DeviceAssuranceIOSPlatform: iOS, + DeviceAssuranceChromeOSPlatform: chromeOS, + DeviceAssuranceMacOSPlatform: macOS, + DeviceAssuranceWindowsPlatform: windows, + }, nil +} + +// Map response body to schema +func mapDeviceAssuranceWindowsToState(data *okta.ListDeviceAssurancePolicies200ResponseInner, state policyDeviceAssuranceWindowsResourceModel) diag.Diagnostics { + var diags diag.Diagnostics + return diags +}