Skip to content

Commit

Permalink
[zitadel#205] Add idp_oidc
Browse files Browse the repository at this point in the history
  • Loading branch information
James Stocker committed Dec 3, 2024
1 parent ed5345e commit c34a49b
Show file tree
Hide file tree
Showing 13 changed files with 319 additions and 1 deletion.
57 changes: 57 additions & 0 deletions docs/resources/idp_oidc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
page_title: "zitadel_idp_oidc Resource - terraform-provider-zitadel"
subcategory: ""
description: |-
Resource representing a generic OIDC IdP on the instance.
---

# zitadel_org_idp_oidc (Resource)

Resource representing a generic OIDC IdP on the organization.

## Example Usage

```terraform
resource "zitadel_idp_oidc" "default" {
name = "My Generic OIDC IDP"
client_id = "a_client_id"
client_secret = "a_client_secret"
scopes = ["openid", "profile", "email"]
issuer = "https://example.com"
is_linking_allowed = false
is_creation_allowed = true
is_auto_creation = false
is_auto_update = true
is_id_token_mapping = true
}
```

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

### Required

- `client_id` (String) client id generated by the identity provider
- `client_secret` (String, Sensitive) client secret generated by the identity provider
- `is_auto_creation` (Boolean) enable if a new account in ZITADEL should be created automatically on login with an external account
- `is_auto_update` (Boolean) enable if a the ZITADEL account fields should be updated automatically on each login
- `is_creation_allowed` (Boolean) enable if users should be able to create a new account in ZITADEL when using an external account
- `is_id_token_mapping` (Boolean) if true, provider information get mapped from the id token, not from the userinfo endpoint
- `is_linking_allowed` (Boolean) enable if users should be able to link an existing ZITADEL user with an external account
- `issuer` (String) the issuer of the idp

### Optional

- `name` (String) Name of the IDP
- `scopes` (Set of String) the scopes requested by ZITADEL during the request on the identity provider

### Read-Only

- `id` (String) The ID of this resource.

## Import

```bash
# The resource can be imported using the ID format `<id[:client_secret]>`, e.g.
terraform import zitadel_idp_oidc.imported '123456789012345678:1234567890abcdef'
```
3 changes: 3 additions & 0 deletions examples/provider/data-sources/idp_oidc.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
data "zitadel_idp_oidc" "default" {
id = "123456789012345678"
}
2 changes: 2 additions & 0 deletions examples/provider/resources/idp_oidc-import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# The resource can be imported using the ID format `<id[:client_secret]>`, e.g.
terraform import zitadel_idp_oidc.imported '123456789012345678:1234567890abcdef'
12 changes: 12 additions & 0 deletions examples/provider/resources/idp_oidc.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
resource "zitadel_idp_oidc" "default" {
name = "My Generic OIDC IDP"
client_id = "a_client_id"
client_secret = "a_client_secret"
scopes = ["openid", "profile", "email"]
issuer = "https://example.com"
is_linking_allowed = false
is_creation_allowed = true
is_auto_creation = false
is_auto_update = true
is_id_token_mapping = true
}
2 changes: 1 addition & 1 deletion examples/provider/resources/org_idp_oidc-import.sh
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# The resource can be imported using the ID format `<id[:org_id][:client_secret]>`, e.g.
terraform import zitadel_org_idp_oidc.imported '123456789012345678:123456789012345678:1234567890abcdef'
terraform import zitadel_idp_oidc.imported '123456789012345678:123456789012345678:1234567890abcdef'
16 changes: 16 additions & 0 deletions templates/data-sources/idp_oidc.md.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}"
subcategory: ""
description: |-
{{ .Description | plainmarkdown | trimspace | prefixlines " " }}
---

# {{.Name}} ({{.Type}})

{{ .Description | trimspace }}

## Example Usage

{{ tffile "examples/provider/data-sources/idp_oidc.tf" }}

{{ .SchemaMarkdown | trimspace }}
20 changes: 20 additions & 0 deletions templates/resources/idp_oidc.md.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}"
subcategory: ""
description: |-
{{ .Description | plainmarkdown | trimspace | prefixlines " " }}
---

# {{.Name}} ({{.Type}})

{{ .Description | trimspace }}

## Example Usage

{{ tffile "examples/provider/resources/idp_oidc.tf" }}

{{ .SchemaMarkdown | trimspace }}

## Import

{{ codefile "bash" "examples/provider/resources/idp_oidc-import.sh" }}
27 changes: 27 additions & 0 deletions zitadel/idp_oidc/datasource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package idp_oidc

import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

"github.com/zitadel/terraform-provider-zitadel/v2/zitadel/idp_utils"
)

func GetDatasource() *schema.Resource {
return &schema.Resource{
Description: "Datasource representing a generic OIDC IdP on the instance.",
Schema: map[string]*schema.Schema{
idp_utils.IdpIDVar: idp_utils.IdPIDDataSourceField,
idp_utils.NameVar: idp_utils.NameDataSourceField,
idp_utils.ClientIDVar: idp_utils.ClientIDDataSourceField,
idp_utils.ClientSecretVar: idp_utils.ClientSecretDataSourceField,
idp_utils.ScopesVar: idp_utils.ScopesDataSourceField,
idp_utils.IsLinkingAllowedVar: idp_utils.IsLinkingAllowedDataSourceField,
idp_utils.IsCreationAllowedVar: idp_utils.IsCreationAllowedDataSourceField,
idp_utils.IsAutoCreationVar: idp_utils.IsAutoCreationDataSourceField,
idp_utils.IsAutoUpdateVar: idp_utils.IsAutoUpdateDataSourceField,
IssuerVar: IssuerDatasourceField,
IsIdTokenMappingVar: IsIdTokenMappingDatasourceField,
},
ReadContext: read,
}
}
106 changes: 106 additions & 0 deletions zitadel/idp_oidc/funcs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package idp_oidc

import (
"context"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/admin"
"github.com/zitadel/zitadel-go/v3/pkg/client/zitadel/idp"

"github.com/zitadel/terraform-provider-zitadel/v2/zitadel/helper"
"github.com/zitadel/terraform-provider-zitadel/v2/zitadel/idp_utils"
)

func create(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
clientinfo, ok := m.(*helper.ClientInfo)
if !ok {
return diag.Errorf("failed to get client")
}
client, err := helper.GetAdminClient(ctx, clientinfo)
if err != nil {
return diag.FromErr(err)
}
resp, err := client.AddGenericOIDCProvider(ctx, &admin.AddGenericOIDCProviderRequest{
Name: idp_utils.StringValue(d, idp_utils.NameVar),
ClientId: idp_utils.StringValue(d, idp_utils.ClientIDVar),
ClientSecret: idp_utils.StringValue(d, idp_utils.ClientSecretVar),
Scopes: idp_utils.ScopesValue(d),
ProviderOptions: idp_utils.ProviderOptionsValue(d),
Issuer: idp_utils.StringValue(d, IssuerVar),
IsIdTokenMapping: idp_utils.BoolValue(d, IsIdTokenMappingVar),
})
if err != nil {
return diag.Errorf("failed to create idp: %v", err)
}
d.SetId(resp.GetId())
return nil
}

func update(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
clientinfo, ok := m.(*helper.ClientInfo)
if !ok {
return diag.Errorf("failed to get client")
}
client, err := helper.GetAdminClient(ctx, clientinfo)
if err != nil {
return diag.FromErr(err)
}
_, err = client.UpdateGenericOIDCProvider(ctx, &admin.UpdateGenericOIDCProviderRequest{
Id: d.Id(),
Name: idp_utils.StringValue(d, idp_utils.NameVar),
Issuer: idp_utils.StringValue(d, IssuerVar),
ClientId: idp_utils.StringValue(d, idp_utils.ClientIDVar),
ClientSecret: idp_utils.StringValue(d, idp_utils.ClientSecretVar),
Scopes: idp_utils.ScopesValue(d),
ProviderOptions: idp_utils.ProviderOptionsValue(d),
IsIdTokenMapping: idp_utils.BoolValue(d, IsIdTokenMappingVar),
})
if err != nil {
return diag.Errorf("failed to update idp: %v", err)
}
return nil
}

func read(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
clientinfo, ok := m.(*helper.ClientInfo)
if !ok {
return diag.Errorf("failed to get client")
}
client, err := helper.GetAdminClient(ctx, clientinfo)
if err != nil {
return diag.FromErr(err)
}
resp, err := client.GetProviderByID(ctx, &admin.GetProviderByIDRequest{Id: helper.GetID(d, idp_utils.IdpIDVar)})
if err != nil && helper.IgnoreIfNotFoundError(err) == nil {
d.SetId("")
return nil
}
if err != nil {
return diag.Errorf("failed to get idp")
}
idp := resp.GetIdp()
cfg := idp.GetConfig()
specificCfg := cfg.GetSaml()
generalCfg := cfg.GetOptions()
set := map[string]interface{}{
helper.OrgIDVar: idp.GetDetails().GetResourceOwner(),
idp_utils.NameVar: idp.GetName(),
idp_utils.ClientIDVar: specificCfg.GetClientId(),
idp_utils.ClientSecretVar: idp_utils.StringValue(d, idp_utils.ClientSecretVar),
idp_utils.ScopesVar: specificCfg.GetScopes(),
idp_utils.IsLinkingAllowedVar: generalCfg.GetIsLinkingAllowed(),
idp_utils.IsCreationAllowedVar: generalCfg.GetIsCreationAllowed(),
idp_utils.IsAutoCreationVar: generalCfg.GetIsAutoCreation(),
idp_utils.IsAutoUpdateVar: generalCfg.GetIsAutoUpdate(),
IssuerVar: specificCfg.GetIssuer(),
IsIdTokenMappingVar: specificCfg.GetIsIdTokenMapping(),
}
for k, v := range set {
if err := d.Set(k, v); err != nil {
return diag.Errorf("failed to set %s of oidc idp: %v", k, err)
}
}
d.SetId(idp.Id)
return nil
}
32 changes: 32 additions & 0 deletions zitadel/idp_oidc/resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package idp_oidc

import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

"github.com/zitadel/terraform-provider-zitadel/v2/zitadel/helper"
"github.com/zitadel/terraform-provider-zitadel/v2/zitadel/idp_utils"
)

func GetResource() *schema.Resource {
return &schema.Resource{
Description: "Resource representing a SAML IDP on the instance.",
Schema: map[string]*schema.Schema{
helper.OrgIDVar: helper.OrgIDResourceField,
idp_utils.NameVar: idp_utils.NameResourceField,
idp_utils.ClientIDVar: idp_utils.ClientIDResourceField,
idp_utils.ClientSecretVar: idp_utils.ClientSecretResourceField,
idp_utils.ScopesVar: idp_utils.ScopesResourceField,
idp_utils.IsLinkingAllowedVar: idp_utils.IsLinkingAllowedResourceField,
idp_utils.IsCreationAllowedVar: idp_utils.IsCreationAllowedResourceField,
idp_utils.IsAutoCreationVar: idp_utils.IsAutoCreationResourceField,
idp_utils.IsAutoUpdateVar: idp_utils.IsAutoUpdateResourceField,
IssuerVar: IssuerResourceField,
IsIdTokenMappingVar: IsIdTokenMappingResourceField,
},
ReadContext: read,
UpdateContext: update,
CreateContext: create,
DeleteContext: idp_utils.Delete,
Importer: helper.ImportWithIDAndOptionalOrgAndSecret(idp_utils.IdpIDVar, idp_utils.ClientSecretVar),
}
}
11 changes: 11 additions & 0 deletions zitadel/idp_oidc/resource_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package idp_oidc_test

import (
"testing"

"github.com/zitadel/terraform-provider-zitadel/v2/zitadel/idp_utils/idp_test_utils"
)

func TestAccInstanceIdPOIDC(t *testing.T) {
idp_test_utils.RunInstanceIDPLifecyleTest(t, "zitadel_idp_oidc", idp_utils.ClientSecretVar)
}
31 changes: 31 additions & 0 deletions zitadel/idp_oidc/schema.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org_idp_oidc

import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

const (
IsIdTokenMappingVar = "is_id_token_mapping"
IssuerVar = "issuer"
)

var (
IsIdTokenMappingResourceField = &schema.Schema{
Type: schema.TypeBool,
Required: true,
Description: "if true, provider information get mapped from the id token, not from the userinfo endpoint",
}
IsIdTokenMappingDatasourceField = &schema.Schema{
Type: schema.TypeBool,
Computed: true,
Description: "if true, provider information get mapped from the id token, not from the userinfo endpoint.",
}
IssuerResourceField = &schema.Schema{
Type: schema.TypeString,
Required: true,
Description: "the issuer of the idp",
}
IssuerDatasourceField = &schema.Schema{
Type: schema.TypeString,
Computed: true,
Description: "the issuer of the idp",
}
)
1 change: 1 addition & 0 deletions zitadel/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import (
"github.com/zitadel/terraform-provider-zitadel/v2/zitadel/idp_google"
"github.com/zitadel/terraform-provider-zitadel/v2/zitadel/idp_ldap"
"github.com/zitadel/terraform-provider-zitadel/v2/zitadel/idp_oauth"
"github.com/zitadel/terraform-provider-zitadel/v2/zitadel/idp_oidc"
"github.com/zitadel/terraform-provider-zitadel/v2/zitadel/idp_saml"
"github.com/zitadel/terraform-provider-zitadel/v2/zitadel/init_message_text"
"github.com/zitadel/terraform-provider-zitadel/v2/zitadel/instance_member"
Expand Down

0 comments on commit c34a49b

Please sign in to comment.