Skip to content

Commit

Permalink
adds jwt_groups_filter (#34)
Browse files Browse the repository at this point in the history
  • Loading branch information
wasaga authored Jan 29, 2025
1 parent 00eb7a6 commit 5d3bbae
Show file tree
Hide file tree
Showing 9 changed files with 227 additions and 2 deletions.
10 changes: 9 additions & 1 deletion example/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ terraform {
required_providers {
pomerium = {
source = "pomerium/pomerium"
version = "0.0.5"
version = "0.0.7"
}
}
}
Expand Down Expand Up @@ -52,6 +52,10 @@ resource "pomerium_settings" "settings" {
proxy_log_level = "info"

timeout_idle = "5m"

jwt_groups_filter = {
groups = ["id1", "id2"]
}
}

resource "pomerium_service_account" "test_sa" {
Expand Down Expand Up @@ -100,6 +104,10 @@ resource "pomerium_route" "test_route" {
pomerium_policy.test_policy_group.id,
pomerium_policy.test_policy.id,
]
jwt_groups_filter = {
groups = ["group1", "group2"]
infer_from_ppl = true
}
}

resource "pomerium_key_pair" "test_key_pair" {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ require (
github.com/hashicorp/terraform-plugin-go v0.25.0
github.com/hashicorp/terraform-plugin-log v0.9.0
github.com/iancoleman/strcase v0.3.0
github.com/pomerium/enterprise-client-go v0.28.1-0.20250124233741-2592eb1169f7
github.com/pomerium/enterprise-client-go v0.28.1-0.20250129215653-11b7f67dcbf4
github.com/pomerium/pomerium v0.28.1-0.20250122205906-0bd6d8cc8315
github.com/rs/zerolog v1.33.0
github.com/stretchr/testify v1.10.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ github.com/pomerium/csrf v1.7.0 h1:Qp4t6oyEod3svQtKfJZs589mdUTWKVf7q0PgCKYCshY=
github.com/pomerium/csrf v1.7.0/go.mod h1:hAPZV47mEj2T9xFs+ysbum4l7SF1IdrryYaY6PdoIqw=
github.com/pomerium/enterprise-client-go v0.28.1-0.20250124233741-2592eb1169f7 h1:m5rq102yZxD4UWUfyq5M0+butxmhuIeh5STMjMSQzJI=
github.com/pomerium/enterprise-client-go v0.28.1-0.20250124233741-2592eb1169f7/go.mod h1:fnT1uLizb7e1aodN9SqSiqg6iYlWoppWFdaPlSR5eKc=
github.com/pomerium/enterprise-client-go v0.28.1-0.20250129215653-11b7f67dcbf4 h1:hT9HWRvA54ujeCl4OS8voVl5oeRhyAjxKs/7ODBJoGo=
github.com/pomerium/enterprise-client-go v0.28.1-0.20250129215653-11b7f67dcbf4/go.mod h1:fnT1uLizb7e1aodN9SqSiqg6iYlWoppWFdaPlSR5eKc=
github.com/pomerium/pomerium v0.28.1-0.20250122205906-0bd6d8cc8315 h1:pdCpEr39m9UomjVkTp17Q4qeTbDZj7yxEffdBXZADe4=
github.com/pomerium/pomerium v0.28.1-0.20250122205906-0bd6d8cc8315/go.mod h1:ujclJDq2BGZuSe2/9Lz2w4MpTVIR8DrR05qyjk1OcsU=
github.com/pomerium/protoutil v0.0.0-20240813175624-47b7ac43ff46 h1:NRTg8JOXCxcIA1lAgD74iYud0rbshbWOB3Ou4+Huil8=
Expand Down
93 changes: 93 additions & 0 deletions internal/provider/jwt_group_filter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package provider

import (
"context"

"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
"github.com/pomerium/enterprise-client-go/pb"
)

var (
JWTGroupsFilterSchema = schema.SingleNestedAttribute{
Optional: true,
Description: "JWT Groups Filter",
Attributes: map[string]schema.Attribute{
"groups": schema.SetAttribute{
ElementType: types.StringType,
Optional: true,
Computed: false,
Sensitive: false,
Description: "Group IDs to include",
},
"infer_from_ppl": schema.BoolAttribute{
Optional: true,
},
},
}
JWTGroupsFilterSchemaAttr = map[string]attr.Type{
"groups": types.SetType{
ElemType: types.StringType,
},
"infer_from_ppl": types.BoolType,
}
)

func JWTGroupsFilterFromPB(
dst *types.Object,
src *pb.JwtGroupsFilter,
) {
if src == nil {
*dst = types.ObjectNull(JWTGroupsFilterSchemaAttr)
return
}

attrs := make(map[string]attr.Value)
if src.Groups == nil {
attrs["groups"] = types.SetNull(types.StringType)
} else {
var vals []attr.Value
for _, v := range src.Groups {
vals = append(vals, types.StringValue(v))
}
attrs["groups"] = types.SetValueMust(types.StringType, vals)
}

attrs["infer_from_ppl"] = types.BoolPointerValue(src.InferFromPpl)

*dst = types.ObjectValueMust(JWTGroupsFilterSchemaAttr, attrs)
}

func JWTGroupsFilterToPB(
ctx context.Context,
dst **pb.JwtGroupsFilter,
src types.Object,
diags *diag.Diagnostics,
) {
if src.IsNull() {
*dst = nil
return
}

type jwtOptions struct {
Groups []string `tfsdk:"groups"`
InferFromPpl *bool `tfsdk:"infer_from_ppl"`
}
var opts jwtOptions
d := src.As(ctx, &opts, basetypes.ObjectAsOptions{
UnhandledNullAsEmpty: true,
UnhandledUnknownAsEmpty: false,
})
diags.Append(d...)
if d.HasError() {
return
}

*dst = &pb.JwtGroupsFilter{
Groups: opts.Groups,
InferFromPpl: opts.InferFromPpl,
}
}
114 changes: 114 additions & 0 deletions internal/provider/jwt_group_filter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package provider_test

import (
"context"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/pomerium/enterprise-client-go/pb"
"github.com/pomerium/enterprise-terraform-provider/internal/provider"
"github.com/stretchr/testify/assert"
"google.golang.org/protobuf/testing/protocmp"
)

func TestJWTGroupsFilterFromPB(t *testing.T) {
tests := []struct {
name string
input *pb.JwtGroupsFilter
expected types.Object
}{
{
name: "nil input",
input: nil,
expected: types.ObjectNull(provider.JWTGroupsFilterSchemaAttr),
},
{
name: "empty groups",
input: &pb.JwtGroupsFilter{
Groups: []string{},
InferFromPpl: P(false),
},
expected: types.ObjectValueMust(provider.JWTGroupsFilterSchemaAttr, map[string]attr.Value{
"groups": types.SetValueMust(types.StringType, []attr.Value{}),
"infer_from_ppl": types.BoolValue(false),
}),
},
{
name: "with groups",
input: &pb.JwtGroupsFilter{
Groups: []string{"group1", "group2"},
InferFromPpl: P(true),
},
expected: types.ObjectValueMust(provider.JWTGroupsFilterSchemaAttr, map[string]attr.Value{
"groups": types.SetValueMust(types.StringType, []attr.Value{
types.StringValue("group1"),
types.StringValue("group2"),
}),
"infer_from_ppl": types.BoolValue(true),
}),
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
var result types.Object
provider.JWTGroupsFilterFromPB(&result, tc.input)
diff := cmp.Diff(tc.expected, result)
assert.Empty(t, diff)
})
}
}

func TestJWTGroupsFilterToPB(t *testing.T) {
ctx := context.Background()
tests := []struct {
name string
input types.Object
expected *pb.JwtGroupsFilter
}{
{
name: "null input",
input: types.ObjectNull(provider.JWTGroupsFilterSchemaAttr),
expected: nil,
},
{
name: "empty groups",
input: types.ObjectValueMust(provider.JWTGroupsFilterSchemaAttr, map[string]attr.Value{
"groups": types.SetValueMust(types.StringType, []attr.Value{}),
"infer_from_ppl": types.BoolValue(false),
}),
expected: &pb.JwtGroupsFilter{
Groups: []string{},
InferFromPpl: P(false),
},
},
{
name: "with groups",
input: types.ObjectValueMust(provider.JWTGroupsFilterSchemaAttr, map[string]attr.Value{
"groups": types.SetValueMust(types.StringType, []attr.Value{
types.StringValue("group1"),
types.StringValue("group2"),
}),
"infer_from_ppl": types.BoolValue(true),
}),
expected: &pb.JwtGroupsFilter{
Groups: []string{"group1", "group2"},
InferFromPpl: P(true),
},
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
var diags diag.Diagnostics
var result *pb.JwtGroupsFilter
provider.JWTGroupsFilterToPB(ctx, &result, tc.input, &diags)
assert.False(t, diags.HasError())
diff := cmp.Diff(tc.expected, result, protocmp.Transform())
assert.Empty(t, diff)
})
}
}
1 change: 1 addition & 0 deletions internal/provider/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ func (r *RouteResource) Schema(_ context.Context, _ resource.SchemaRequest, resp
Optional: true,
Computed: true,
},
"jwt_groups_filter": JWTGroupsFilterSchema,
},
}
}
Expand Down
3 changes: 3 additions & 0 deletions internal/provider/route_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type RouteModel struct {
IDPClientID types.String `tfsdk:"idp_client_id"`
IDPClientSecret types.String `tfsdk:"idp_client_secret"`
ShowErrorDetails types.Bool `tfsdk:"show_error_details"`
JWTGroupsFilter types.Object `tfsdk:"jwt_groups_filter"`
}

func ConvertRouteToPB(
Expand Down Expand Up @@ -88,6 +89,7 @@ func ConvertRouteToPB(
pbRoute.IdpClientId = src.IDPClientID.ValueStringPointer()
pbRoute.IdpClientSecret = src.IDPClientSecret.ValueStringPointer()
pbRoute.ShowErrorDetails = src.ShowErrorDetails.ValueBool()
JWTGroupsFilterToPB(ctx, &pbRoute.JwtGroupsFilter, src.JWTGroupsFilter, &diagnostics)

diags := src.To.ElementsAs(ctx, &pbRoute.To, false)
diagnostics.Append(diags...)
Expand Down Expand Up @@ -140,6 +142,7 @@ func ConvertRouteFromPB(
dst.IDPClientID = types.StringPointerValue(src.IdpClientId)
dst.IDPClientSecret = types.StringPointerValue(src.IdpClientSecret)
dst.ShowErrorDetails = types.BoolValue(src.ShowErrorDetails)
JWTGroupsFilterFromPB(&dst.JWTGroupsFilter, src.JwtGroupsFilter)

return diagnostics
}
3 changes: 3 additions & 0 deletions internal/provider/settings_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ type SettingsModel struct {
TimeoutIdle timetypes.GoDuration `tfsdk:"timeout_idle"`
TimeoutRead timetypes.GoDuration `tfsdk:"timeout_read"`
TimeoutWrite timetypes.GoDuration `tfsdk:"timeout_write"`
JWTGroupsFilter types.Object `tfsdk:"jwt_groups_filter"`
}

func ConvertSettingsToPB(
Expand Down Expand Up @@ -151,6 +152,7 @@ func ConvertSettingsToPB(
ToDuration(&pbSettings.TimeoutIdle, src.TimeoutIdle, &diagnostics)
ToDuration(&pbSettings.TimeoutRead, src.TimeoutRead, &diagnostics)
ToDuration(&pbSettings.TimeoutWrite, src.TimeoutWrite, &diagnostics)
JWTGroupsFilterToPB(ctx, &pbSettings.JwtGroupsFilter, src.JWTGroupsFilter, &diagnostics)

return pbSettings, diagnostics
}
Expand Down Expand Up @@ -223,6 +225,7 @@ func ConvertSettingsFromPB(
dst.TimeoutIdle = FromDuration(src.TimeoutIdle)
dst.TimeoutRead = FromDuration(src.TimeoutRead)
dst.TimeoutWrite = FromDuration(src.TimeoutWrite)
JWTGroupsFilterFromPB(&dst.JWTGroupsFilter, src.JwtGroupsFilter)

return diagnostics
}
1 change: 1 addition & 0 deletions internal/provider/settings_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ var SettingsResourceSchema = schema.Schema{
Optional: true,
Description: "JWT claims headers mapping",
},
"jwt_groups_filter": JWTGroupsFilterSchema,
"default_upstream_timeout": schema.StringAttribute{
Optional: true,
Description: "Default upstream timeout",
Expand Down

0 comments on commit 5d3bbae

Please sign in to comment.