Skip to content

Commit 3d2f98e

Browse files
authored
feat: add valid_post_logout_redirect_uris attribute to keycloak_openid_client resource (#777)
1 parent 2159797 commit 3d2f98e

27 files changed

+372
-258
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*.so
66
*.dylib
77
terraform-provider-keycloak
8+
terraform-provider-keycloak_*
89

910
# Test binary, build with `go test -c`
1011
*.test

docs/resources/openid_client.md

+1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ resource "keycloak_openid_client" "openid_client" {
6767
- `valid_redirect_uris` - (Optional) A list of valid URIs a browser is permitted to redirect to after a successful login or logout. Simple
6868
wildcards in the form of an asterisk can be used here. This attribute must be set if either `standard_flow_enabled` or `implicit_flow_enabled`
6969
is set to `true`.
70+
- `valid_post_logout_redirect_uris` - (Optional) A list of valid URIs a browser is permitted to redirect to after a successful logout.
7071
- `web_origins` - (Optional) A list of allowed CORS origins. To permit all valid redirect URIs, add `+`. Note that this will not include the `*` wildcard. To permit all origins, explicitly add `*`."
7172
- `root_url` - (Optional) When specified, this URL is prepended to any relative URLs found within `valid_redirect_uris`, `web_origins`, and `admin_url`. NOTE: Due to limitations in the Keycloak API, when the `root_url` attribute is used, the `valid_redirect_uris`, `web_origins`, and `admin_url` attributes will be required.
7273
- `admin_url` - (Optional) URL to the admin interface of the client.

example/main.tf

+4
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,10 @@ resource "keycloak_openid_client" "test_client" {
209209
valid_redirect_uris = [
210210
"http://localhost:5555/callback",
211211
]
212+
valid_post_logout_redirect_uris = [
213+
"http://localhost:5555/post-logout",
214+
"http://localhost:5555/post-logout3",
215+
]
212216

213217
client_secret = "secret"
214218

keycloak/extra_config.go

+14-9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package keycloak
22

33
import (
44
"encoding/json"
5+
"github.com/mrparkers/terraform-provider-keycloak/keycloak/types"
56
"reflect"
67
"strconv"
78
"strings"
@@ -26,17 +27,18 @@ func unmarshalExtraConfig(data []byte, reflectValue reflect.Value, extraConfig *
2627
} else if field.Kind() == reflect.Bool {
2728
boolVal, err := strconv.ParseBool(configValue.(string))
2829
if err == nil {
29-
field.Set(reflect.ValueOf(KeycloakBoolQuoted(boolVal)))
30+
field.Set(reflect.ValueOf(types.KeycloakBoolQuoted(boolVal)))
3031
}
3132
} else if field.Kind() == reflect.TypeOf([]string{}).Kind() {
32-
var s KeycloakSliceQuoted
33-
34-
err = json.Unmarshal([]byte(configValue.(string)), &s)
35-
if err != nil {
33+
var sliceQuoted types.KeycloakSliceQuoted
34+
var sliceHashDelimited types.KeycloakSliceHashDelimited
3635

36+
if err = json.Unmarshal([]byte(configValue.(string)), &sliceQuoted); err == nil {
37+
field.Set(reflect.ValueOf(sliceQuoted))
38+
} else if err = sliceHashDelimited.UnmarshalJSON([]byte(configValue.(string))); err == nil {
39+
field.Set(reflect.ValueOf(sliceHashDelimited))
3740
}
3841

39-
field.Set(reflect.ValueOf(s))
4042
}
4143

4244
delete(*extraConfig, jsonKey)
@@ -63,10 +65,13 @@ func marshalExtraConfig(reflectValue reflect.Value, extraConfig map[string]inter
6365
if field.Kind() == reflect.String {
6466
out[jsonKey] = field.String()
6567
} else if field.Kind() == reflect.Bool {
66-
out[jsonKey] = KeycloakBoolQuoted(field.Bool())
68+
out[jsonKey] = types.KeycloakBoolQuoted(field.Bool())
6769
} else if field.Kind() == reflect.TypeOf([]string{}).Kind() {
68-
s := field.Interface().(KeycloakSliceQuoted)
69-
out[jsonKey] = s
70+
if s, ok := field.Interface().(types.KeycloakSliceQuoted); ok {
71+
out[jsonKey] = s
72+
} else if s, ok := field.Interface().(types.KeycloakSliceHashDelimited); ok {
73+
out[jsonKey] = s
74+
}
7075
}
7176
}
7277
}

keycloak/identity_provider.go

+45-44
Original file line numberDiff line numberDiff line change
@@ -3,54 +3,55 @@ package keycloak
33
import (
44
"context"
55
"fmt"
6+
"github.com/mrparkers/terraform-provider-keycloak/keycloak/types"
67
"reflect"
78
)
89

910
type IdentityProviderConfig struct {
10-
Key string `json:"key,omitempty"`
11-
HostIp string `json:"hostIp,omitempty"`
12-
UseJwksUrl KeycloakBoolQuoted `json:"useJwksUrl,omitempty"`
13-
JwksUrl string `json:"jwksUrl,omitempty"`
14-
ClientId string `json:"clientId,omitempty"`
15-
ClientSecret string `json:"clientSecret,omitempty"`
16-
DisableUserInfo KeycloakBoolQuoted `json:"disableUserInfo"`
17-
UserInfoUrl string `json:"userInfoUrl,omitempty"`
18-
HideOnLoginPage KeycloakBoolQuoted `json:"hideOnLoginPage"`
19-
NameIDPolicyFormat string `json:"nameIDPolicyFormat,omitempty"`
20-
EntityId string `json:"entityId,omitempty"`
21-
SingleLogoutServiceUrl string `json:"singleLogoutServiceUrl,omitempty"`
22-
SingleSignOnServiceUrl string `json:"singleSignOnServiceUrl,omitempty"`
23-
SigningCertificate string `json:"signingCertificate,omitempty"`
24-
SignatureAlgorithm string `json:"signatureAlgorithm,omitempty"`
25-
XmlSigKeyInfoKeyNameTransformer string `json:"xmlSigKeyInfoKeyNameTransformer,omitempty"`
26-
PostBindingAuthnRequest KeycloakBoolQuoted `json:"postBindingAuthnRequest,omitempty"`
27-
PostBindingResponse KeycloakBoolQuoted `json:"postBindingResponse,omitempty"`
28-
PostBindingLogout KeycloakBoolQuoted `json:"postBindingLogout,omitempty"`
29-
ForceAuthn KeycloakBoolQuoted `json:"forceAuthn,omitempty"`
30-
WantAuthnRequestsSigned KeycloakBoolQuoted `json:"wantAuthnRequestsSigned,omitempty"`
31-
WantAssertionsSigned KeycloakBoolQuoted `json:"wantAssertionsSigned,omitempty"`
32-
WantAssertionsEncrypted KeycloakBoolQuoted `json:"wantAssertionsEncrypted,omitempty"`
33-
BackchannelSupported KeycloakBoolQuoted `json:"backchannelSupported,omitempty"`
34-
ValidateSignature KeycloakBoolQuoted `json:"validateSignature,omitempty"`
35-
AuthorizationUrl string `json:"authorizationUrl,omitempty"`
36-
TokenUrl string `json:"tokenUrl,omitempty"`
37-
LoginHint string `json:"loginHint,omitempty"`
38-
UILocales KeycloakBoolQuoted `json:"uiLocales,omitempty"`
39-
LogoutUrl string `json:"logoutUrl,omitempty"`
40-
DefaultScope string `json:"defaultScope,omitempty"`
41-
AcceptsPromptNoneForwFrmClt KeycloakBoolQuoted `json:"acceptsPromptNoneForwardFromClient,omitempty"`
42-
HostedDomain string `json:"hostedDomain,omitempty"`
43-
UserIp KeycloakBoolQuoted `json:"userIp,omitempty"`
44-
OfflineAccess KeycloakBoolQuoted `json:"offlineAccess,omitempty"`
45-
PrincipalType string `json:"principalType,omitempty"`
46-
PrincipalAttribute string `json:"principalAttribute,omitempty"`
47-
GuiOrder string `json:"guiOrder,omitempty"`
48-
SyncMode string `json:"syncMode,omitempty"`
49-
ExtraConfig map[string]interface{} `json:"-"`
50-
AuthnContextClassRefs KeycloakSliceQuoted `json:"authnContextClassRefs,omitempty"`
51-
AuthnContextComparisonType string `json:"authnContextComparisonType,omitempty"`
52-
AuthnContextDeclRefs KeycloakSliceQuoted `json:"authnContextDeclRefs,omitempty"`
53-
Issuer string `json:"issuer,omitempty"`
11+
Key string `json:"key,omitempty"`
12+
HostIp string `json:"hostIp,omitempty"`
13+
UseJwksUrl types.KeycloakBoolQuoted `json:"useJwksUrl,omitempty"`
14+
JwksUrl string `json:"jwksUrl,omitempty"`
15+
ClientId string `json:"clientId,omitempty"`
16+
ClientSecret string `json:"clientSecret,omitempty"`
17+
DisableUserInfo types.KeycloakBoolQuoted `json:"disableUserInfo"`
18+
UserInfoUrl string `json:"userInfoUrl,omitempty"`
19+
HideOnLoginPage types.KeycloakBoolQuoted `json:"hideOnLoginPage"`
20+
NameIDPolicyFormat string `json:"nameIDPolicyFormat,omitempty"`
21+
EntityId string `json:"entityId,omitempty"`
22+
SingleLogoutServiceUrl string `json:"singleLogoutServiceUrl,omitempty"`
23+
SingleSignOnServiceUrl string `json:"singleSignOnServiceUrl,omitempty"`
24+
SigningCertificate string `json:"signingCertificate,omitempty"`
25+
SignatureAlgorithm string `json:"signatureAlgorithm,omitempty"`
26+
XmlSigKeyInfoKeyNameTransformer string `json:"xmlSigKeyInfoKeyNameTransformer,omitempty"`
27+
PostBindingAuthnRequest types.KeycloakBoolQuoted `json:"postBindingAuthnRequest,omitempty"`
28+
PostBindingResponse types.KeycloakBoolQuoted `json:"postBindingResponse,omitempty"`
29+
PostBindingLogout types.KeycloakBoolQuoted `json:"postBindingLogout,omitempty"`
30+
ForceAuthn types.KeycloakBoolQuoted `json:"forceAuthn,omitempty"`
31+
WantAuthnRequestsSigned types.KeycloakBoolQuoted `json:"wantAuthnRequestsSigned,omitempty"`
32+
WantAssertionsSigned types.KeycloakBoolQuoted `json:"wantAssertionsSigned,omitempty"`
33+
WantAssertionsEncrypted types.KeycloakBoolQuoted `json:"wantAssertionsEncrypted,omitempty"`
34+
BackchannelSupported types.KeycloakBoolQuoted `json:"backchannelSupported,omitempty"`
35+
ValidateSignature types.KeycloakBoolQuoted `json:"validateSignature,omitempty"`
36+
AuthorizationUrl string `json:"authorizationUrl,omitempty"`
37+
TokenUrl string `json:"tokenUrl,omitempty"`
38+
LoginHint string `json:"loginHint,omitempty"`
39+
UILocales types.KeycloakBoolQuoted `json:"uiLocales,omitempty"`
40+
LogoutUrl string `json:"logoutUrl,omitempty"`
41+
DefaultScope string `json:"defaultScope,omitempty"`
42+
AcceptsPromptNoneForwFrmClt types.KeycloakBoolQuoted `json:"acceptsPromptNoneForwardFromClient,omitempty"`
43+
HostedDomain string `json:"hostedDomain,omitempty"`
44+
UserIp types.KeycloakBoolQuoted `json:"userIp,omitempty"`
45+
OfflineAccess types.KeycloakBoolQuoted `json:"offlineAccess,omitempty"`
46+
PrincipalType string `json:"principalType,omitempty"`
47+
PrincipalAttribute string `json:"principalAttribute,omitempty"`
48+
GuiOrder string `json:"guiOrder,omitempty"`
49+
SyncMode string `json:"syncMode,omitempty"`
50+
ExtraConfig map[string]interface{} `json:"-"`
51+
AuthnContextClassRefs types.KeycloakSliceQuoted `json:"authnContextClassRefs,omitempty"`
52+
AuthnContextComparisonType string `json:"authnContextComparisonType,omitempty"`
53+
AuthnContextDeclRefs types.KeycloakSliceQuoted `json:"authnContextDeclRefs,omitempty"`
54+
Issuer string `json:"issuer,omitempty"`
5455
}
5556

5657
type IdentityProvider struct {

keycloak/openid_client.go

+22-20
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package keycloak
33
import (
44
"context"
55
"fmt"
6+
"github.com/mrparkers/terraform-provider-keycloak/keycloak/types"
67
"reflect"
78
)
89

@@ -58,26 +59,27 @@ type OpenidClient struct {
5859
}
5960

6061
type OpenidClientAttributes struct {
61-
PkceCodeChallengeMethod string `json:"pkce.code.challenge.method"`
62-
ExcludeSessionStateFromAuthResponse KeycloakBoolQuoted `json:"exclude.session.state.from.auth.response"`
63-
AccessTokenLifespan string `json:"access.token.lifespan"`
64-
LoginTheme string `json:"login_theme"`
65-
ClientOfflineSessionIdleTimeout string `json:"client.offline.session.idle.timeout,omitempty"`
66-
DisplayOnConsentScreen KeycloakBoolQuoted `json:"display.on.consent.screen"`
67-
ConsentScreenText string `json:"consent.screen.text"`
68-
ClientOfflineSessionMaxLifespan string `json:"client.offline.session.max.lifespan,omitempty"`
69-
ClientSessionIdleTimeout string `json:"client.session.idle.timeout,omitempty"`
70-
ClientSessionMaxLifespan string `json:"client.session.max.lifespan,omitempty"`
71-
UseRefreshTokens KeycloakBoolQuoted `json:"use.refresh.tokens"`
72-
UseRefreshTokensClientCredentials KeycloakBoolQuoted `json:"client_credentials.use_refresh_token"`
73-
BackchannelLogoutUrl string `json:"backchannel.logout.url"`
74-
FrontchannelLogoutUrl string `json:"frontchannel.logout.url"`
75-
BackchannelLogoutRevokeOfflineTokens KeycloakBoolQuoted `json:"backchannel.logout.revoke.offline.tokens"`
76-
BackchannelLogoutSessionRequired KeycloakBoolQuoted `json:"backchannel.logout.session.required"`
77-
ExtraConfig map[string]interface{} `json:"-"`
78-
Oauth2DeviceAuthorizationGrantEnabled KeycloakBoolQuoted `json:"oauth2.device.authorization.grant.enabled"`
79-
Oauth2DeviceCodeLifespan string `json:"oauth2.device.code.lifespan,omitempty"`
80-
Oauth2DevicePollingInterval string `json:"oauth2.device.polling.interval,omitempty"`
62+
PkceCodeChallengeMethod string `json:"pkce.code.challenge.method"`
63+
ExcludeSessionStateFromAuthResponse types.KeycloakBoolQuoted `json:"exclude.session.state.from.auth.response"`
64+
AccessTokenLifespan string `json:"access.token.lifespan"`
65+
LoginTheme string `json:"login_theme"`
66+
ClientOfflineSessionIdleTimeout string `json:"client.offline.session.idle.timeout,omitempty"`
67+
DisplayOnConsentScreen types.KeycloakBoolQuoted `json:"display.on.consent.screen"`
68+
ConsentScreenText string `json:"consent.screen.text"`
69+
ClientOfflineSessionMaxLifespan string `json:"client.offline.session.max.lifespan,omitempty"`
70+
ClientSessionIdleTimeout string `json:"client.session.idle.timeout,omitempty"`
71+
ClientSessionMaxLifespan string `json:"client.session.max.lifespan,omitempty"`
72+
UseRefreshTokens types.KeycloakBoolQuoted `json:"use.refresh.tokens"`
73+
UseRefreshTokensClientCredentials types.KeycloakBoolQuoted `json:"client_credentials.use_refresh_token"`
74+
BackchannelLogoutUrl string `json:"backchannel.logout.url"`
75+
FrontchannelLogoutUrl string `json:"frontchannel.logout.url"`
76+
BackchannelLogoutRevokeOfflineTokens types.KeycloakBoolQuoted `json:"backchannel.logout.revoke.offline.tokens"`
77+
BackchannelLogoutSessionRequired types.KeycloakBoolQuoted `json:"backchannel.logout.session.required"`
78+
ExtraConfig map[string]interface{} `json:"-"`
79+
Oauth2DeviceAuthorizationGrantEnabled types.KeycloakBoolQuoted `json:"oauth2.device.authorization.grant.enabled"`
80+
Oauth2DeviceCodeLifespan string `json:"oauth2.device.code.lifespan,omitempty"`
81+
Oauth2DevicePollingInterval string `json:"oauth2.device.polling.interval,omitempty"`
82+
PostLogoutRedirectUris types.KeycloakSliceHashDelimited `json:"post.logout.redirect.uris,omitempty"`
8183
}
8284

8385
type OpenidAuthenticationFlowBindingOverrides struct {

keycloak/openid_client_scope.go

+5-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package keycloak
33
import (
44
"context"
55
"fmt"
6+
"github.com/mrparkers/terraform-provider-keycloak/keycloak/types"
67
)
78

89
type OpenidClientScope struct {
@@ -12,10 +13,10 @@ type OpenidClientScope struct {
1213
Description string `json:"description"`
1314
Protocol string `json:"protocol"`
1415
Attributes struct {
15-
DisplayOnConsentScreen KeycloakBoolQuoted `json:"display.on.consent.screen"` // boolean in string form
16-
ConsentScreenText string `json:"consent.screen.text"`
17-
GuiOrder string `json:"gui.order"`
18-
IncludeInTokenScope KeycloakBoolQuoted `json:"include.in.token.scope"` // boolean in string form
16+
DisplayOnConsentScreen types.KeycloakBoolQuoted `json:"display.on.consent.screen"` // boolean in string form
17+
ConsentScreenText string `json:"consent.screen.text"`
18+
GuiOrder string `json:"gui.order"`
19+
IncludeInTokenScope types.KeycloakBoolQuoted `json:"include.in.token.scope"` // boolean in string form
1920
} `json:"attributes"`
2021
}
2122

keycloak/realm.go

+13-12
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package keycloak
33
import (
44
"context"
55
"fmt"
6+
"github.com/mrparkers/terraform-provider-keycloak/keycloak/types"
67
"strings"
78
)
89

@@ -152,18 +153,18 @@ type BrowserSecurityHeaders struct {
152153
}
153154

154155
type SmtpServer struct {
155-
StartTls KeycloakBoolQuoted `json:"starttls,omitempty"`
156-
Auth KeycloakBoolQuoted `json:"auth,omitempty"`
157-
Port string `json:"port,omitempty"`
158-
Host string `json:"host,omitempty"`
159-
ReplyTo string `json:"replyTo,omitempty"`
160-
ReplyToDisplayName string `json:"replyToDisplayName,omitempty"`
161-
From string `json:"from,omitempty"`
162-
FromDisplayName string `json:"fromDisplayName,omitempty"`
163-
EnvelopeFrom string `json:"envelopeFrom,omitempty"`
164-
Ssl KeycloakBoolQuoted `json:"ssl,omitempty"`
165-
User string `json:"user,omitempty"`
166-
Password string `json:"password,omitempty"`
156+
StartTls types.KeycloakBoolQuoted `json:"starttls,omitempty"`
157+
Auth types.KeycloakBoolQuoted `json:"auth,omitempty"`
158+
Port string `json:"port,omitempty"`
159+
Host string `json:"host,omitempty"`
160+
ReplyTo string `json:"replyTo,omitempty"`
161+
ReplyToDisplayName string `json:"replyToDisplayName,omitempty"`
162+
From string `json:"from,omitempty"`
163+
FromDisplayName string `json:"fromDisplayName,omitempty"`
164+
EnvelopeFrom string `json:"envelopeFrom,omitempty"`
165+
Ssl types.KeycloakBoolQuoted `json:"ssl,omitempty"`
166+
User string `json:"user,omitempty"`
167+
Password string `json:"password,omitempty"`
167168
}
168169

169170
func (keycloakClient *KeycloakClient) NewRealm(ctx context.Context, realm *Realm) error {

0 commit comments

Comments
 (0)