Skip to content

Commit 3185abd

Browse files
fix(auth) require lowercase letters for role assignment subject (#1264)
1 parent 5eec4cd commit 3185abd

File tree

6 files changed

+73
-4
lines changed

6 files changed

+73
-4
lines changed

docs/resources/authorization_folder_role_assignment.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import {
4343

4444
- `resource_id` (String) folder Resource to assign the role to.
4545
- `role` (String) Role to be assigned. Available roles can be queried using stackit-cli: `stackit curl https://authorization.api.stackit.cloud/v2/permissions`
46-
- `subject` (String) Identifier of user, service account or client. Usually email address or name in case of clients
46+
- `subject` (String) Identifier of user, service account or client. Usually email address or name in case of clients. All letters must be lowercased.
4747

4848
### Read-Only
4949

docs/resources/authorization_organization_role_assignment.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import {
3636

3737
- `resource_id` (String) organization Resource to assign the role to.
3838
- `role` (String) Role to be assigned. Available roles can be queried using stackit-cli: `stackit curl https://authorization.api.stackit.cloud/v2/permissions`
39-
- `subject` (String) Identifier of user, service account or client. Usually email address or name in case of clients
39+
- `subject` (String) Identifier of user, service account or client. Usually email address or name in case of clients. All letters must be lowercased.
4040

4141
### Read-Only
4242

docs/resources/authorization_project_role_assignment.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import {
4343

4444
- `resource_id` (String) project Resource to assign the role to.
4545
- `role` (String) Role to be assigned. Available roles can be queried using stackit-cli: `stackit curl https://authorization.api.stackit.cloud/v2/permissions`
46-
- `subject` (String) Identifier of user, service account or client. Usually email address or name in case of clients
46+
- `subject` (String) Identifier of user, service account or client. Usually email address or name in case of clients. All letters must be lowercased.
4747

4848
### Read-Only
4949

stackit/internal/services/authorization/roleassignments/resource.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ func (r *roleAssignmentResource) Schema(_ context.Context, _ resource.SchemaRequ
9999
"id": "Terraform's internal resource identifier. It is structured as \"`resource_id`,`role`,`subject`\".",
100100
"resource_id": fmt.Sprintf("%s Resource to assign the role to.", r.apiName),
101101
"role": "Role to be assigned. Available roles can be queried using stackit-cli: `stackit curl https://authorization.api.stackit.cloud/v2/permissions`",
102-
"subject": "Identifier of user, service account or client. Usually email address or name in case of clients",
102+
"subject": "Identifier of user, service account or client. Usually email address or name in case of clients. All letters must be lowercased.",
103103
}
104104

105105
resp.Schema = schema.Schema{
@@ -133,6 +133,9 @@ func (r *roleAssignmentResource) Schema(_ context.Context, _ resource.SchemaRequ
133133
"subject": schema.StringAttribute{
134134
Description: descriptions["subject"],
135135
Required: true,
136+
Validators: []validator.String{
137+
validate.IsLowercased(),
138+
},
136139
PlanModifiers: []planmodifier.String{
137140
stringplanmodifier.RequiresReplace(),
138141
},

stackit/internal/validate/validate.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,3 +369,27 @@ func ValidNoTrailingNewline() *Validator {
369369
},
370370
}
371371
}
372+
373+
// IsLowercased returns a Validator that checks if all letters in the input string are lowercase.
374+
// Examples:
375+
// - "example": valid
376+
// - "example123": valid, numbers are not affected by case
377+
// - "exaMPle123": invalid
378+
func IsLowercased() *Validator {
379+
description := `All letters in the value must be lowercase as defined by gos unicode.IsLower(rune).`
380+
return &Validator{
381+
description: description,
382+
validate: func(_ context.Context, request validator.StringRequest, response *validator.StringResponse) {
383+
val := request.ConfigValue.ValueString()
384+
lowercased := strings.ToLower(val)
385+
if val != lowercased {
386+
response.Diagnostics.Append(validatordiag.InvalidAttributeValueDiagnostic(
387+
request.Path,
388+
description,
389+
val,
390+
))
391+
return
392+
}
393+
},
394+
}
395+
}

stackit/internal/validate/validate_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,3 +966,45 @@ func TestValidNoTrailingNewline(t *testing.T) {
966966
})
967967
}
968968
}
969+
970+
func TestIsLowercased(t *testing.T) {
971+
tests := []struct {
972+
description string
973+
input string
974+
wantErr bool
975+
}{
976+
{
977+
description: "empty",
978+
input: "",
979+
},
980+
{
981+
description: "simple lowercase",
982+
input: "lowercase",
983+
},
984+
{
985+
description: "lowercase with numbers and symbols",
986+
input: "lowercase123!@#",
987+
},
988+
{
989+
description: "uppercase letters",
990+
input: "UpperCase",
991+
wantErr: true,
992+
},
993+
}
994+
995+
for _, tt := range tests {
996+
t.Run(tt.description, func(t *testing.T) {
997+
r := validator.StringResponse{}
998+
IsLowercased().ValidateString(context.Background(), validator.StringRequest{
999+
ConfigValue: types.StringValue(tt.input),
1000+
}, &r)
1001+
1002+
if tt.wantErr && !r.Diagnostics.HasError() {
1003+
t.Fatalf("Expected validation to fail for input: %q", tt.input)
1004+
}
1005+
if !tt.wantErr && r.Diagnostics.HasError() {
1006+
t.Fatalf("Expected validation to succeed for input: %q, but got errors: %v", tt.input, r.Diagnostics.Errors())
1007+
}
1008+
})
1009+
}
1010+
}

0 commit comments

Comments
 (0)