Skip to content

Commit 0afe0b2

Browse files
authored
1067 Add first broker login flow to authentication flow bindings (#1084)
* 1067 Add first broker login flow to authentication flow bindings Signed-off-by: Sebastian Schuster <[email protected]> * Fixed failures with Keycloak < 24 Signed-off-by: Sebastian Schuster <[email protected]> --------- Signed-off-by: Sebastian Schuster <[email protected]>
1 parent 93db672 commit 0afe0b2

7 files changed

+85
-18
lines changed

docs/resources/authentication_bindings.md

+1
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,4 @@ resource "keycloak_authentication_bindings" "browser_authentication_binding" {
6666
- `reset_credentials_flow` - (Optional) The alias of the flow to assign to the realm ResetCredentialsFlow.
6767
- `client_authentication_flow` - (Optional) The alias of the flow to assign to the realm ClientAuthenticationFlow.
6868
- `docker_authentication_flow` - (Optional) The alias of the flow to assign to the realm DockerAuthenticationFlow.
69+
- `first_broker_login_flow` - (Optional) The alias of the flow to assign to the realm FirstBrokerLoginFlow (since Keycloak 24).

docs/resources/realm.md

+1
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ The arguments below can be used to configure authentication flow bindings:
208208
- `reset_credentials_flow` - (Optional) The desired flow to use when a user attempts to reset their credentials. Defaults to `reset credentials`.
209209
- `client_authentication_flow` - (Optional) The desired flow for client authentication. Defaults to `clients`.
210210
- `docker_authentication_flow` - (Optional) The desired flow for Docker authentication. Defaults to `docker auth`.
211+
- `first_broker_login_flow` - (Optional) The desired flow for First Broker Login (since Keycloak 24). Defaults to `first broker login`.
211212

212213
### OTP Policy
213214

keycloak/realm.go

+1
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ type Realm struct {
106106
ResetCredentialsFlow *string `json:"resetCredentialsFlow,omitempty"`
107107
ClientAuthenticationFlow *string `json:"clientAuthenticationFlow,omitempty"`
108108
DockerAuthenticationFlow *string `json:"dockerAuthenticationFlow,omitempty"`
109+
FirstBrokerLoginFlow *string `json:"firstBrokerLoginFlow,omitempty"`
109110

110111
// OTP Policy
111112
OTPPolicyAlgorithm string `json:"otpPolicyAlgorithm,omitempty"`

provider/data_source_keycloak_realm.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,11 @@ func dataSourceKeycloakRealm() *schema.Resource {
478478
Description: "Which flow should be used for DockerAuthenticationFlow",
479479
Computed: true,
480480
},
481+
"first_broker_login_flow": {
482+
Type: schema.TypeString,
483+
Description: "Which flow should be used for FirstBrokerLoginFlow",
484+
Computed: true,
485+
},
481486
"attributes": {
482487
Type: schema.TypeMap,
483488
Optional: true,
@@ -536,6 +541,7 @@ func dataSourceKeycloakRealm() *schema.Resource {
536541

537542
func dataSourceKeycloakRealmRead(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
538543
keycloakClient := meta.(*keycloak.KeycloakClient)
544+
keycloakVersion := keycloakClient.Version()
539545

540546
realmName := data.Get("realm").(string)
541547

@@ -544,7 +550,7 @@ func dataSourceKeycloakRealmRead(ctx context.Context, data *schema.ResourceData,
544550
return diag.FromErr(err)
545551
}
546552

547-
setRealmData(data, realm)
553+
setRealmData(data, realm, keycloakVersion)
548554

549555
return nil
550556
}

provider/resource_keycloak_authentication_bindings.go

+25-8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package provider
22

33
import (
44
"context"
5+
"github.com/hashicorp/go-version"
56
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
67
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
78
"github.com/keycloak/terraform-provider-keycloak/keycloak"
@@ -55,38 +56,51 @@ func resourceKeycloakAuthenticationBindings() *schema.Resource {
5556
Optional: true,
5657
Computed: true,
5758
},
59+
"first_broker_login_flow": {
60+
Type: schema.TypeString,
61+
Description: "Which flow should be used for FirstBrokerLoginFlow",
62+
Optional: true,
63+
Computed: true,
64+
},
5865
},
5966
}
6067
}
6168

62-
func setAuthenticationBindingsData(data *schema.ResourceData, realm *keycloak.Realm) {
69+
func setAuthenticationBindingsData(data *schema.ResourceData, realm *keycloak.Realm, keycloakVersion *version.Version) {
6370
data.SetId(realm.Realm)
6471
data.Set("browser_flow", realm.BrowserFlow)
6572
data.Set("registration_flow", realm.RegistrationFlow)
6673
data.Set("direct_grant_flow", realm.DirectGrantFlow)
6774
data.Set("reset_credentials_flow", realm.ResetCredentialsFlow)
6875
data.Set("client_authentication_flow", realm.ClientAuthenticationFlow)
6976
data.Set("docker_authentication_flow", realm.DockerAuthenticationFlow)
77+
if keycloakVersion.GreaterThanOrEqual(keycloak.Version_24.AsVersion()) {
78+
data.Set("first_broker_login_flow", realm.FirstBrokerLoginFlow)
79+
}
7080
}
7181

72-
func resetAuthenticationBindingsForRealm(realm *keycloak.Realm) {
82+
func resetAuthenticationBindingsForRealm(realm *keycloak.Realm, keycloakVersion *version.Version) {
7383
realm.BrowserFlow = stringPointer("browser")
7484
realm.RegistrationFlow = stringPointer("registration")
7585
realm.DirectGrantFlow = stringPointer("direct grant")
7686
realm.ResetCredentialsFlow = stringPointer("reset credentials")
7787
realm.ClientAuthenticationFlow = stringPointer("clients")
7888
realm.DockerAuthenticationFlow = stringPointer("docker auth")
89+
if keycloakVersion.GreaterThanOrEqual(keycloak.Version_24.AsVersion()) {
90+
realm.FirstBrokerLoginFlow = stringPointer("first broker login")
91+
}
7992
}
8093

8194
func resourceKeycloakAuthenticationBindingsCreate(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
8295
keycloakClient := meta.(*keycloak.KeycloakClient)
96+
keycloakVersion := keycloakClient.Version()
8397

8498
realm, err := keycloakClient.GetRealm(ctx, data.Get("realm_id").(string))
8599
if err != nil {
86100
return diag.FromErr(err)
87101
}
88102

89-
setRealmFlowBindings(data, realm)
103+
setRealmFlowBindings(data, realm, keycloakVersion)
90104

91105
err = keycloakClient.ValidateRealm(ctx, realm)
92106
if err != nil {
@@ -103,33 +117,35 @@ func resourceKeycloakAuthenticationBindingsCreate(ctx context.Context, data *sch
103117
return diag.FromErr(err)
104118
}
105119

106-
setAuthenticationBindingsData(data, realm)
120+
setAuthenticationBindingsData(data, realm, keycloakVersion)
107121

108122
return resourceKeycloakAuthenticationBindingsRead(ctx, data, meta)
109123
}
110124

111125
func resourceKeycloakAuthenticationBindingsRead(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
112126
keycloakClient := meta.(*keycloak.KeycloakClient)
127+
keycloakVersion := keycloakClient.Version()
113128

114129
realm, err := keycloakClient.GetRealm(ctx, data.Id())
115130
if err != nil {
116131
return handleNotFoundError(ctx, err, data)
117132
}
118133

119-
setAuthenticationBindingsData(data, realm)
134+
setAuthenticationBindingsData(data, realm, keycloakVersion)
120135

121136
return nil
122137
}
123138

124139
func resourceKeycloakAuthenticationBindingsDelete(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
125140
keycloakClient := meta.(*keycloak.KeycloakClient)
141+
keycloakVersion := keycloakClient.Version()
126142

127143
realm, err := keycloakClient.GetRealm(ctx, data.Id())
128144
if err != nil {
129145
return diag.FromErr(err)
130146
}
131147

132-
resetAuthenticationBindingsForRealm(realm)
148+
resetAuthenticationBindingsForRealm(realm, keycloakVersion)
133149

134150
err = keycloakClient.UpdateRealm(ctx, realm)
135151
if err != nil {
@@ -141,13 +157,14 @@ func resourceKeycloakAuthenticationBindingsDelete(ctx context.Context, data *sch
141157

142158
func resourceKeycloakAuthenticationBindingsUpdate(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
143159
keycloakClient := meta.(*keycloak.KeycloakClient)
160+
keycloakVersion := keycloakClient.Version()
144161

145162
realm, err := keycloakClient.GetRealm(ctx, data.Id())
146163
if err != nil {
147164
return diag.FromErr(err)
148165
}
149166

150-
setRealmFlowBindings(data, realm)
167+
setRealmFlowBindings(data, realm, keycloakVersion)
151168

152169
err = keycloakClient.ValidateRealm(ctx, realm)
153170
if err != nil {
@@ -159,7 +176,7 @@ func resourceKeycloakAuthenticationBindingsUpdate(ctx context.Context, data *sch
159176
return diag.FromErr(err)
160177
}
161178

162-
setAuthenticationBindingsData(data, realm)
179+
setAuthenticationBindingsData(data, realm, keycloakVersion)
163180

164181
return resourceKeycloakAuthenticationBindingsRead(ctx, data, meta)
165182
}

provider/resource_keycloak_authentication_bindings_test.go

+19
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package provider
33
import (
44
"fmt"
55
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
6+
"github.com/keycloak/terraform-provider-keycloak/keycloak"
67
"reflect"
78
"testing"
89

@@ -124,6 +125,24 @@ func TestAccKeycloakAuthenticationBindings_dockerAuthenticationGrant(t *testing.
124125
})
125126
}
126127

128+
func TestAccKeycloakAuthenticationBindings_firstBrokerLoginFlow(t *testing.T) {
129+
skipIfVersionIsLessThan(testCtx, t, keycloakClient, keycloak.Version_24)
130+
131+
flow := "first_broker_login_flow"
132+
flowAlias := "firstBrokerLoginCopyFlow"
133+
134+
resource.Test(t, resource.TestCase{
135+
ProviderFactories: testAccProviderFactories,
136+
PreCheck: func() { testAccPreCheck(t) },
137+
Steps: []resource.TestStep{
138+
{
139+
Config: testKeycloakAuthenticationBindings(testAccRealm.Realm, flow, flowAlias),
140+
Check: testAccCheckKeycloakAuthenticationBindingBrowserSet(testAccRealm.Realm, "FirstBrokerLoginFlow", flowAlias),
141+
},
142+
},
143+
})
144+
}
145+
127146
func TestAccKeycloakAuthenticationBindings_existingFlow(t *testing.T) {
128147
flow := "browser_flow"
129148
flowAlias := "browser"

provider/resource_keycloak_realm.go

+31-9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package provider
22

33
import (
44
"context"
5+
"github.com/hashicorp/go-version"
56
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
67
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
78
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
@@ -610,6 +611,12 @@ func resourceKeycloakRealm() *schema.Resource {
610611
Optional: true,
611612
Computed: true,
612613
},
614+
"first_broker_login_flow": {
615+
Type: schema.TypeString,
616+
Description: "Which flow should be used for FirstBrokerLoginFlow",
617+
Optional: true,
618+
Computed: true,
619+
},
613620

614621
// misc attributes
615622
"attributes": {
@@ -684,7 +691,7 @@ func getRealmSMTPPasswordFromData(data *schema.ResourceData) (string, bool) {
684691
return "", false
685692
}
686693

687-
func setRealmFlowBindings(data *schema.ResourceData, realm *keycloak.Realm) {
694+
func setRealmFlowBindings(data *schema.ResourceData, realm *keycloak.Realm, keycloakVersion *version.Version) {
688695
if flow, ok := data.GetOk("browser_flow"); ok {
689696
realm.BrowserFlow = stringPointer(flow.(string))
690697
} else {
@@ -720,9 +727,17 @@ func setRealmFlowBindings(data *schema.ResourceData, realm *keycloak.Realm) {
720727
} else {
721728
realm.DockerAuthenticationFlow = stringPointer("docker auth")
722729
}
730+
731+
if keycloakVersion.GreaterThanOrEqual(keycloak.Version_24.AsVersion()) {
732+
if flow, ok := data.GetOk("first_broker_login_flow"); ok {
733+
realm.FirstBrokerLoginFlow = stringPointer(flow.(string))
734+
} else {
735+
realm.FirstBrokerLoginFlow = stringPointer("first broker login")
736+
}
737+
}
723738
}
724739

725-
func getRealmFromData(data *schema.ResourceData) (*keycloak.Realm, error) {
740+
func getRealmFromData(data *schema.ResourceData, keycloakVersion *version.Version) (*keycloak.Realm, error) {
726741
internationalizationEnabled := false
727742
supportLocales := make([]string, 0)
728743
defaultLocale := ""
@@ -1012,7 +1027,7 @@ func getRealmFromData(data *schema.ResourceData) (*keycloak.Realm, error) {
10121027
realm.PasswordPolicy = passwordPolicy.(string)
10131028
}
10141029

1015-
setRealmFlowBindings(data, realm)
1030+
setRealmFlowBindings(data, realm, keycloakVersion)
10161031

10171032
attributes := map[string]interface{}{}
10181033
if v, ok := data.GetOk("attributes"); ok {
@@ -1176,7 +1191,7 @@ func setDefaultSecuritySettingsBruteForceDetection(realm *keycloak.Realm) {
11761191
realm.MaxDeltaTimeSeconds = 43200
11771192
}
11781193

1179-
func setRealmData(data *schema.ResourceData, realm *keycloak.Realm) {
1194+
func setRealmData(data *schema.ResourceData, realm *keycloak.Realm, keycloakVersion *version.Version) {
11801195
data.SetId(realm.Realm)
11811196

11821197
data.Set("realm", realm.Realm)
@@ -1296,6 +1311,10 @@ func setRealmData(data *schema.ResourceData, realm *keycloak.Realm) {
12961311
data.Set("client_authentication_flow", realm.ClientAuthenticationFlow)
12971312
data.Set("docker_authentication_flow", realm.DockerAuthenticationFlow)
12981313

1314+
if keycloakVersion.GreaterThanOrEqual(keycloak.Version_24.AsVersion()) {
1315+
data.Set("first_broker_login_flow", realm.FirstBrokerLoginFlow)
1316+
}
1317+
12991318
//WebAuthn
13001319
webAuthnPolicy := make(map[string]interface{})
13011320
webAuthnPolicy["acceptable_aaguids"] = realm.WebAuthnPolicyAcceptableAaguids
@@ -1375,8 +1394,9 @@ func getHeaderSettings(realm *keycloak.Realm) map[string]interface{} {
13751394

13761395
func resourceKeycloakRealmCreate(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
13771396
keycloakClient := meta.(*keycloak.KeycloakClient)
1397+
keycloakVersion := keycloakClient.Version()
13781398

1379-
realm, err := getRealmFromData(data)
1399+
realm, err := getRealmFromData(data, keycloakVersion)
13801400
if err != nil {
13811401
return diag.FromErr(err)
13821402
}
@@ -1396,13 +1416,14 @@ func resourceKeycloakRealmCreate(ctx context.Context, data *schema.ResourceData,
13961416
return diag.FromErr(err)
13971417
}
13981418

1399-
setRealmData(data, realm)
1419+
setRealmData(data, realm, keycloakVersion)
14001420

14011421
return resourceKeycloakRealmRead(ctx, data, meta)
14021422
}
14031423

14041424
func resourceKeycloakRealmRead(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
14051425
keycloakClient := meta.(*keycloak.KeycloakClient)
1426+
keycloakVersion := keycloakClient.Version()
14061427

14071428
realm, err := keycloakClient.GetRealm(ctx, data.Id())
14081429
if err != nil {
@@ -1414,15 +1435,16 @@ func resourceKeycloakRealmRead(ctx context.Context, data *schema.ResourceData, m
14141435
realm.SmtpServer.Password = smtpPassword
14151436
}
14161437

1417-
setRealmData(data, realm)
1438+
setRealmData(data, realm, keycloakVersion)
14181439

14191440
return nil
14201441
}
14211442

14221443
func resourceKeycloakRealmUpdate(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
14231444
keycloakClient := meta.(*keycloak.KeycloakClient)
1445+
keycloakVersion := keycloakClient.Version()
14241446

1425-
realm, err := getRealmFromData(data)
1447+
realm, err := getRealmFromData(data, keycloakVersion)
14261448
if err != nil {
14271449
return diag.FromErr(err)
14281450
}
@@ -1437,7 +1459,7 @@ func resourceKeycloakRealmUpdate(ctx context.Context, data *schema.ResourceData,
14371459
return diag.FromErr(err)
14381460
}
14391461

1440-
setRealmData(data, realm)
1462+
setRealmData(data, realm, keycloakVersion)
14411463

14421464
return nil
14431465
}

0 commit comments

Comments
 (0)