001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.settings;
018
019import org.apache.wicket.Application;
020import org.apache.wicket.Component;
021import org.apache.wicket.authentication.IAuthenticationStrategy;
022import org.apache.wicket.authentication.strategy.DefaultAuthenticationStrategy;
023import org.apache.wicket.authorization.IAuthorizationStrategy;
024import org.apache.wicket.authorization.IUnauthorizedComponentInstantiationListener;
025import org.apache.wicket.authorization.IUnauthorizedResourceRequestListener;
026import org.apache.wicket.authorization.UnauthorizedInstantiationException;
027import org.apache.wicket.coep.CrossOriginEmbedderPolicyConfiguration;
028import org.apache.wicket.coep.CrossOriginEmbedderPolicyConfiguration.CoepMode;
029import org.apache.wicket.coop.CrossOriginOpenerPolicyConfiguration;
030import org.apache.wicket.coop.CrossOriginOpenerPolicyConfiguration.CoopMode;
031import org.apache.wicket.core.random.DefaultSecureRandomSupplier;
032import org.apache.wicket.core.random.ISecureRandomSupplier;
033import org.apache.wicket.core.util.crypt.KeyInSessionSunJceCryptFactory;
034import org.apache.wicket.util.crypt.ICryptFactory;
035import org.apache.wicket.util.crypt.SunJceCrypt;
036import org.apache.wicket.util.lang.Args;
037
038/**
039 * Class for security related settings
040 *
041 * @author Jonathan Locke
042 * @author Chris Turner
043 * @author Eelco Hillenius
044 * @author Juergen Donnerstag
045 * @author Johan Compagner
046 * @author Igor Vaynberg (ivaynberg)
047 * @author Martijn Dashorst
048 * @author James Carman
049 */
050public class SecuritySettings
051{
052        /** The authorization strategy. */
053        private IAuthorizationStrategy authorizationStrategy = IAuthorizationStrategy.ALLOW_ALL;
054
055        /** The authentication strategy. */
056        private IAuthenticationStrategy authenticationStrategy;
057
058        /** factory for creating crypt objects */
059        private ICryptFactory cryptFactory;
060
061        /** supplier of random data and SecureRandom */
062        private ISecureRandomSupplier randomSupplier = new DefaultSecureRandomSupplier();
063
064        /**
065         * Whether mounts should be enforced. If {@code true}, requests for a page will be
066         * allowed only if the page has been explicitly mounted in {@link Application#init() MyApplication#init()}.
067         *
068         * This setting basically disables {@link org.apache.wicket.core.request.mapper.BookmarkableMapper}
069         */
070        private boolean enforceMounts = false;
071
072        /**
073         * Represents the configuration for Cross-Origin-Opener-Policy headers
074         */
075        private CrossOriginOpenerPolicyConfiguration crossOriginOpenerPolicyConfiguration = new CrossOriginOpenerPolicyConfiguration(
076                CoopMode.SAME_ORIGIN);
077
078        /**
079         * Represents the configuration for Cross-Origin-Embedder-Policy headers
080         */
081        private CrossOriginEmbedderPolicyConfiguration crossOriginEmbedderPolicyConfiguration = new CrossOriginEmbedderPolicyConfiguration(
082                CoepMode.REPORTING);
083
084        /** Authorizer for component instantiations */
085        private static final IUnauthorizedComponentInstantiationListener DEFAULT_UNAUTHORIZED_COMPONENT_INSTANTIATION_LISTENER = new IUnauthorizedComponentInstantiationListener()
086        {
087                /**
088                 * Called when an unauthorized component instantiation is about to take place (but before it
089                 * happens).
090                 * 
091                 * @param component
092                 *            The partially constructed component (only the id is guaranteed to be valid).
093                 */
094                @Override
095                public void onUnauthorizedInstantiation(final Component component)
096                {
097                        throw new UnauthorizedInstantiationException(component.getClass());
098                }
099        };
100
101        private IUnauthorizedComponentInstantiationListener unauthorizedComponentInstantiationListener =
102                        DEFAULT_UNAUTHORIZED_COMPONENT_INSTANTIATION_LISTENER;
103
104        private static final IUnauthorizedResourceRequestListener DEFAULT_UNAUTHORIZED_RESOURCE_REQUEST_LISTENER =
105                        new DefaultUnauthorizedResourceRequestListener();
106
107        private IUnauthorizedResourceRequestListener unauthorizedResourceRequestListener = DEFAULT_UNAUTHORIZED_RESOURCE_REQUEST_LISTENER;
108
109        /**
110         * Gets the authorization strategy.
111         *
112         * @return Returns the authorizationStrategy.
113         */
114        public IAuthorizationStrategy getAuthorizationStrategy()
115        {
116                return authorizationStrategy;
117        }
118
119        /**
120         * Returns the {@link ICryptFactory}. If no factory is set, a {@link KeyInSessionSunJceCryptFactory}
121         * is used.
122         * 
123         * @return crypt factory used to generate crypt objects
124         */
125        public synchronized ICryptFactory getCryptFactory()
126        {
127                if (cryptFactory == null)
128                {
129                        cryptFactory = new KeyInSessionSunJceCryptFactory();
130                }
131                return cryptFactory;
132        }
133
134        /**
135         * Returns the {@link ISecureRandomSupplier} to use for secure random data. If no custom
136         * supplier is set, a {@link DefaultSecureRandomSupplier} is used.
137         * 
138         * @return The {@link ISecureRandomSupplier} to use for secure random data.
139         */
140        public ISecureRandomSupplier getRandomSupplier()
141        {
142                return randomSupplier;
143        }
144
145        /**
146         * Gets whether page mounts should be enforced. If {@code true}, requests for a page will be
147         * allowed only if the page has been explicitly mounted in {@link Application#init() MyApplication#init()}.
148         *
149         * This setting basically disables {@link org.apache.wicket.core.request.mapper.BookmarkableMapper}
150         *
151         * @return Whether mounts should be enforced
152         */
153        public boolean getEnforceMounts()
154        {
155                return enforceMounts;
156        }
157
158        /**
159         * @return The listener
160         * @see IUnauthorizedComponentInstantiationListener
161         */
162        public IUnauthorizedComponentInstantiationListener getUnauthorizedComponentInstantiationListener()
163        {
164                return unauthorizedComponentInstantiationListener;
165        }
166
167        /**
168         * Sets the authorization strategy.
169         *
170         * @param strategy
171         *            new authorization strategy
172         * @return {@code this} object for chaining
173         */
174        public SecuritySettings setAuthorizationStrategy(IAuthorizationStrategy strategy)
175        {
176                Args.notNull(strategy, "strategy");
177                authorizationStrategy = strategy;
178                return this;
179        }
180
181        /**
182         * Sets the factory that will be used to create crypt objects. The crypt object returned from
183         * the first call is cached.
184         *
185         * @param cryptFactory
186         * @return {@code this} object for chaining
187         */
188        public SecuritySettings setCryptFactory(ICryptFactory cryptFactory)
189        {
190                Args.notNull(cryptFactory, "cryptFactory");
191                this.cryptFactory = cryptFactory;
192                return this;
193        }
194        
195        /**
196         * Sets the supplier of secure random data for Wicket. The implementation must use a strong
197         * source of random data and be able to generate a lot of random data without running out of
198         * entropy.
199         * 
200         * @param randomSupplier
201         *            The new supplier, must not be null.
202         * @return {@code this} object for chaining
203         */
204        public SecuritySettings setRandomSupplier(ISecureRandomSupplier randomSupplier)
205        {
206                Args.notNull(randomSupplier, "randomSupplier");
207                this.randomSupplier = randomSupplier;
208                return this;
209        }
210
211        /**
212         * Sets whether mounts should be enforced. If true, requests for mounted targets have to done
213         * through the mounted paths. If, for instance, a bookmarkable page is mounted to a path, a
214         * request to that same page via the bookmarkablePage parameter will be denied.
215         *
216         * @param enforce
217         *            Whether mounts should be enforced
218         * @return {@code this} object for chaining
219         */
220        public SecuritySettings setEnforceMounts(boolean enforce)
221        {
222                enforceMounts = enforce;
223                return this;
224        }
225
226        /**
227         * @param listener
228         *            The listener to set
229         * @see IUnauthorizedComponentInstantiationListener
230         * @return {@code this} object for chaining
231         */
232        public SecuritySettings setUnauthorizedComponentInstantiationListener(
233                IUnauthorizedComponentInstantiationListener listener)
234        {
235                this.unauthorizedComponentInstantiationListener = listener == null ?
236                                DEFAULT_UNAUTHORIZED_COMPONENT_INSTANTIATION_LISTENER :
237                                listener;
238                return this;
239        }
240
241        /**
242         * @return The listener that will be used when a request to an IResource is not allowed for some reason
243         */
244        public IUnauthorizedResourceRequestListener getUnauthorizedResourceRequestListener()
245        {
246                return unauthorizedResourceRequestListener;
247        }
248
249        /**
250         * Sets a listener that will be used when a request to an IResource is not allowed for some reason
251         *
252         * @param listener
253         *          The listener
254         * @return {@code this} object for chaining
255         */
256        public SecuritySettings setUnauthorizedResourceRequestListener(IUnauthorizedResourceRequestListener listener)
257        {
258                this.unauthorizedResourceRequestListener = listener == null ?
259                                DEFAULT_UNAUTHORIZED_RESOURCE_REQUEST_LISTENER :
260                                listener;
261                return this;
262        }
263
264        /**
265         * Gets the authentication strategy.
266         *
267         * @return Returns the authentication strategy.
268         */
269        @SuppressWarnings("deprecation")
270        public IAuthenticationStrategy getAuthenticationStrategy()
271        {
272                if (authenticationStrategy == null)
273                {
274                        authenticationStrategy = new DefaultAuthenticationStrategy("LoggedIn", new SunJceCrypt(SunJceCrypt.randomSalt(), 17));
275                }
276                return authenticationStrategy;
277        }
278
279        /**
280         * Sets the authentication strategy.
281         *
282         * @param strategy
283         *            new authentication strategy
284         * @return {@code this} object for chaining
285         */
286        public SecuritySettings setAuthenticationStrategy(final IAuthenticationStrategy strategy)
287        {
288                authenticationStrategy = strategy;
289                return this;
290        }
291
292        public CrossOriginOpenerPolicyConfiguration getCrossOriginOpenerPolicyConfiguration()
293        {
294                return crossOriginOpenerPolicyConfiguration;
295        }
296
297        /**
298         * Sets the Cross-Origin Opener Policy's mode and exempted paths. The config values are only
299         * read once at startup in Application#initApplication(), changing the config at runtime will have no effect
300         *
301         * @param mode
302         *            CoopMode, one of the 4 values: UNSAFE_NONE, SAME_ORIGIN, SAME_ORIGIN_ALLOW_POPUPS, DISABLED
303         * @param exemptions
304         *            exempted paths for which COOP will be disabled
305         * @return
306         */
307        public SecuritySettings setCrossOriginOpenerPolicyConfiguration(
308                CoopMode mode, String... exemptions)
309        {
310                crossOriginOpenerPolicyConfiguration = new CrossOriginOpenerPolicyConfiguration(mode, exemptions);
311                return this;
312        }
313
314
315        public CrossOriginEmbedderPolicyConfiguration getCrossOriginEmbedderPolicyConfiguration()
316        {
317                return crossOriginEmbedderPolicyConfiguration;
318        }
319
320        /**
321         * Sets the Cross-Origin Embedder Policy's mode and exempted paths. The config values are only
322         * read once at startup in Application#initApplication(), changing the config at runtime will
323         * have no effect
324         * 
325         * @param mode
326         *            CoepMode, one of the 3 values: ENFORCING, REPORTING, DISABLED
327         * @param exemptions
328         *            exempted paths for which COEP will be disabled
329         * @return
330         */
331        public SecuritySettings setCrossOriginEmbedderPolicyConfiguration(CoepMode mode,
332                String... exemptions)
333        {
334                crossOriginEmbedderPolicyConfiguration = new CrossOriginEmbedderPolicyConfiguration(mode,
335                        exemptions);
336                return this;
337        }
338
339}