Skip to content

Commit

Permalink
Merge pull request #185 from jfrog/GH-183-add-httpsso-settings-resource
Browse files Browse the repository at this point in the history
Add platform_http_sso_settings resource
  • Loading branch information
alexhung authored Dec 20, 2024
2 parents 6fa618c + 8cb9983 commit 93552d9
Show file tree
Hide file tree
Showing 9 changed files with 393 additions and 171 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 2.1.0 (December 20, 2024). Tested on Artifactory 7.98.11 with Terraform 1.10.3 and OpenTofu 1.8.7

FEATURES:

**New Resource:**

* `platform_http_sso_settings` - Resource to manage HTTP SSO settings. PR: [#185](https://github.com/jfrog/terraform-provider-platform/pull/185)

## 2.0.0 (December 18, 2024). Tested on Artifactory 7.98.11 with Terraform 1.10.2 and OpenTofu 1.8.7

NOTES:
Expand Down
45 changes: 45 additions & 0 deletions docs/resources/http_sso_settings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "platform_http_sso_settings Resource - terraform-provider-platform"
subcategory: ""
description: |-
Provides a JFrog HTTP SSO Settings https://jfrog.com/help/r/jfrog-platform-administration-documentation/http-sso resource. This allows you to reuse existing HTTP-based SSO infrastructures with the JFrog Platform Unit (JPD), such as the SSO modules offered by Apache HTTPd.
---

# platform_http_sso_settings (Resource)

Provides a JFrog [HTTP SSO Settings](https://jfrog.com/help/r/jfrog-platform-administration-documentation/http-sso) resource. This allows you to reuse existing HTTP-based SSO infrastructures with the JFrog Platform Unit (JPD), such as the SSO modules offered by Apache HTTPd.

## Example Usage

```terraform
resource "platform_http_sso_settings" "my-http-sso-settings" {
proxied = true
auto_create_user = true
allow_user_to_access_profile = true
remote_user_request_variable = "MY_REMOTE_USER"
sync_ldap_groups = false
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `proxied` (Boolean) When set, Artifactory trusts incoming requests and reuses the remote user originally set on the request by the SSO of the HTTP server. This is useful if you want to use existing enterprise SSO integrations, such as the powerful authentication schemes provided by Apache (mod_auth_ldap, mod_auth_ntlm, mod_auth_kerb, etc.). When Artifactory is deployed as a webapp on Tomcat behind Apache: If using mod_jk, be sure to use the `JkEnvVar REMOTE_USER` directive in Apache's configuration.

### Optional

- `allow_user_to_access_profile` (Boolean) Auto created users will have access to their profile page and will be able to perform actions such as generating an API key. Default to `false`.
- `auto_create_user` (Boolean) When set, authenticated users are automatically created in Artifactory. When not set, for every request from an SSO user, the user is temporarily associated with default groups (if such groups are defined), and the permissions for these groups apply. Without automatic user creation, you must manually create the user inside Artifactory to manage user permissions not attached to their default groups. Default to `false`.
- `remote_user_request_variable` (String) The name of the HTTP request variable to use for extracting the user identity. Default to `REMOTE_USER`.
- `sync_ldap_groups` (Boolean) When set, the user will be associated with the groups returned in the LDAP login response. Note that the user's association with the returned groups is persistent if the `auto_create_user` is set. Default to `false`.

## Import

Import is supported using the following syntax:

```shell
terraform import platform_http_sso_settings.my-http-sso-settings my-http-sso-settings
```
1 change: 1 addition & 0 deletions examples/resources/platform_http_sso_settings/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
terraform import platform_http_sso_settings.my-http-sso-settings my-http-sso-settings
7 changes: 7 additions & 0 deletions examples/resources/platform_http_sso_settings/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
resource "platform_http_sso_settings" "my-http-sso-settings" {
proxied = true
auto_create_user = true
allow_user_to_access_profile = true
remote_user_request_variable = "MY_REMOTE_USER"
sync_ldap_groups = false
}
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ require (
github.com/hashicorp/terraform-plugin-framework-validators v0.16.0
github.com/hashicorp/terraform-plugin-go v0.25.0
github.com/hashicorp/terraform-plugin-testing v1.11.0
github.com/jfrog/terraform-provider-shared v1.27.1
github.com/jfrog/terraform-provider-shared v1.28.0
github.com/samber/lo v1.47.0
)

Expand Down Expand Up @@ -84,7 +84,7 @@ require (
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819 // indirect
golang.org/x/mod v0.21.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/tools v0.22.0 // indirect
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jfrog/terraform-provider-shared v1.27.1 h1:uVp3RN/H3mZm6f9mw917ZjOPLELfb7Zv3I1YrKjC9BI=
github.com/jfrog/terraform-provider-shared v1.27.1/go.mod h1:6J2ITGCAs6hAuFClSDeXHz0sJEIElDIMu4A/+WB1zvs=
github.com/jfrog/terraform-provider-shared v1.28.0 h1:WKsqc13p0RdaR4yjzr2T4OEtAvGpR62hTpnUAV1Obh4=
github.com/jfrog/terraform-provider-shared v1.28.0/go.mod h1:0snzhXJR++SKRxpCtZnIFEIeP/Ud5zuF3Lm6OZncb4k=
github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
Expand Down Expand Up @@ -230,8 +230,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand Down
175 changes: 10 additions & 165 deletions pkg/platform/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,152 +2,32 @@ package platform

import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"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"
"github.com/jfrog/terraform-provider-shared/client"
"github.com/jfrog/terraform-provider-shared/util"
validator_string "github.com/jfrog/terraform-provider-shared/validator/fw/string"
)

var Version = "2.0.0"

// needs to be exported so make file can update this
var productId = "terraform-provider-platform/" + Version
var Version = "2.0.0"

var _ provider.Provider = (*PlatformProvider)(nil)
var _ provider.Provider = &PlatformProvider{}

type PlatformProvider struct {
Meta util.ProviderMetadata
}

type platformProviderModel struct {
Url types.String `tfsdk:"url"`
AccessToken types.String `tfsdk:"access_token"`
OIDCProviderName types.String `tfsdk:"oidc_provider_name"`
TFCCredentialTagName types.String `tfsdk:"tfc_credential_tag_name"`
util.JFrogProvider
}

func NewProvider() func() provider.Provider {
return func() provider.Provider {
return &PlatformProvider{}
}
}

func (p *PlatformProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
// Check environment variables, first available OS variable will be assigned to the var
url := util.CheckEnvVars([]string{"JFROG_URL"}, "")
accessToken := util.CheckEnvVars([]string{"JFROG_ACCESS_TOKEN"}, "")

var config platformProviderModel

// Read configuration data into model
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
if resp.Diagnostics.HasError() {
return
}

if config.Url.ValueString() != "" {
url = config.Url.ValueString()
}

if url == "" {
resp.Diagnostics.AddError(
"Missing URL Configuration",
"While configuring the provider, the url was not found in the JFROG_URL environment variable or provider configuration block url attribute.",
)
return
}

restyClient, err := client.Build(url, productId)
if err != nil {
resp.Diagnostics.AddError(
"Error creating Resty client",
err.Error(),
)
return
}

oidcProviderName := config.OIDCProviderName.ValueString()
if oidcProviderName != "" {
oidcAccessToken, err := util.OIDCTokenExchange(ctx, restyClient, oidcProviderName, config.TFCCredentialTagName.ValueString())
if err != nil {
resp.Diagnostics.AddError(
"Failed OIDC ID token exchange",
err.Error(),
)
return
}

// use token from OIDC provider, which should take precedence over
// environment variable data, if found.
if oidcAccessToken != "" {
accessToken = oidcAccessToken
}
}

// use token from configuration, which should take precedence over
// environment variable data or OIDC provider, if found.
if config.AccessToken.ValueString() != "" {
accessToken = config.AccessToken.ValueString()
}

if accessToken == "" {
resp.Diagnostics.AddWarning(
"Missing JFrog Access Token",
"Access Token was not found in the JFROG_ACCESS_TOKEN environment variable, provider configuration block access_token attribute, or Terraform Cloud TFC_WORKLOAD_IDENTITY_TOKEN environment variable. Platform functionality will be affected.",
)
}

artifactoryVersion := ""
if len(accessToken) > 0 {
_, err = client.AddAuth(restyClient, "", accessToken)
if err != nil {
resp.Diagnostics.AddError(
"Error adding Auth to Resty client",
err.Error(),
)
return
}

version, err := util.GetArtifactoryVersion(restyClient)
if err != nil {
resp.Diagnostics.AddWarning(
"Error getting Artifactory version",
fmt.Sprintf("Provider functionality might be affected by the absence of Artifactory version. %v", err),
)
return &PlatformProvider{
JFrogProvider: util.JFrogProvider{
TypeName: "platform",
ProductID: "terraform-provider-platform/" + Version,
Version: Version,
},
}

artifactoryVersion = version

featureUsage := fmt.Sprintf("Terraform/%s", req.TerraformVersion)
go util.SendUsage(ctx, restyClient.R(), productId, featureUsage)
}

featureUsage := fmt.Sprintf("Terraform/%s", req.TerraformVersion)
go util.SendUsage(ctx, restyClient.R(), productId, featureUsage)

meta := util.ProviderMetadata{
Client: restyClient,
ArtifactoryVersion: artifactoryVersion,
ProductId: productId,
}

p.Meta = meta

resp.DataSourceData = meta
resp.ResourceData = meta
}

func (p *PlatformProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
resp.TypeName = "platform"
resp.Version = Version
}

func (p *PlatformProvider) DataSources(ctx context.Context) []func() datasource.DataSource {
Expand All @@ -163,6 +43,7 @@ func (p *PlatformProvider) Resources(ctx context.Context) []func() resource.Reso
NewLicenseResource,
NewGlobalRoleResource,
NewGroupResource,
NewHTTPSSOSettingsResource,
NewOIDCConfigurationResource,
NewOIDCIdentityMappingResource,
NewMyJFrogIPAllowListResource,
Expand All @@ -174,39 +55,3 @@ func (p *PlatformProvider) Resources(ctx context.Context) []func() resource.Reso
NewWorkerServiceResource,
}
}

func (p *PlatformProvider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"url": schema.StringAttribute{
Optional: true,
Validators: []validator.String{
validator_string.IsURLHttpOrHttps(),
},
MarkdownDescription: "JFrog Platform URL. This can also be sourced from the `JFROG_URL` environment variable.",
},
"access_token": schema.StringAttribute{
Optional: true,
Sensitive: true,
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
},
MarkdownDescription: "This is a access token that can be given to you by your admin under `Platform Configuration -> User Management -> Access Tokens`. This can also be sourced from the `JFROG_ACCESS_TOKEN` environment variable.",
},
"oidc_provider_name": schema.StringAttribute{
Optional: true,
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
},
MarkdownDescription: "OIDC provider name. See [Configure an OIDC Integration](https://jfrog.com/help/r/jfrog-platform-administration-documentation/configure-an-oidc-integration) for more details.",
},
"tfc_credential_tag_name": schema.StringAttribute{
Optional: true,
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
},
Description: "Terraform Cloud Workload Identity Token tag name. Use for generating multiple TFC workload identity tokens. When set, the provider will attempt to use env var with this tag name as suffix. **Note:** this is case sensitive, so if set to `JFROG`, then env var `TFC_WORKLOAD_IDENTITY_TOKEN_JFROG` is used instead of `TFC_WORKLOAD_IDENTITY_TOKEN`. See [Generating Multiple Tokens](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/dynamic-provider-credentials/manual-generation#generating-multiple-tokens) on HCP Terraform for more details.",
},
},
}
}
Loading

0 comments on commit 93552d9

Please sign in to comment.