1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.myfaces.tobago.internal.config;
21
22 import org.apache.myfaces.tobago.config.TobagoConfig;
23 import org.apache.myfaces.tobago.context.Theme;
24 import org.apache.myfaces.tobago.context.ThemeImpl;
25 import org.apache.myfaces.tobago.exception.TobagoConfigurationException;
26 import org.apache.myfaces.tobago.sanitizer.Sanitizer;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 import javax.faces.application.Application;
31 import javax.faces.context.FacesContext;
32 import java.lang.invoke.MethodHandles;
33 import java.util.ArrayList;
34 import java.util.Collections;
35 import java.util.HashMap;
36 import java.util.HashSet;
37 import java.util.List;
38 import java.util.Map;
39 import java.util.Set;
40
41
42
43
44
45
46
47
48
49
50
51 public class TobagoConfigImpl extends TobagoConfig {
52
53 private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
54
55 private List<Theme> supportedThemes;
56 private List<String> supportedThemeNames;
57 private Theme defaultTheme;
58 private String defaultThemeName;
59 private Map<String, ThemeImpl> availableThemes;
60 private boolean createSessionSecret;
61 private boolean checkSessionSecret;
62 private boolean preventFrameAttacks;
63 private final ContentSecurityPolicy contentSecurityPolicy;
64 private SecurityAnnotation securityAnnotation;
65 private boolean setNosniffHeader;
66 private Map<String, String> defaultValidatorInfo;
67 private Sanitizer sanitizer;
68 private boolean decodeLineFeed;
69 private Map<String, String> mimeTypes;
70
71 private boolean locked = false;
72
73 protected TobagoConfigImpl(String fixme) {
74 supportedThemeNames = new ArrayList<>();
75 supportedThemes = new ArrayList<>();
76 availableThemes = new HashMap<>();
77 createSessionSecret = true;
78 checkSessionSecret = true;
79 preventFrameAttacks = true;
80 setNosniffHeader = true;
81 securityAnnotation = SecurityAnnotation.disable;
82 decodeLineFeed = true;
83 contentSecurityPolicy = new ContentSecurityPolicy(ContentSecurityPolicy.Mode.OFF.getValue());
84 mimeTypes = new HashMap<>();
85 }
86
87
88
89
90 protected void lock() {
91 locked = true;
92 supportedThemes = Collections.unmodifiableList(supportedThemes);
93 for (final Theme theme : supportedThemes) {
94 ((ThemeImpl) theme).lock();
95 }
96 supportedThemeNames = Collections.unmodifiableList(supportedThemeNames);
97 availableThemes = Collections.unmodifiableMap(availableThemes);
98
99 contentSecurityPolicy.lock();
100
101 mimeTypes = Collections.unmodifiableMap(mimeTypes);
102 }
103
104 private void checkUnlocked() throws IllegalStateException {
105 if (locked) {
106 throw new TobagoConfigurationException("The configuration must not be changed after initialization!");
107 }
108 }
109
110 protected void addSupportedThemeName(final String name) {
111 checkUnlocked();
112 supportedThemeNames.add(name);
113 }
114
115
116 protected void resolveThemes() {
117 checkUnlocked();
118
119 if (defaultThemeName != null) {
120 defaultTheme = availableThemes.get(defaultThemeName);
121 checkThemeIsAvailable(defaultThemeName, defaultTheme);
122 if (LOG.isDebugEnabled()) {
123 LOG.debug("name = '{}'", defaultThemeName);
124 LOG.debug("defaultTheme = '{}'", defaultTheme);
125 }
126 } else {
127 int deep = 0;
128 for (final Map.Entry<String, ThemeImpl> entry : availableThemes.entrySet()) {
129 final Theme theme = entry.getValue();
130 if (theme.getFallbackList().size() > deep) {
131 defaultTheme = theme;
132 deep = theme.getFallbackList().size();
133 }
134 }
135 if (defaultTheme == null) {
136 final String error = "Did not found any theme! "
137 + "Please ensure you have a tobago-config.xml with a theme-definition in your "
138 + "theme JAR. Please add a theme JAR to your classpath. Usually "
139 + "tobago-theme-standard.jar in WEB-INF/lib";
140 LOG.error(error);
141 throw new TobagoConfigurationException(error);
142 } else {
143 if (LOG.isInfoEnabled()) {
144 LOG.info("Using default Theme {}", defaultTheme.getName());
145 }
146 }
147 }
148 if (!supportedThemeNames.isEmpty()) {
149 for (final String name : supportedThemeNames) {
150 final Theme theme = availableThemes.get(name);
151 checkThemeIsAvailable(name, theme);
152 supportedThemes.add(theme);
153 if (LOG.isDebugEnabled()) {
154 LOG.debug("name = '{}'", name);
155 LOG.debug("supportedThemes.last() = '{}'", supportedThemes.get(supportedThemes.size() - 1));
156 }
157 }
158 }
159 }
160
161 private void checkThemeIsAvailable(final String name, final Theme theme) {
162 if (theme == null) {
163 final String error = "Theme not found! name: '" + name + "'. "
164 + "Please ensure you have a tobago-config.xml with a theme-definition in your "
165 + "theme JAR. Found the following themes: " + availableThemes.keySet();
166 LOG.error(error);
167 throw new TobagoConfigurationException(error);
168 }
169 }
170
171 @Override
172 public Theme getTheme(final String name) {
173 if (name == null) {
174 LOG.debug("searching theme: null");
175 return defaultTheme;
176 }
177 if (defaultTheme != null && defaultTheme.getName().equals(name)) {
178 return defaultTheme;
179 }
180 for (final Theme theme : supportedThemes) {
181 if (theme.getName().equals(name)) {
182 return theme;
183 }
184 }
185 LOG.debug("searching theme '{}' not found. Using default: {}", name, defaultTheme);
186 return defaultTheme;
187 }
188
189 protected void setDefaultThemeName(final String defaultThemeName) {
190 checkUnlocked();
191 this.defaultThemeName = defaultThemeName;
192 }
193
194 @Override
195 public List<Theme> getSupportedThemes() {
196 return supportedThemes;
197 }
198
199 @Override
200 public Theme getDefaultTheme() {
201 return defaultTheme;
202 }
203
204 protected void addAvailableTheme(final ThemeImpl availableTheme) {
205 checkUnlocked();
206 final String name = availableTheme.getName();
207 if (availableThemes.containsKey(name)) {
208 final ThemeImpl base = availableThemes.get(name);
209 availableThemes.put(name, ThemeImpl.merge(base, availableTheme));
210 } else {
211 availableThemes.put(name, availableTheme);
212 }
213 }
214
215 public Map<String, ThemeImpl> getAvailableThemes() {
216 return availableThemes;
217 }
218
219 protected synchronized void initDefaultValidatorInfo() {
220 if (defaultValidatorInfo != null) {
221 checkUnlocked();
222 }
223 final FacesContext facesContext = FacesContext.getCurrentInstance();
224 if (facesContext != null) {
225 try {
226 final Application application = facesContext.getApplication();
227 final Map<String, String> map = application.getDefaultValidatorInfo();
228 if (map.size() > 0) {
229 defaultValidatorInfo = Collections.unmodifiableMap(map);
230 } else {
231 defaultValidatorInfo = Collections.emptyMap();
232 }
233 } catch (final Exception e) {
234 LOG.error("Can't initialize default validators (this happens with JBoss GateIn 3.6.0).", e);
235 defaultValidatorInfo = Collections.emptyMap();
236 }
237 }
238 }
239
240 @Override
241 public boolean isCreateSessionSecret() {
242 return createSessionSecret;
243 }
244
245 protected void setCreateSessionSecret(final boolean createSessionSecret) {
246 checkUnlocked();
247 this.createSessionSecret = createSessionSecret;
248 }
249
250 @Override
251 public boolean isCheckSessionSecret() {
252 return checkSessionSecret;
253 }
254
255 protected void setCheckSessionSecret(final boolean checkSessionSecret) {
256 checkUnlocked();
257 this.checkSessionSecret = checkSessionSecret;
258 }
259
260
261 @Override
262 public boolean isPreventFrameAttacks() {
263 return preventFrameAttacks;
264 }
265
266 protected void setPreventFrameAttacks(final boolean preventFrameAttacks) {
267 checkUnlocked();
268 this.preventFrameAttacks = preventFrameAttacks;
269 }
270
271 @Override
272 public ContentSecurityPolicy getContentSecurityPolicy() {
273 return contentSecurityPolicy;
274 }
275
276 @Override
277 public boolean isSetNosniffHeader() {
278 return setNosniffHeader;
279 }
280
281 protected void setSetNosniffHeader(final boolean setNosniffHeader) {
282 checkUnlocked();
283 this.setNosniffHeader = setNosniffHeader;
284 }
285
286 @Override
287 public SecurityAnnotation getSecurityAnnotation() {
288 return securityAnnotation;
289 }
290
291 public void setSecurityAnnotation(final SecurityAnnotation securityAnnotation) {
292 checkUnlocked();
293 this.securityAnnotation = securityAnnotation;
294 }
295
296 public Map<String, String> getDefaultValidatorInfo() {
297
298 if (defaultValidatorInfo == null) {
299 initDefaultValidatorInfo();
300 }
301 return defaultValidatorInfo;
302 }
303
304 @Override
305 public Sanitizer getSanitizer() {
306 return sanitizer;
307 }
308
309 protected void setSanitizer(final Sanitizer sanitizer) {
310 checkUnlocked();
311 this.sanitizer = sanitizer;
312 }
313
314 @Override
315 public boolean isDecodeLineFeed() {
316 return decodeLineFeed;
317 }
318
319 public void setDecodeLineFeed(final boolean decodeLineFeed) {
320 checkUnlocked();
321 this.decodeLineFeed = decodeLineFeed;
322 }
323
324 @Override
325 public Map<String, String> getMimeTypes() {
326 return mimeTypes;
327 }
328
329 @Override
330 public String toString() {
331 final StringBuilder builder = new StringBuilder();
332 builder.append("TobagoConfigImpl{");
333 builder.append("\nsupportedThemes=[");
334 for (final Theme supportedTheme : supportedThemes) {
335 builder.append(supportedTheme.getName());
336 builder.append(", ");
337 }
338 builder.append("], \ndefaultTheme=");
339 builder.append(defaultTheme != null ? defaultTheme.getName() : null);
340 builder.append(", \navailableThemes=");
341 builder.append(availableThemes.keySet());
342 builder.append(", \ncreateSessionSecret=");
343 builder.append(createSessionSecret);
344 builder.append(", \ncheckSessionSecret=");
345 builder.append(checkSessionSecret);
346 builder.append(", \npreventFrameAttacks=");
347 builder.append(preventFrameAttacks);
348 builder.append(", \ncontentSecurityPolicy=");
349 builder.append(contentSecurityPolicy);
350 builder.append(", \nsecurityAnnotation=");
351 builder.append(securityAnnotation);
352 builder.append(", \nsetNosniffHeader=");
353 builder.append(setNosniffHeader);
354 builder.append(", \ndefaultValidatorInfo=");
355 builder.append(defaultValidatorInfo);
356 builder.append(", \nsanitizer=");
357 builder.append(sanitizer);
358 builder.append(", \ndecodeLineFeed=");
359 builder.append(decodeLineFeed);
360
361 builder.append(", \nthemes=");
362 final Set<Theme> all = new HashSet<>(availableThemes.values());
363 builder.append(all);
364 builder.append(", \nmimeTypes=");
365 builder.append(mimeTypes);
366 builder.append('}');
367 return builder.toString();
368 }
369 }