Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions keycloak/realm.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package keycloak
import (
"context"
"fmt"
"github.com/keycloak/terraform-provider-keycloak/keycloak/types"
"strings"

"github.com/keycloak/terraform-provider-keycloak/keycloak/types"
)

type Key struct {
Expand Down Expand Up @@ -86,7 +87,7 @@ type Realm struct {
DefaultDefaultClientScopes []string `json:"defaultDefaultClientScopes,omitempty"`
DefaultOptionalClientScopes []string `json:"defaultOptionalClientScopes,omitempty"`

BrowserSecurityHeaders BrowserSecurityHeaders `json:"browserSecurityHeaders"`
BrowserSecurityHeaders *BrowserSecurityHeaders `json:"browserSecurityHeaders,omitempty"`
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

omitempty allows us to leverage the BrowserSecurityHeader defaults from Keycloak.


BruteForceProtected bool `json:"bruteForceProtected"`
PermanentLockout bool `json:"permanentLockout"`
Expand Down
23 changes: 17 additions & 6 deletions provider/resource_keycloak_realm.go
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,7 @@ func resourceKeycloakRealm() *schema.Resource {
"security_defenses": {
Type: schema.TypeList,
Optional: true,
Computed: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
Expand Down Expand Up @@ -998,7 +999,7 @@ func getRealmFromData(data *schema.ResourceData, keycloakVersion *version.Versio
if len(headersConfig) == 1 {
headerSettings := headersConfig[0].(map[string]interface{})

realm.BrowserSecurityHeaders = keycloak.BrowserSecurityHeaders{
realm.BrowserSecurityHeaders = &keycloak.BrowserSecurityHeaders{
ContentSecurityPolicy: headerSettings["content_security_policy"].(string),
ContentSecurityPolicyReportOnly: headerSettings["content_security_policy_report_only"].(string),
StrictTransportSecurity: headerSettings["strict_transport_security"].(string),
Expand All @@ -1008,8 +1009,6 @@ func getRealmFromData(data *schema.ResourceData, keycloakVersion *version.Versio
XXSSProtection: headerSettings["x_xss_protection"].(string),
ReferrerPolicy: headerSettings["referrer_policy"].(string),
}
} else {
setDefaultSecuritySettingHeaders(realm)
}

bruteForceDetectionConfig := securityDefensesSettings["brute_force_detection"].([]interface{})
Expand All @@ -1027,7 +1026,6 @@ func getRealmFromData(data *schema.ResourceData, keycloakVersion *version.Versio
setDefaultSecuritySettingsBruteForceDetection(realm)
}
} else {
setDefaultSecuritySettingHeaders(realm)
setDefaultSecuritySettingsBruteForceDetection(realm)
}

Expand Down Expand Up @@ -1178,7 +1176,7 @@ func getRealmFromData(data *schema.ResourceData, keycloakVersion *version.Versio
}

func setDefaultSecuritySettingHeaders(realm *keycloak.Realm) {
realm.BrowserSecurityHeaders = keycloak.BrowserSecurityHeaders{
realm.BrowserSecurityHeaders = &keycloak.BrowserSecurityHeaders{
ContentSecurityPolicy: "frame-src 'self'; frame-ancestors 'self'; object-src 'none';",
ContentSecurityPolicyReportOnly: "",
StrictTransportSecurity: "max-age=31536000; includeSubDomains",
Expand Down Expand Up @@ -1309,6 +1307,14 @@ func setRealmData(data *schema.ResourceData, realm *keycloak.Realm, keycloakVers
securityDefensesSettings["brute_force_detection"] = []interface{}{getBruteForceDetectionSettings(realm)}
data.Set("security_defenses", []interface{}{securityDefensesSettings})
}
} else {
// if we do not have any configuration in the realm config, use the default config generated by Keycloak
securityDefensesSettings := make(map[string]interface{})
securityDefensesSettings["headers"] = []interface{}{getHeaderSettings(realm)}
if realm.BruteForceProtected {
securityDefensesSettings["brute_force_detection"] = []interface{}{getBruteForceDetectionSettings(realm)}
}
data.Set("security_defenses", []interface{}{securityDefensesSettings})
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This populates the tfstate with the security defenses defaults configured generated by Keycloak.

}

data.Set("password_policy", realm.PasswordPolicy)
Expand Down Expand Up @@ -1392,6 +1398,11 @@ func getBruteForceDetectionSettings(realm *keycloak.Realm) map[string]interface{
}

func getHeaderSettings(realm *keycloak.Realm) map[string]interface{} {

if realm.BrowserSecurityHeaders == nil {
return nil
}

headersSettings := make(map[string]interface{})
headersSettings["content_security_policy"] = realm.BrowserSecurityHeaders.ContentSecurityPolicy
headersSettings["content_security_policy_report_only"] = realm.BrowserSecurityHeaders.ContentSecurityPolicyReportOnly
Expand Down Expand Up @@ -1431,7 +1442,7 @@ func resourceKeycloakRealmCreate(ctx context.Context, data *schema.ResourceData,
return diag.FromErr(err)
}

setRealmData(data, realm, keycloakVersion)
data.SetId(realm.Realm)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The call to setRealmData(...) was not necessary as it is already done by resourceKeycloakRealmRead(..), however we do need to set the realm ID via SetId before.


return resourceKeycloakRealmRead(ctx, data, meta)
}
Expand Down
13 changes: 11 additions & 2 deletions provider/resource_keycloak_realm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ package provider

import (
"fmt"
"regexp"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/keycloak/terraform-provider-keycloak/keycloak"
"regexp"
"testing"
)

func TestAccKeycloakRealm_basic(t *testing.T) {
Expand Down Expand Up @@ -629,6 +630,14 @@ func TestAccKeycloakRealm_securityDefenses(t *testing.T) {
testAccCheckKeycloakRealmSecurityDefensesBruteForceDetectionFailureFactor("keycloak_realm.realm", 30),
),
},
{
Config: testKeycloakRealm_basic(realmName, realmDisplayName, realmDisplayNameHtml),
Check: resource.ComposeTestCheckFunc(
testAccCheckKeycloakRealmSecurityDefensesHeaders("keycloak_realm.realm", ""), // empty xFrameOptions
testAccCheckKeycloakRealmSecurityDefensesBruteForceDetection("keycloak_realm.realm", false),
testAccCheckKeycloakRealmSecurityDefensesBruteForceDetectionFailureFactor("keycloak_realm.realm", 30),
),
},
},
})
}
Expand Down
Loading