Skip to content

Commit d62911a

Browse files
authored
Add smallstep_identity_provider and smalltep_idp_client (#35)
1 parent dcf8930 commit d62911a

File tree

21 files changed

+1445
-8
lines changed

21 files changed

+1445
-8
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "smallstep_identity_provider Data Source - terraform-provider-smallstep"
4+
subcategory: ""
5+
description: |-
6+
7+
---
8+
9+
# smallstep_identity_provider (Data Source)
10+
11+
12+
13+
14+
15+
<!-- schema generated by tfplugindocs -->
16+
## Schema
17+
18+
### Read-Only
19+
20+
- `authorize_endpoint` (String) The URL where clients authenticate.
21+
- `issuer` (String) The URL of this identity provider.
22+
- `jwks_endpoint` (String) The URL where relying parties can read the provider's public key.
23+
- `token_endpoint` (String) The URL where relying parties exchange authorization codes for identity tokens.
24+
- `trust_roots` (String) The CA used to verify clients at the authorize endpoint.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "smallstep_identity_provider_client Data Source - terraform-provider-smallstep"
4+
subcategory: ""
5+
description: |-
6+
7+
---
8+
9+
# smallstep_identity_provider_client (Data Source)
10+
11+
12+
13+
14+
15+
<!-- schema generated by tfplugindocs -->
16+
## Schema
17+
18+
### Required
19+
20+
- `id` (String) The client ID.
21+
22+
### Read-Only
23+
24+
- `redirect_uri` (String) Where user-agents will be sent after authentication attempts.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "smallstep_identity_provider Resource - terraform-provider-smallstep"
4+
subcategory: ""
5+
description: |-
6+
7+
---
8+
9+
# smallstep_identity_provider (Resource)
10+
11+
12+
13+
## Example Usage
14+
15+
```terraform
16+
resource "smallstep_identity_provider" "my_idp" {
17+
trust_roots = file("${path.module}/root.crt")
18+
}
19+
20+
output "idp_authorize_url" {
21+
value = smallstep_identity_provider.my_idp.authorize_endpoint
22+
}
23+
24+
output "idp_token_url" {
25+
value = smallstep_identity_provider.my_idp.token_endpoint
26+
}
27+
28+
output "idp_jwks_url" {
29+
value = smallstep_identity_provider.my_idp.jwks_endpoint
30+
}
31+
```
32+
33+
<!-- schema generated by tfplugindocs -->
34+
## Schema
35+
36+
### Required
37+
38+
- `trust_roots` (String) The CA used to verify clients at the authorize endpoint.
39+
40+
### Read-Only
41+
42+
- `authorize_endpoint` (String) The URL where clients authenticate.
43+
- `issuer` (String) The URL of this identity provider.
44+
- `jwks_endpoint` (String) The URL where relying parties can read the provider's public key.
45+
- `token_endpoint` (String) The URL where relying parties exchange authorization codes for identity tokens.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "smallstep_identity_provider_client Resource - terraform-provider-smallstep"
4+
subcategory: ""
5+
description: |-
6+
7+
---
8+
9+
# smallstep_identity_provider_client (Resource)
10+
11+
12+
13+
## Example Usage
14+
15+
```terraform
16+
resource "smallstep_identity_provider" "my_idp" {
17+
trust_roots = file("${path.module}/root.crt")
18+
}
19+
20+
resource "smallstep_identity_provider_client" "my_idp_client" {
21+
redirect_uri = "https://example.com/callback"
22+
store_secret = true
23+
depends_on = [smallstep_identity_provider.my_idp]
24+
}
25+
26+
output "idp_client_id" {
27+
value = smallstep_identity_provider_client.my_idp_client.id
28+
}
29+
30+
output "idp_client_secret" {
31+
value = smallstep_identity_provider_client.my_idp_client.secret
32+
}
33+
```
34+
35+
<!-- schema generated by tfplugindocs -->
36+
## Schema
37+
38+
### Required
39+
40+
- `redirect_uri` (String) Where user-agents will be sent after authentication attempts.
41+
42+
### Optional
43+
44+
- `store_secret` (Boolean) Whether to store the client_secret in terraform state when it is created. The secret cannot be recovered later.
45+
- `write_secret_file` (String) If non-empty the client_secret will be written to this filepath when it is created. The secret cannot be recovered later.
46+
47+
### Read-Only
48+
49+
- `id` (String) The client ID.
50+
- `secret` (String, Sensitive) The secret relying parties will use to authenticate when exchanging an authorization code for an id token.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
resource "smallstep_identity_provider" "my_idp" {
3+
trust_roots = file("${path.module}/root.crt")
4+
}
5+
6+
output "idp_authorize_url" {
7+
value = smallstep_identity_provider.my_idp.authorize_endpoint
8+
}
9+
10+
output "idp_token_url" {
11+
value = smallstep_identity_provider.my_idp.token_endpoint
12+
}
13+
14+
output "idp_jwks_url" {
15+
value = smallstep_identity_provider.my_idp.jwks_endpoint
16+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
resource "smallstep_identity_provider" "my_idp" {
3+
trust_roots = file("${path.module}/root.crt")
4+
}
5+
6+
resource "smallstep_identity_provider_client" "my_idp_client" {
7+
redirect_uri = "https://example.com/callback"
8+
store_secret = true
9+
depends_on = [smallstep_identity_provider.my_idp]
10+
}
11+
12+
output "idp_client_id" {
13+
value = smallstep_identity_provider_client.my_idp_client.id
14+
}
15+
16+
output "idp_client_secret" {
17+
value = smallstep_identity_provider_client.my_idp_client.secret
18+
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package identity_provider
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"net/http"
8+
9+
"github.com/hashicorp/terraform-plugin-framework/datasource"
10+
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
11+
"github.com/hashicorp/terraform-plugin-framework/path"
12+
13+
v20250101 "github.com/smallstep/terraform-provider-smallstep/internal/apiclient/v20250101"
14+
"github.com/smallstep/terraform-provider-smallstep/internal/provider/utils"
15+
)
16+
17+
var _ datasource.DataSourceWithConfigure = (*ClientDataSource)(nil)
18+
19+
func NewClientDataSource() datasource.DataSource {
20+
return &ClientDataSource{}
21+
}
22+
23+
type ClientDataSource struct {
24+
client *v20250101.Client
25+
}
26+
27+
func (a *ClientDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
28+
resp.TypeName = client_name
29+
}
30+
31+
// Configure adds the Smallstep API client to the data source.
32+
func (ds *ClientDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
33+
// Prevent panic if the provider has not been configured.
34+
if req.ProviderData == nil {
35+
return
36+
}
37+
38+
client, ok := req.ProviderData.(*v20250101.Client)
39+
40+
if !ok {
41+
resp.Diagnostics.AddError(
42+
"Get Smallstep API client from provider",
43+
fmt.Sprintf("Expected *v20250101.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
44+
)
45+
return
46+
}
47+
48+
ds.client = client
49+
}
50+
51+
func (d *ClientDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
52+
idp, props, err := utils.Describe("idpClient")
53+
if err != nil {
54+
resp.Diagnostics.AddError(
55+
"Parse Smallstep OpenAPI Identity Provider Schema",
56+
err.Error(),
57+
)
58+
return
59+
}
60+
61+
resp.Schema = schema.Schema{
62+
MarkdownDescription: idp,
63+
64+
Attributes: map[string]schema.Attribute{
65+
"id": schema.StringAttribute{
66+
MarkdownDescription: props["id"],
67+
Required: true,
68+
},
69+
"redirect_uri": schema.StringAttribute{
70+
MarkdownDescription: props["redirectURI"],
71+
Computed: true,
72+
},
73+
},
74+
}
75+
}
76+
77+
func (ds *ClientDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
78+
var id string
79+
diags := req.Config.GetAttribute(ctx, path.Root("id"), &id)
80+
resp.Diagnostics.Append(diags...)
81+
if resp.Diagnostics.HasError() {
82+
return
83+
}
84+
if id == "" {
85+
resp.Diagnostics.AddError(
86+
"Invalid Read Identity Provider Client Request",
87+
"ID is required.",
88+
)
89+
return
90+
}
91+
httpResp, err := ds.client.GetIdpClient(ctx, id, &v20250101.GetIdpClientParams{})
92+
if err != nil {
93+
resp.Diagnostics.AddError(
94+
"Smallstep API Client Error",
95+
fmt.Sprintf("Failed to read identity provider client: %v", err),
96+
)
97+
return
98+
}
99+
defer httpResp.Body.Close()
100+
101+
if httpResp.StatusCode == http.StatusNotFound {
102+
resp.State.RemoveResource(ctx)
103+
return
104+
}
105+
if httpResp.StatusCode != http.StatusOK {
106+
reqID := httpResp.Header.Get("X-Request-Id")
107+
resp.Diagnostics.AddError(
108+
"Smallstep API Response Error",
109+
fmt.Sprintf("Request %q received status %d reading identity provider client: %s", reqID, httpResp.StatusCode, utils.APIErrorMsg(httpResp.Body)),
110+
)
111+
return
112+
}
113+
114+
remote := &v20250101.IdpClient{}
115+
if err := json.NewDecoder(httpResp.Body).Decode(remote); err != nil {
116+
resp.Diagnostics.AddError(
117+
"Smallstep API Client Error",
118+
fmt.Sprintf("Failed to unmarshal identity provider: %v", err),
119+
)
120+
return
121+
}
122+
123+
model := clientFromAPI(remote)
124+
125+
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), model.ID)...)
126+
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("redirect_uri"), model.RedirectURI)...)
127+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package identity_provider
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
helper "github.com/hashicorp/terraform-plugin-testing/helper/resource"
8+
"github.com/smallstep/terraform-provider-smallstep/internal/provider/utils"
9+
)
10+
11+
func TestAccIdentityProviderClientDataSource(t *testing.T) {
12+
utils.NewIdentityProvider(t)
13+
client := utils.NewIdentityProviderClient(t)
14+
15+
const config = `
16+
data "smallstep_identity_provider_client" "my_idp_client" {
17+
id = %q
18+
}`
19+
cfg := fmt.Sprintf(config, *client.Id)
20+
21+
helper.Test(t, helper.TestCase{
22+
ProtoV6ProviderFactories: providerFactories,
23+
Steps: []helper.TestStep{
24+
{
25+
Config: cfg,
26+
Check: helper.ComposeAggregateTestCheckFunc(
27+
helper.TestCheckResourceAttr("data.smallstep_identity_provider_client.my_idp_client", "id", *client.Id),
28+
helper.TestCheckResourceAttr("data.smallstep_identity_provider_client.my_idp_client", "redirect_uri", client.RedirectURI),
29+
),
30+
},
31+
},
32+
})
33+
}

0 commit comments

Comments
 (0)