keycloakify 8.0.0-rc.3 → 9.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -54
- package/account/kcContext/KcContext.js.map +1 -1
- package/account/kcContext/createGetKcContext.js +2 -6
- package/account/kcContext/createGetKcContext.js.map +1 -1
- package/account/kcContext/kcContextMocks.js +4 -3
- package/account/kcContext/kcContextMocks.js.map +1 -1
- package/bin/constants.d.ts +7 -0
- package/bin/constants.js +10 -0
- package/bin/constants.js.map +1 -0
- package/bin/copy-keycloak-resources-to-public.js +34 -22
- package/bin/copy-keycloak-resources-to-public.js.map +1 -1
- package/bin/download-builtin-keycloak-theme.d.ts +4 -1
- package/bin/download-builtin-keycloak-theme.js +8 -6
- package/bin/download-builtin-keycloak-theme.js.map +1 -1
- package/bin/eject-keycloak-page.js +5 -3
- package/bin/eject-keycloak-page.js.map +1 -1
- package/bin/getSrcDirPath.d.ts +1 -1
- package/bin/getSrcDirPath.js +4 -4
- package/bin/getSrcDirPath.js.map +1 -1
- package/bin/initialize-email-theme.js +9 -9
- package/bin/initialize-email-theme.js.map +1 -1
- package/bin/keycloakify/BuildOptions.d.ts +8 -6
- package/bin/keycloakify/BuildOptions.js +63 -71
- package/bin/keycloakify/BuildOptions.js.map +1 -1
- package/bin/keycloakify/generateFtl/generateFtl.d.ts +2 -3
- package/bin/keycloakify/generateFtl/generateFtl.js +3 -4
- package/bin/keycloakify/generateFtl/generateFtl.js.map +1 -1
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountPages.java +33 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProvider.java +76 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProviderFactory.java +25 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountSpi.java +50 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProvider.java +424 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProviderFactory.java +51 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/Templates.java +51 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountBean.java +91 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountFederatedIdentityBean.java +157 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ApplicationsBean.java +258 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AuthorizationBean.java +515 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/FeaturesBean.java +56 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/LogBean.java +95 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/PasswordBean.java +34 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/RealmBean.java +75 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ReferrerBean.java +38 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/SessionsBean.java +93 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/TotpBean.java +125 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/UrlBean.java +121 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/AccountUrls.java +115 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormService.java +1320 -0
- package/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormServiceFactory.java +64 -0
- package/bin/keycloakify/generateJavaStackFiles/bringInAccountV1.d.ts +7 -0
- package/bin/keycloakify/generateJavaStackFiles/bringInAccountV1.js +194 -0
- package/bin/keycloakify/generateJavaStackFiles/bringInAccountV1.js.map +1 -0
- package/bin/keycloakify/{generateJavaStackFiles.d.ts → generateJavaStackFiles/generateJavaStackFiles.d.ts} +6 -6
- package/bin/keycloakify/generateJavaStackFiles/generateJavaStackFiles.js +276 -0
- package/bin/keycloakify/generateJavaStackFiles/generateJavaStackFiles.js.map +1 -0
- package/bin/keycloakify/generateJavaStackFiles/index.d.ts +1 -0
- package/bin/keycloakify/generateJavaStackFiles/index.js +18 -0
- package/bin/keycloakify/generateJavaStackFiles/index.js.map +1 -0
- package/bin/keycloakify/generateStartKeycloakTestingContainer.d.ts +1 -3
- package/bin/keycloakify/generateStartKeycloakTestingContainer.js +15 -6
- package/bin/keycloakify/generateStartKeycloakTestingContainer.js.map +1 -1
- package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.d.ts +5 -2
- package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.js +11 -8
- package/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.js.map +1 -1
- package/bin/keycloakify/generateTheme/generateMessageProperties.d.ts +1 -1
- package/bin/keycloakify/generateTheme/generateTheme.d.ts +6 -5
- package/bin/keycloakify/generateTheme/generateTheme.js +59 -49
- package/bin/keycloakify/generateTheme/generateTheme.js.map +1 -1
- package/bin/keycloakify/generateTheme/readExtraPageNames.d.ts +1 -1
- package/bin/keycloakify/generateTheme/readExtraPageNames.js.map +1 -1
- package/bin/keycloakify/generateTheme/readFieldNameUsage.d.ts +1 -1
- package/bin/keycloakify/generateTheme/readStaticResourcesUsage.d.ts +1 -1
- package/bin/keycloakify/keycloakify.js +49 -90
- package/bin/keycloakify/keycloakify.js.map +1 -1
- package/bin/keycloakify/parsedPackageJson.d.ts +29 -31
- package/bin/keycloakify/parsedPackageJson.js +7 -8
- package/bin/keycloakify/parsedPackageJson.js.map +1 -1
- package/bin/promptKeycloakVersion.js +1 -1
- package/bin/promptKeycloakVersion.js.map +1 -1
- package/bin/tools/downloadAndUnzip.d.ts +1 -1
- package/bin/tools/downloadAndUnzip.js +24 -26
- package/bin/tools/downloadAndUnzip.js.map +1 -1
- package/bin/tools/getAbsoluteAndInOsFormatPath.d.ts +4 -0
- package/bin/tools/getAbsoluteAndInOsFormatPath.js +15 -0
- package/bin/tools/getAbsoluteAndInOsFormatPath.js.map +1 -0
- package/bin/tools/pathJoin.js +1 -1
- package/bin/tools/pathJoin.js.map +1 -1
- package/login/kcContext/KcContext.js.map +1 -1
- package/login/kcContext/createGetKcContext.js +2 -6
- package/login/kcContext/createGetKcContext.js.map +1 -1
- package/login/kcContext/kcContextMocks.js +5 -4
- package/login/kcContext/kcContextMocks.js.map +1 -1
- package/package.json +92 -21
- package/src/account/kcContext/KcContext.ts +2 -1
- package/src/account/kcContext/createGetKcContext.ts +2 -7
- package/src/account/kcContext/kcContextMocks.ts +5 -3
- package/src/bin/constants.ts +9 -0
- package/src/bin/copy-keycloak-resources-to-public.ts +20 -19
- package/src/bin/download-builtin-keycloak-theme.ts +14 -6
- package/src/bin/eject-keycloak-page.ts +5 -9
- package/src/bin/getSrcDirPath.ts +4 -4
- package/src/bin/initialize-email-theme.ts +7 -7
- package/src/bin/keycloakify/BuildOptions.ts +78 -59
- package/src/bin/keycloakify/generateFtl/generateFtl.ts +4 -7
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountPages.java +33 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProvider.java +76 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountProviderFactory.java +25 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/AccountSpi.java +50 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProvider.java +424 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/FreeMarkerAccountProviderFactory.java +51 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/Templates.java +51 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountBean.java +91 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AccountFederatedIdentityBean.java +157 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ApplicationsBean.java +258 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/AuthorizationBean.java +515 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/FeaturesBean.java +56 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/LogBean.java +95 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/PasswordBean.java +34 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/RealmBean.java +75 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/ReferrerBean.java +38 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/SessionsBean.java +93 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/TotpBean.java +125 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/forms/account/freemarker/model/UrlBean.java +121 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/AccountUrls.java +115 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormService.java +1320 -0
- package/src/bin/keycloakify/generateJavaStackFiles/account-v1-java/services/resources/account/AccountFormServiceFactory.java +64 -0
- package/src/bin/keycloakify/generateJavaStackFiles/bringInAccountV1.ts +92 -0
- package/src/bin/keycloakify/generateJavaStackFiles/generateJavaStackFiles.ts +211 -0
- package/src/bin/keycloakify/generateJavaStackFiles/index.ts +1 -0
- package/src/bin/keycloakify/generateStartKeycloakTestingContainer.ts +21 -22
- package/src/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.ts +19 -15
- package/src/bin/keycloakify/generateTheme/generateMessageProperties.ts +1 -1
- package/src/bin/keycloakify/generateTheme/generateTheme.ts +78 -72
- package/src/bin/keycloakify/generateTheme/readExtraPageNames.ts +2 -1
- package/src/bin/keycloakify/generateTheme/readFieldNameUsage.ts +1 -1
- package/src/bin/keycloakify/generateTheme/readStaticResourcesUsage.ts +1 -1
- package/src/bin/keycloakify/keycloakify.ts +21 -44
- package/src/bin/keycloakify/parsedPackageJson.ts +11 -13
- package/src/bin/promptKeycloakVersion.ts +1 -1
- package/src/bin/tools/downloadAndUnzip.ts +6 -7
- package/src/bin/tools/getAbsoluteAndInOsFormatPath.ts +15 -0
- package/src/bin/tools/pathJoin.ts +1 -1
- package/src/login/kcContext/KcContext.ts +2 -1
- package/src/login/kcContext/createGetKcContext.ts +2 -7
- package/src/login/kcContext/kcContextMocks.ts +7 -5
- package/bin/keycloakify/generateJavaStackFiles.js +0 -103
- package/bin/keycloakify/generateJavaStackFiles.js.map +0 -1
- package/bin/mockTestingResourcesPath.d.ts +0 -3
- package/bin/mockTestingResourcesPath.js +0 -8
- package/bin/mockTestingResourcesPath.js.map +0 -1
- package/bin/tools/jar.d.ts +0 -33
- package/bin/tools/jar.js +0 -241
- package/bin/tools/jar.js.map +0 -1
- package/bin/tools/walk.d.ts +0 -8
- package/bin/tools/walk.js +0 -125
- package/bin/tools/walk.js.map +0 -1
- package/src/bin/keycloakify/generateJavaStackFiles.ts +0 -84
- package/src/bin/mockTestingResourcesPath.ts +0 -5
- package/src/bin/tools/jar.ts +0 -99
- package/src/bin/tools/walk.ts +0 -19
@@ -0,0 +1,424 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright 2022 Red Hat, Inc. and/or its affiliates
|
3
|
+
* and other contributors as indicated by the @author tags.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
*
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
*
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
* See the License for the specific language governing permissions and
|
15
|
+
* limitations under the License.
|
16
|
+
*/
|
17
|
+
package org.keycloak.forms.account.freemarker;
|
18
|
+
|
19
|
+
import jakarta.ws.rs.core.HttpHeaders;
|
20
|
+
import jakarta.ws.rs.core.MultivaluedMap;
|
21
|
+
import jakarta.ws.rs.core.Response;
|
22
|
+
import jakarta.ws.rs.core.Response.Status;
|
23
|
+
import jakarta.ws.rs.core.UriBuilder;
|
24
|
+
import jakarta.ws.rs.core.UriInfo;
|
25
|
+
import java.io.IOException;
|
26
|
+
import java.net.URI;
|
27
|
+
import java.text.MessageFormat;
|
28
|
+
import java.util.ArrayList;
|
29
|
+
import java.util.HashMap;
|
30
|
+
import java.util.List;
|
31
|
+
import java.util.Locale;
|
32
|
+
import java.util.Map;
|
33
|
+
import java.util.Properties;
|
34
|
+
import org.jboss.logging.Logger;
|
35
|
+
import org.keycloak.events.Event;
|
36
|
+
import org.keycloak.forms.account.AccountPages;
|
37
|
+
import org.keycloak.forms.account.AccountProvider;
|
38
|
+
import org.keycloak.forms.account.freemarker.model.AccountBean;
|
39
|
+
import org.keycloak.forms.account.freemarker.model.AccountFederatedIdentityBean;
|
40
|
+
import org.keycloak.forms.account.freemarker.model.ApplicationsBean;
|
41
|
+
import org.keycloak.forms.account.freemarker.model.AuthorizationBean;
|
42
|
+
import org.keycloak.forms.account.freemarker.model.FeaturesBean;
|
43
|
+
import org.keycloak.forms.account.freemarker.model.LogBean;
|
44
|
+
import org.keycloak.forms.account.freemarker.model.PasswordBean;
|
45
|
+
import org.keycloak.forms.account.freemarker.model.RealmBean;
|
46
|
+
import org.keycloak.forms.account.freemarker.model.ReferrerBean;
|
47
|
+
import org.keycloak.forms.account.freemarker.model.SessionsBean;
|
48
|
+
import org.keycloak.forms.account.freemarker.model.TotpBean;
|
49
|
+
import org.keycloak.forms.account.freemarker.model.UrlBean;
|
50
|
+
import org.keycloak.forms.login.MessageType;
|
51
|
+
import org.keycloak.models.KeycloakSession;
|
52
|
+
import org.keycloak.models.RealmModel;
|
53
|
+
import org.keycloak.models.UserModel;
|
54
|
+
import org.keycloak.models.UserSessionModel;
|
55
|
+
import org.keycloak.models.utils.FormMessage;
|
56
|
+
import org.keycloak.services.util.CacheControlUtil;
|
57
|
+
import org.keycloak.theme.FreeMarkerException;
|
58
|
+
import org.keycloak.theme.Theme;
|
59
|
+
import org.keycloak.theme.beans.AdvancedMessageFormatterMethod;
|
60
|
+
import org.keycloak.theme.beans.LocaleBean;
|
61
|
+
import org.keycloak.theme.beans.MessageBean;
|
62
|
+
import org.keycloak.theme.beans.MessageFormatterMethod;
|
63
|
+
import org.keycloak.theme.beans.MessagesPerFieldBean;
|
64
|
+
import org.keycloak.theme.freemarker.FreeMarkerProvider;
|
65
|
+
import org.keycloak.utils.MediaType;
|
66
|
+
import org.keycloak.utils.StringUtil;
|
67
|
+
|
68
|
+
/**
|
69
|
+
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
70
|
+
*/
|
71
|
+
public class FreeMarkerAccountProvider implements AccountProvider {
|
72
|
+
|
73
|
+
private static final Logger logger = Logger.getLogger(FreeMarkerAccountProvider.class);
|
74
|
+
|
75
|
+
protected UserModel user;
|
76
|
+
protected MultivaluedMap<String, String> profileFormData;
|
77
|
+
protected Response.Status status = Response.Status.OK;
|
78
|
+
protected RealmModel realm;
|
79
|
+
protected String[] referrer;
|
80
|
+
protected List<Event> events;
|
81
|
+
protected String stateChecker;
|
82
|
+
protected String idTokenHint;
|
83
|
+
protected List<UserSessionModel> sessions;
|
84
|
+
protected boolean identityProviderEnabled;
|
85
|
+
protected boolean eventsEnabled;
|
86
|
+
protected boolean passwordUpdateSupported;
|
87
|
+
protected boolean passwordSet;
|
88
|
+
protected KeycloakSession session;
|
89
|
+
protected FreeMarkerProvider freeMarker;
|
90
|
+
protected HttpHeaders headers;
|
91
|
+
protected Map<String, Object> attributes;
|
92
|
+
|
93
|
+
protected UriInfo uriInfo;
|
94
|
+
|
95
|
+
protected List<FormMessage> messages = null;
|
96
|
+
protected MessageType messageType = MessageType.ERROR;
|
97
|
+
private boolean authorizationSupported;
|
98
|
+
|
99
|
+
public FreeMarkerAccountProvider(KeycloakSession session) {
|
100
|
+
this.session = session;
|
101
|
+
this.freeMarker = session.getProvider(FreeMarkerProvider.class);
|
102
|
+
}
|
103
|
+
|
104
|
+
public AccountProvider setUriInfo(UriInfo uriInfo) {
|
105
|
+
this.uriInfo = uriInfo;
|
106
|
+
return this;
|
107
|
+
}
|
108
|
+
|
109
|
+
@Override
|
110
|
+
public AccountProvider setHttpHeaders(HttpHeaders httpHeaders) {
|
111
|
+
this.headers = httpHeaders;
|
112
|
+
return this;
|
113
|
+
}
|
114
|
+
|
115
|
+
@Override
|
116
|
+
public Response createResponse(AccountPages page) {
|
117
|
+
Map<String, Object> attributes = new HashMap<>();
|
118
|
+
|
119
|
+
if (this.attributes != null) {
|
120
|
+
attributes.putAll(this.attributes);
|
121
|
+
}
|
122
|
+
|
123
|
+
Theme theme;
|
124
|
+
try {
|
125
|
+
theme = getTheme();
|
126
|
+
} catch (IOException e) {
|
127
|
+
logger.error("Failed to create theme", e);
|
128
|
+
return Response.serverError().build();
|
129
|
+
}
|
130
|
+
|
131
|
+
Locale locale = session.getContext().resolveLocale(user);
|
132
|
+
Properties messagesBundle = handleThemeResources(theme, locale, attributes);
|
133
|
+
|
134
|
+
URI baseUri = uriInfo.getBaseUri();
|
135
|
+
UriBuilder baseUriBuilder = uriInfo.getBaseUriBuilder();
|
136
|
+
for (Map.Entry<String, List<String>> e : uriInfo.getQueryParameters().entrySet()) {
|
137
|
+
baseUriBuilder.queryParam(e.getKey(), e.getValue().toArray());
|
138
|
+
}
|
139
|
+
URI baseQueryUri = baseUriBuilder.build();
|
140
|
+
|
141
|
+
if (stateChecker != null) {
|
142
|
+
attributes.put("stateChecker", stateChecker);
|
143
|
+
}
|
144
|
+
|
145
|
+
handleMessages(locale, messagesBundle, attributes);
|
146
|
+
|
147
|
+
if (referrer != null) {
|
148
|
+
attributes.put("referrer", new ReferrerBean(referrer));
|
149
|
+
}
|
150
|
+
|
151
|
+
if (realm != null) {
|
152
|
+
attributes.put("realm", new RealmBean(realm));
|
153
|
+
}
|
154
|
+
|
155
|
+
attributes.put(
|
156
|
+
"url",
|
157
|
+
new UrlBean(realm, theme, baseUri, baseQueryUri, uriInfo.getRequestUri(), idTokenHint));
|
158
|
+
|
159
|
+
if (realm.isInternationalizationEnabled()) {
|
160
|
+
UriBuilder b = UriBuilder.fromUri(baseQueryUri).path(uriInfo.getPath());
|
161
|
+
attributes.put("locale", new LocaleBean(realm, locale, b, messagesBundle));
|
162
|
+
}
|
163
|
+
|
164
|
+
attributes.put(
|
165
|
+
"features",
|
166
|
+
new FeaturesBean(
|
167
|
+
identityProviderEnabled,
|
168
|
+
eventsEnabled,
|
169
|
+
passwordUpdateSupported,
|
170
|
+
authorizationSupported));
|
171
|
+
attributes.put("account", new AccountBean(user, profileFormData));
|
172
|
+
|
173
|
+
switch (page) {
|
174
|
+
case TOTP:
|
175
|
+
attributes.put("totp", new TotpBean(session, realm, user, uriInfo.getRequestUriBuilder()));
|
176
|
+
break;
|
177
|
+
case FEDERATED_IDENTITY:
|
178
|
+
attributes.put(
|
179
|
+
"federatedIdentity",
|
180
|
+
new AccountFederatedIdentityBean(
|
181
|
+
session, realm, user, uriInfo.getBaseUri(), stateChecker));
|
182
|
+
break;
|
183
|
+
case LOG:
|
184
|
+
attributes.put("log", new LogBean(events));
|
185
|
+
break;
|
186
|
+
case SESSIONS:
|
187
|
+
attributes.put("sessions", new SessionsBean(realm, sessions));
|
188
|
+
break;
|
189
|
+
case APPLICATIONS:
|
190
|
+
attributes.put("applications", new ApplicationsBean(session, realm, user));
|
191
|
+
attributes.put("advancedMsg", new AdvancedMessageFormatterMethod(locale, messagesBundle));
|
192
|
+
break;
|
193
|
+
case PASSWORD:
|
194
|
+
attributes.put("password", new PasswordBean(passwordSet));
|
195
|
+
break;
|
196
|
+
case RESOURCES:
|
197
|
+
if (!realm.isUserManagedAccessAllowed()) {
|
198
|
+
return Response.status(Status.FORBIDDEN).build();
|
199
|
+
}
|
200
|
+
attributes.put("authorization", new AuthorizationBean(session, realm, user, uriInfo));
|
201
|
+
case RESOURCE_DETAIL:
|
202
|
+
if (!realm.isUserManagedAccessAllowed()) {
|
203
|
+
return Response.status(Status.FORBIDDEN).build();
|
204
|
+
}
|
205
|
+
attributes.put("authorization", new AuthorizationBean(session, realm, user, uriInfo));
|
206
|
+
}
|
207
|
+
|
208
|
+
return processTemplate(theme, page, attributes, locale);
|
209
|
+
}
|
210
|
+
|
211
|
+
/**
|
212
|
+
* Get Theme used for page rendering.
|
213
|
+
*
|
214
|
+
* @return theme for page rendering, never null
|
215
|
+
* @throws IOException in case of Theme loading problem
|
216
|
+
*/
|
217
|
+
protected Theme getTheme() throws IOException {
|
218
|
+
return session.theme().getTheme(Theme.Type.ACCOUNT);
|
219
|
+
}
|
220
|
+
|
221
|
+
/**
|
222
|
+
* Load message bundle and place it into <code>msg</code> template attribute. Also load Theme
|
223
|
+
* properties and place them into <code>properties</code> template attribute.
|
224
|
+
*
|
225
|
+
* @param theme actual Theme to load bundle from
|
226
|
+
* @param locale to load bundle for
|
227
|
+
* @param attributes template attributes to add resources to
|
228
|
+
* @return message bundle for other use
|
229
|
+
*/
|
230
|
+
protected Properties handleThemeResources(
|
231
|
+
Theme theme, Locale locale, Map<String, Object> attributes) {
|
232
|
+
Properties messagesBundle = new Properties();
|
233
|
+
try {
|
234
|
+
if (!StringUtil.isNotBlank(realm.getDefaultLocale())) {
|
235
|
+
messagesBundle.putAll(realm.getRealmLocalizationTextsByLocale(realm.getDefaultLocale()));
|
236
|
+
}
|
237
|
+
messagesBundle.putAll(theme.getMessages(locale));
|
238
|
+
messagesBundle.putAll(realm.getRealmLocalizationTextsByLocale(locale.toLanguageTag()));
|
239
|
+
attributes.put("msg", new MessageFormatterMethod(locale, messagesBundle));
|
240
|
+
} catch (IOException e) {
|
241
|
+
logger.warn("Failed to load messages", e);
|
242
|
+
messagesBundle = new Properties();
|
243
|
+
}
|
244
|
+
try {
|
245
|
+
attributes.put("properties", theme.getProperties());
|
246
|
+
} catch (IOException e) {
|
247
|
+
logger.warn("Failed to load properties", e);
|
248
|
+
}
|
249
|
+
return messagesBundle;
|
250
|
+
}
|
251
|
+
|
252
|
+
/**
|
253
|
+
* Handle messages to be shown on the page - set them to template attributes
|
254
|
+
*
|
255
|
+
* @param locale to be used for message text loading
|
256
|
+
* @param messagesBundle to be used for message text loading
|
257
|
+
* @param attributes template attributes to messages related info to
|
258
|
+
* @see #messageType
|
259
|
+
* @see #messages
|
260
|
+
*/
|
261
|
+
protected void handleMessages(
|
262
|
+
Locale locale, Properties messagesBundle, Map<String, Object> attributes) {
|
263
|
+
MessagesPerFieldBean messagesPerField = new MessagesPerFieldBean();
|
264
|
+
if (messages != null) {
|
265
|
+
MessageBean wholeMessage = new MessageBean(null, messageType);
|
266
|
+
for (FormMessage message : this.messages) {
|
267
|
+
String formattedMessageText = formatMessage(message, messagesBundle, locale);
|
268
|
+
if (formattedMessageText != null) {
|
269
|
+
wholeMessage.appendSummaryLine(formattedMessageText);
|
270
|
+
messagesPerField.addMessage(message.getField(), formattedMessageText, messageType);
|
271
|
+
}
|
272
|
+
}
|
273
|
+
attributes.put("message", wholeMessage);
|
274
|
+
}
|
275
|
+
attributes.put("messagesPerField", messagesPerField);
|
276
|
+
}
|
277
|
+
|
278
|
+
/**
|
279
|
+
* Process FreeMarker template and prepare Response. Some fields are used for rendering also.
|
280
|
+
*
|
281
|
+
* @param theme to be used (provided by <code>getTheme()</code>)
|
282
|
+
* @param page to be rendered
|
283
|
+
* @param attributes pushed to the template
|
284
|
+
* @param locale to be used
|
285
|
+
* @return Response object to be returned to the browser, never null
|
286
|
+
*/
|
287
|
+
protected Response processTemplate(
|
288
|
+
Theme theme, AccountPages page, Map<String, Object> attributes, Locale locale) {
|
289
|
+
try {
|
290
|
+
String result = freeMarker.processTemplate(attributes, Templates.getTemplate(page), theme);
|
291
|
+
Response.ResponseBuilder builder =
|
292
|
+
Response.status(status)
|
293
|
+
.type(MediaType.TEXT_HTML_UTF_8_TYPE)
|
294
|
+
.language(locale)
|
295
|
+
.entity(result);
|
296
|
+
builder.cacheControl(CacheControlUtil.noCache());
|
297
|
+
return builder.build();
|
298
|
+
} catch (FreeMarkerException e) {
|
299
|
+
logger.error("Failed to process template", e);
|
300
|
+
return Response.serverError().build();
|
301
|
+
}
|
302
|
+
}
|
303
|
+
|
304
|
+
public AccountProvider setPasswordSet(boolean passwordSet) {
|
305
|
+
this.passwordSet = passwordSet;
|
306
|
+
return this;
|
307
|
+
}
|
308
|
+
|
309
|
+
protected void setMessage(MessageType type, String message, Object... parameters) {
|
310
|
+
messageType = type;
|
311
|
+
messages = new ArrayList<>();
|
312
|
+
messages.add(new FormMessage(null, message, parameters));
|
313
|
+
}
|
314
|
+
|
315
|
+
protected String formatMessage(FormMessage message, Properties messagesBundle, Locale locale) {
|
316
|
+
if (message == null) return null;
|
317
|
+
if (messagesBundle.containsKey(message.getMessage())) {
|
318
|
+
return new MessageFormat(messagesBundle.getProperty(message.getMessage()), locale)
|
319
|
+
.format(message.getParameters());
|
320
|
+
} else {
|
321
|
+
return message.getMessage();
|
322
|
+
}
|
323
|
+
}
|
324
|
+
|
325
|
+
@Override
|
326
|
+
public AccountProvider setErrors(Response.Status status, List<FormMessage> messages) {
|
327
|
+
this.status = status;
|
328
|
+
this.messageType = MessageType.ERROR;
|
329
|
+
this.messages = new ArrayList<>(messages);
|
330
|
+
return this;
|
331
|
+
}
|
332
|
+
|
333
|
+
@Override
|
334
|
+
public AccountProvider setError(Response.Status status, String message, Object... parameters) {
|
335
|
+
this.status = status;
|
336
|
+
setMessage(MessageType.ERROR, message, parameters);
|
337
|
+
return this;
|
338
|
+
}
|
339
|
+
|
340
|
+
@Override
|
341
|
+
public AccountProvider setSuccess(String message, Object... parameters) {
|
342
|
+
setMessage(MessageType.SUCCESS, message, parameters);
|
343
|
+
return this;
|
344
|
+
}
|
345
|
+
|
346
|
+
@Override
|
347
|
+
public AccountProvider setWarning(String message, Object... parameters) {
|
348
|
+
setMessage(MessageType.WARNING, message, parameters);
|
349
|
+
return this;
|
350
|
+
}
|
351
|
+
|
352
|
+
@Override
|
353
|
+
public AccountProvider setUser(UserModel user) {
|
354
|
+
this.user = user;
|
355
|
+
return this;
|
356
|
+
}
|
357
|
+
|
358
|
+
@Override
|
359
|
+
public AccountProvider setProfileFormData(MultivaluedMap<String, String> formData) {
|
360
|
+
this.profileFormData = formData;
|
361
|
+
return this;
|
362
|
+
}
|
363
|
+
|
364
|
+
@Override
|
365
|
+
public AccountProvider setRealm(RealmModel realm) {
|
366
|
+
this.realm = realm;
|
367
|
+
return this;
|
368
|
+
}
|
369
|
+
|
370
|
+
@Override
|
371
|
+
public AccountProvider setReferrer(String[] referrer) {
|
372
|
+
this.referrer = referrer;
|
373
|
+
return this;
|
374
|
+
}
|
375
|
+
|
376
|
+
@Override
|
377
|
+
public AccountProvider setEvents(List<Event> events) {
|
378
|
+
this.events = events;
|
379
|
+
return this;
|
380
|
+
}
|
381
|
+
|
382
|
+
@Override
|
383
|
+
public AccountProvider setSessions(List<UserSessionModel> sessions) {
|
384
|
+
this.sessions = sessions;
|
385
|
+
return this;
|
386
|
+
}
|
387
|
+
|
388
|
+
@Override
|
389
|
+
public AccountProvider setStateChecker(String stateChecker) {
|
390
|
+
this.stateChecker = stateChecker;
|
391
|
+
return this;
|
392
|
+
}
|
393
|
+
|
394
|
+
@Override
|
395
|
+
public AccountProvider setIdTokenHint(String idTokenHint) {
|
396
|
+
this.idTokenHint = idTokenHint;
|
397
|
+
return this;
|
398
|
+
}
|
399
|
+
|
400
|
+
@Override
|
401
|
+
public AccountProvider setFeatures(
|
402
|
+
boolean identityProviderEnabled,
|
403
|
+
boolean eventsEnabled,
|
404
|
+
boolean passwordUpdateSupported,
|
405
|
+
boolean authorizationSupported) {
|
406
|
+
this.identityProviderEnabled = identityProviderEnabled;
|
407
|
+
this.eventsEnabled = eventsEnabled;
|
408
|
+
this.passwordUpdateSupported = passwordUpdateSupported;
|
409
|
+
this.authorizationSupported = authorizationSupported;
|
410
|
+
return this;
|
411
|
+
}
|
412
|
+
|
413
|
+
@Override
|
414
|
+
public AccountProvider setAttribute(String key, String value) {
|
415
|
+
if (attributes == null) {
|
416
|
+
attributes = new HashMap<>();
|
417
|
+
}
|
418
|
+
attributes.put(key, value);
|
419
|
+
return this;
|
420
|
+
}
|
421
|
+
|
422
|
+
@Override
|
423
|
+
public void close() {}
|
424
|
+
}
|
@@ -0,0 +1,51 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
3
|
+
* and other contributors as indicated by the @author tags.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
*
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
*
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
* See the License for the specific language governing permissions and
|
15
|
+
* limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
package org.keycloak.forms.account.freemarker;
|
19
|
+
|
20
|
+
import com.google.auto.service.AutoService;
|
21
|
+
import org.keycloak.Config;
|
22
|
+
import org.keycloak.forms.account.AccountProvider;
|
23
|
+
import org.keycloak.forms.account.AccountProviderFactory;
|
24
|
+
import org.keycloak.models.KeycloakSession;
|
25
|
+
import org.keycloak.models.KeycloakSessionFactory;
|
26
|
+
|
27
|
+
/**
|
28
|
+
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
29
|
+
*/
|
30
|
+
@AutoService(AccountProviderFactory.class)
|
31
|
+
public class FreeMarkerAccountProviderFactory implements AccountProviderFactory {
|
32
|
+
|
33
|
+
@Override
|
34
|
+
public AccountProvider create(KeycloakSession session) {
|
35
|
+
return new FreeMarkerAccountProvider(session);
|
36
|
+
}
|
37
|
+
|
38
|
+
@Override
|
39
|
+
public void init(Config.Scope config) {}
|
40
|
+
|
41
|
+
@Override
|
42
|
+
public void postInit(KeycloakSessionFactory factory) {}
|
43
|
+
|
44
|
+
@Override
|
45
|
+
public void close() {}
|
46
|
+
|
47
|
+
@Override
|
48
|
+
public String getId() {
|
49
|
+
return "freemarker";
|
50
|
+
}
|
51
|
+
}
|
@@ -0,0 +1,51 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
3
|
+
* and other contributors as indicated by the @author tags.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
*
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
*
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
* See the License for the specific language governing permissions and
|
15
|
+
* limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
package org.keycloak.forms.account.freemarker;
|
19
|
+
|
20
|
+
import org.keycloak.forms.account.AccountPages;
|
21
|
+
|
22
|
+
/**
|
23
|
+
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
24
|
+
*/
|
25
|
+
public class Templates {
|
26
|
+
|
27
|
+
public static String getTemplate(AccountPages page) {
|
28
|
+
switch (page) {
|
29
|
+
case ACCOUNT:
|
30
|
+
return "account.ftl";
|
31
|
+
case PASSWORD:
|
32
|
+
return "password.ftl";
|
33
|
+
case TOTP:
|
34
|
+
return "totp.ftl";
|
35
|
+
case FEDERATED_IDENTITY:
|
36
|
+
return "federatedIdentity.ftl";
|
37
|
+
case LOG:
|
38
|
+
return "log.ftl";
|
39
|
+
case SESSIONS:
|
40
|
+
return "sessions.ftl";
|
41
|
+
case APPLICATIONS:
|
42
|
+
return "applications.ftl";
|
43
|
+
case RESOURCES:
|
44
|
+
return "resources.ftl";
|
45
|
+
case RESOURCE_DETAIL:
|
46
|
+
return "resource-detail.ftl";
|
47
|
+
default:
|
48
|
+
throw new IllegalArgumentException();
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
@@ -0,0 +1,91 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
3
|
+
* and other contributors as indicated by the @author tags.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
*
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
*
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
* See the License for the specific language governing permissions and
|
15
|
+
* limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
package org.keycloak.forms.account.freemarker.model;
|
19
|
+
|
20
|
+
import jakarta.ws.rs.core.MultivaluedMap;
|
21
|
+
import java.util.HashMap;
|
22
|
+
import java.util.List;
|
23
|
+
import java.util.Map;
|
24
|
+
import org.jboss.logging.Logger;
|
25
|
+
import org.keycloak.models.Constants;
|
26
|
+
import org.keycloak.models.UserModel;
|
27
|
+
|
28
|
+
/**
|
29
|
+
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
30
|
+
*/
|
31
|
+
public class AccountBean {
|
32
|
+
|
33
|
+
private static final Logger logger = Logger.getLogger(AccountBean.class);
|
34
|
+
|
35
|
+
private final UserModel user;
|
36
|
+
private final MultivaluedMap<String, String> profileFormData;
|
37
|
+
|
38
|
+
// TODO: More proper multi-value attribute support
|
39
|
+
private final Map<String, String> attributes = new HashMap<>();
|
40
|
+
|
41
|
+
public AccountBean(UserModel user, MultivaluedMap<String, String> profileFormData) {
|
42
|
+
this.user = user;
|
43
|
+
this.profileFormData = profileFormData;
|
44
|
+
|
45
|
+
for (Map.Entry<String, List<String>> attr : user.getAttributes().entrySet()) {
|
46
|
+
List<String> attrValue = attr.getValue();
|
47
|
+
if (attrValue.size() > 0) {
|
48
|
+
attributes.put(attr.getKey(), attrValue.get(0));
|
49
|
+
}
|
50
|
+
|
51
|
+
if (attrValue.size() > 1) {
|
52
|
+
logger.warnf(
|
53
|
+
"There are more values for attribute '%s' of user '%s' . Will display just first value",
|
54
|
+
attr.getKey(), user.getUsername());
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
if (profileFormData != null) {
|
59
|
+
for (String key : profileFormData.keySet()) {
|
60
|
+
if (key.startsWith(Constants.USER_ATTRIBUTES_PREFIX)) {
|
61
|
+
String attribute = key.substring(Constants.USER_ATTRIBUTES_PREFIX.length());
|
62
|
+
attributes.put(attribute, profileFormData.getFirst(key));
|
63
|
+
}
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
public String getFirstName() {
|
69
|
+
return profileFormData != null ? profileFormData.getFirst("firstName") : user.getFirstName();
|
70
|
+
}
|
71
|
+
|
72
|
+
public String getLastName() {
|
73
|
+
return profileFormData != null ? profileFormData.getFirst("lastName") : user.getLastName();
|
74
|
+
}
|
75
|
+
|
76
|
+
public String getUsername() {
|
77
|
+
if (profileFormData != null && profileFormData.containsKey("username")) {
|
78
|
+
return profileFormData.getFirst("username");
|
79
|
+
} else {
|
80
|
+
return user.getUsername();
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
public String getEmail() {
|
85
|
+
return profileFormData != null ? profileFormData.getFirst("email") : user.getEmail();
|
86
|
+
}
|
87
|
+
|
88
|
+
public Map<String, String> getAttributes() {
|
89
|
+
return attributes;
|
90
|
+
}
|
91
|
+
}
|