Skip to content

Commit 5d3bbae

Browse files
authored
1 parent 00eb7a6 commit 5d3bbae

9 files changed

+227
-2
lines changed

example/main.tf

+9-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ terraform {
22
required_providers {
33
pomerium = {
44
source = "pomerium/pomerium"
5-
version = "0.0.5"
5+
version = "0.0.7"
66
}
77
}
88
}
@@ -52,6 +52,10 @@ resource "pomerium_settings" "settings" {
5252
proxy_log_level = "info"
5353

5454
timeout_idle = "5m"
55+
56+
jwt_groups_filter = {
57+
groups = ["id1", "id2"]
58+
}
5559
}
5660

5761
resource "pomerium_service_account" "test_sa" {
@@ -100,6 +104,10 @@ resource "pomerium_route" "test_route" {
100104
pomerium_policy.test_policy_group.id,
101105
pomerium_policy.test_policy.id,
102106
]
107+
jwt_groups_filter = {
108+
groups = ["group1", "group2"]
109+
infer_from_ppl = true
110+
}
103111
}
104112

105113
resource "pomerium_key_pair" "test_key_pair" {

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ require (
1111
github.com/hashicorp/terraform-plugin-go v0.25.0
1212
github.com/hashicorp/terraform-plugin-log v0.9.0
1313
github.com/iancoleman/strcase v0.3.0
14-
github.com/pomerium/enterprise-client-go v0.28.1-0.20250124233741-2592eb1169f7
14+
github.com/pomerium/enterprise-client-go v0.28.1-0.20250129215653-11b7f67dcbf4
1515
github.com/pomerium/pomerium v0.28.1-0.20250122205906-0bd6d8cc8315
1616
github.com/rs/zerolog v1.33.0
1717
github.com/stretchr/testify v1.10.0

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,8 @@ github.com/pomerium/csrf v1.7.0 h1:Qp4t6oyEod3svQtKfJZs589mdUTWKVf7q0PgCKYCshY=
231231
github.com/pomerium/csrf v1.7.0/go.mod h1:hAPZV47mEj2T9xFs+ysbum4l7SF1IdrryYaY6PdoIqw=
232232
github.com/pomerium/enterprise-client-go v0.28.1-0.20250124233741-2592eb1169f7 h1:m5rq102yZxD4UWUfyq5M0+butxmhuIeh5STMjMSQzJI=
233233
github.com/pomerium/enterprise-client-go v0.28.1-0.20250124233741-2592eb1169f7/go.mod h1:fnT1uLizb7e1aodN9SqSiqg6iYlWoppWFdaPlSR5eKc=
234+
github.com/pomerium/enterprise-client-go v0.28.1-0.20250129215653-11b7f67dcbf4 h1:hT9HWRvA54ujeCl4OS8voVl5oeRhyAjxKs/7ODBJoGo=
235+
github.com/pomerium/enterprise-client-go v0.28.1-0.20250129215653-11b7f67dcbf4/go.mod h1:fnT1uLizb7e1aodN9SqSiqg6iYlWoppWFdaPlSR5eKc=
234236
github.com/pomerium/pomerium v0.28.1-0.20250122205906-0bd6d8cc8315 h1:pdCpEr39m9UomjVkTp17Q4qeTbDZj7yxEffdBXZADe4=
235237
github.com/pomerium/pomerium v0.28.1-0.20250122205906-0bd6d8cc8315/go.mod h1:ujclJDq2BGZuSe2/9Lz2w4MpTVIR8DrR05qyjk1OcsU=
236238
github.com/pomerium/protoutil v0.0.0-20240813175624-47b7ac43ff46 h1:NRTg8JOXCxcIA1lAgD74iYud0rbshbWOB3Ou4+Huil8=

internal/provider/jwt_group_filter.go

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package provider
2+
3+
import (
4+
"context"
5+
6+
"github.com/hashicorp/terraform-plugin-framework/attr"
7+
"github.com/hashicorp/terraform-plugin-framework/diag"
8+
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
9+
"github.com/hashicorp/terraform-plugin-framework/types"
10+
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
11+
"github.com/pomerium/enterprise-client-go/pb"
12+
)
13+
14+
var (
15+
JWTGroupsFilterSchema = schema.SingleNestedAttribute{
16+
Optional: true,
17+
Description: "JWT Groups Filter",
18+
Attributes: map[string]schema.Attribute{
19+
"groups": schema.SetAttribute{
20+
ElementType: types.StringType,
21+
Optional: true,
22+
Computed: false,
23+
Sensitive: false,
24+
Description: "Group IDs to include",
25+
},
26+
"infer_from_ppl": schema.BoolAttribute{
27+
Optional: true,
28+
},
29+
},
30+
}
31+
JWTGroupsFilterSchemaAttr = map[string]attr.Type{
32+
"groups": types.SetType{
33+
ElemType: types.StringType,
34+
},
35+
"infer_from_ppl": types.BoolType,
36+
}
37+
)
38+
39+
func JWTGroupsFilterFromPB(
40+
dst *types.Object,
41+
src *pb.JwtGroupsFilter,
42+
) {
43+
if src == nil {
44+
*dst = types.ObjectNull(JWTGroupsFilterSchemaAttr)
45+
return
46+
}
47+
48+
attrs := make(map[string]attr.Value)
49+
if src.Groups == nil {
50+
attrs["groups"] = types.SetNull(types.StringType)
51+
} else {
52+
var vals []attr.Value
53+
for _, v := range src.Groups {
54+
vals = append(vals, types.StringValue(v))
55+
}
56+
attrs["groups"] = types.SetValueMust(types.StringType, vals)
57+
}
58+
59+
attrs["infer_from_ppl"] = types.BoolPointerValue(src.InferFromPpl)
60+
61+
*dst = types.ObjectValueMust(JWTGroupsFilterSchemaAttr, attrs)
62+
}
63+
64+
func JWTGroupsFilterToPB(
65+
ctx context.Context,
66+
dst **pb.JwtGroupsFilter,
67+
src types.Object,
68+
diags *diag.Diagnostics,
69+
) {
70+
if src.IsNull() {
71+
*dst = nil
72+
return
73+
}
74+
75+
type jwtOptions struct {
76+
Groups []string `tfsdk:"groups"`
77+
InferFromPpl *bool `tfsdk:"infer_from_ppl"`
78+
}
79+
var opts jwtOptions
80+
d := src.As(ctx, &opts, basetypes.ObjectAsOptions{
81+
UnhandledNullAsEmpty: true,
82+
UnhandledUnknownAsEmpty: false,
83+
})
84+
diags.Append(d...)
85+
if d.HasError() {
86+
return
87+
}
88+
89+
*dst = &pb.JwtGroupsFilter{
90+
Groups: opts.Groups,
91+
InferFromPpl: opts.InferFromPpl,
92+
}
93+
}
+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package provider_test
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/google/go-cmp/cmp"
8+
"github.com/hashicorp/terraform-plugin-framework/attr"
9+
"github.com/hashicorp/terraform-plugin-framework/diag"
10+
"github.com/hashicorp/terraform-plugin-framework/types"
11+
"github.com/pomerium/enterprise-client-go/pb"
12+
"github.com/pomerium/enterprise-terraform-provider/internal/provider"
13+
"github.com/stretchr/testify/assert"
14+
"google.golang.org/protobuf/testing/protocmp"
15+
)
16+
17+
func TestJWTGroupsFilterFromPB(t *testing.T) {
18+
tests := []struct {
19+
name string
20+
input *pb.JwtGroupsFilter
21+
expected types.Object
22+
}{
23+
{
24+
name: "nil input",
25+
input: nil,
26+
expected: types.ObjectNull(provider.JWTGroupsFilterSchemaAttr),
27+
},
28+
{
29+
name: "empty groups",
30+
input: &pb.JwtGroupsFilter{
31+
Groups: []string{},
32+
InferFromPpl: P(false),
33+
},
34+
expected: types.ObjectValueMust(provider.JWTGroupsFilterSchemaAttr, map[string]attr.Value{
35+
"groups": types.SetValueMust(types.StringType, []attr.Value{}),
36+
"infer_from_ppl": types.BoolValue(false),
37+
}),
38+
},
39+
{
40+
name: "with groups",
41+
input: &pb.JwtGroupsFilter{
42+
Groups: []string{"group1", "group2"},
43+
InferFromPpl: P(true),
44+
},
45+
expected: types.ObjectValueMust(provider.JWTGroupsFilterSchemaAttr, map[string]attr.Value{
46+
"groups": types.SetValueMust(types.StringType, []attr.Value{
47+
types.StringValue("group1"),
48+
types.StringValue("group2"),
49+
}),
50+
"infer_from_ppl": types.BoolValue(true),
51+
}),
52+
},
53+
}
54+
55+
for _, tc := range tests {
56+
t.Run(tc.name, func(t *testing.T) {
57+
var result types.Object
58+
provider.JWTGroupsFilterFromPB(&result, tc.input)
59+
diff := cmp.Diff(tc.expected, result)
60+
assert.Empty(t, diff)
61+
})
62+
}
63+
}
64+
65+
func TestJWTGroupsFilterToPB(t *testing.T) {
66+
ctx := context.Background()
67+
tests := []struct {
68+
name string
69+
input types.Object
70+
expected *pb.JwtGroupsFilter
71+
}{
72+
{
73+
name: "null input",
74+
input: types.ObjectNull(provider.JWTGroupsFilterSchemaAttr),
75+
expected: nil,
76+
},
77+
{
78+
name: "empty groups",
79+
input: types.ObjectValueMust(provider.JWTGroupsFilterSchemaAttr, map[string]attr.Value{
80+
"groups": types.SetValueMust(types.StringType, []attr.Value{}),
81+
"infer_from_ppl": types.BoolValue(false),
82+
}),
83+
expected: &pb.JwtGroupsFilter{
84+
Groups: []string{},
85+
InferFromPpl: P(false),
86+
},
87+
},
88+
{
89+
name: "with groups",
90+
input: types.ObjectValueMust(provider.JWTGroupsFilterSchemaAttr, map[string]attr.Value{
91+
"groups": types.SetValueMust(types.StringType, []attr.Value{
92+
types.StringValue("group1"),
93+
types.StringValue("group2"),
94+
}),
95+
"infer_from_ppl": types.BoolValue(true),
96+
}),
97+
expected: &pb.JwtGroupsFilter{
98+
Groups: []string{"group1", "group2"},
99+
InferFromPpl: P(true),
100+
},
101+
},
102+
}
103+
104+
for _, tc := range tests {
105+
t.Run(tc.name, func(t *testing.T) {
106+
var diags diag.Diagnostics
107+
var result *pb.JwtGroupsFilter
108+
provider.JWTGroupsFilterToPB(ctx, &result, tc.input, &diags)
109+
assert.False(t, diags.HasError())
110+
diff := cmp.Diff(tc.expected, result, protocmp.Transform())
111+
assert.Empty(t, diff)
112+
})
113+
}
114+
}

internal/provider/route.go

+1
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ func (r *RouteResource) Schema(_ context.Context, _ resource.SchemaRequest, resp
198198
Optional: true,
199199
Computed: true,
200200
},
201+
"jwt_groups_filter": JWTGroupsFilterSchema,
201202
},
202203
}
203204
}

internal/provider/route_model.go

+3
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ type RouteModel struct {
4646
IDPClientID types.String `tfsdk:"idp_client_id"`
4747
IDPClientSecret types.String `tfsdk:"idp_client_secret"`
4848
ShowErrorDetails types.Bool `tfsdk:"show_error_details"`
49+
JWTGroupsFilter types.Object `tfsdk:"jwt_groups_filter"`
4950
}
5051

5152
func ConvertRouteToPB(
@@ -88,6 +89,7 @@ func ConvertRouteToPB(
8889
pbRoute.IdpClientId = src.IDPClientID.ValueStringPointer()
8990
pbRoute.IdpClientSecret = src.IDPClientSecret.ValueStringPointer()
9091
pbRoute.ShowErrorDetails = src.ShowErrorDetails.ValueBool()
92+
JWTGroupsFilterToPB(ctx, &pbRoute.JwtGroupsFilter, src.JWTGroupsFilter, &diagnostics)
9193

9294
diags := src.To.ElementsAs(ctx, &pbRoute.To, false)
9395
diagnostics.Append(diags...)
@@ -140,6 +142,7 @@ func ConvertRouteFromPB(
140142
dst.IDPClientID = types.StringPointerValue(src.IdpClientId)
141143
dst.IDPClientSecret = types.StringPointerValue(src.IdpClientSecret)
142144
dst.ShowErrorDetails = types.BoolValue(src.ShowErrorDetails)
145+
JWTGroupsFilterFromPB(&dst.JWTGroupsFilter, src.JwtGroupsFilter)
143146

144147
return diagnostics
145148
}

internal/provider/settings_model.go

+3
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ type SettingsModel struct {
8080
TimeoutIdle timetypes.GoDuration `tfsdk:"timeout_idle"`
8181
TimeoutRead timetypes.GoDuration `tfsdk:"timeout_read"`
8282
TimeoutWrite timetypes.GoDuration `tfsdk:"timeout_write"`
83+
JWTGroupsFilter types.Object `tfsdk:"jwt_groups_filter"`
8384
}
8485

8586
func ConvertSettingsToPB(
@@ -151,6 +152,7 @@ func ConvertSettingsToPB(
151152
ToDuration(&pbSettings.TimeoutIdle, src.TimeoutIdle, &diagnostics)
152153
ToDuration(&pbSettings.TimeoutRead, src.TimeoutRead, &diagnostics)
153154
ToDuration(&pbSettings.TimeoutWrite, src.TimeoutWrite, &diagnostics)
155+
JWTGroupsFilterToPB(ctx, &pbSettings.JwtGroupsFilter, src.JWTGroupsFilter, &diagnostics)
154156

155157
return pbSettings, diagnostics
156158
}
@@ -223,6 +225,7 @@ func ConvertSettingsFromPB(
223225
dst.TimeoutIdle = FromDuration(src.TimeoutIdle)
224226
dst.TimeoutRead = FromDuration(src.TimeoutRead)
225227
dst.TimeoutWrite = FromDuration(src.TimeoutWrite)
228+
JWTGroupsFilterFromPB(&dst.JWTGroupsFilter, src.JwtGroupsFilter)
226229

227230
return diagnostics
228231
}

internal/provider/settings_schema.go

+1
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ var SettingsResourceSchema = schema.Schema{
190190
Optional: true,
191191
Description: "JWT claims headers mapping",
192192
},
193+
"jwt_groups_filter": JWTGroupsFilterSchema,
193194
"default_upstream_timeout": schema.StringAttribute{
194195
Optional: true,
195196
Description: "Default upstream timeout",

0 commit comments

Comments
 (0)