Added: wicket/common/site/trunk/_site/guide/guide/security.html URL: http://svn.apache.org/viewvc/wicket/common/site/trunk/_site/guide/guide/security.html?rev=1562075&view=auto ============================================================================== --- wicket/common/site/trunk/_site/guide/guide/security.html (added) +++ wicket/common/site/trunk/_site/guide/guide/security.html Tue Jan 28 14:13:34 2014 @@ -0,0 +1,465 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> + <title>20 Security with Wicket 6.x</title> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> + <link rel="stylesheet" href="../css/main.css" type="text/css" media="screen, print" title="Style" charset="utf-8"/> + <link rel="stylesheet" href="../css/pdf.css" type="text/css" media="print" title="PDF" charset="utf-8"/> + <script type="text/javascript"> +function addJsClass() { + var classes = document.body.className.split(" "); + classes.push("js"); + document.body.className = classes.join(" "); +} + </script> +</head> + +<body class="body" onload="addJsClass();"> +<div id="navigation"> + <ul> + <li> + <div id="nav-summary" onmouseover="toggleNavSummary(false)" onmouseout="toggleNavSummary(true)"> + <a href="../guide/index.html" class="button">Table of contents</a> + + <div id="nav-summary-childs" style="display:none;"> + + <div class="toc-item" style="margin-left:0"><a href="../guide/introduction.html"><strong>1</strong><span>Introduction</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/howToSource.html"><strong>2</strong><span>How to use the example code</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/whyLearn.html"><strong>3</strong><span>Why should I learn Wicket?</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/helloWorld.html"><strong>4</strong><span>Wicket says “Hello world!”</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/layout.html"><strong>5</strong><span>Wicket as page layout manager</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/keepControl.html"><strong>6</strong><span>Keeping control over HTML</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/componentLifecycle.html"><strong>7</strong><span>Components lifecycle</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/versioningCaching.html"><strong>8</strong><span>Page versioning and caching</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/requestProcessing.html"><strong>9</strong><span>Under the hood of the request processing</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/urls.html"><strong>10</strong><span>Wicket Links and URL generation</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/modelsforms.html"><strong>11</strong><span>Wicket models and forms</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/forms2.html"><strong>12</strong><span>Wicket forms in detail</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/repeaters.html"><strong>13</strong><span>Displaying multiple items with repeaters</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/i18n.html"><strong>14</strong><span>Internationalization with Wicket</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/resources.html"><strong>15</strong><span>Resource management with Wicket</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/jsintegration.html"><strong>16</strong><span>An example of integration with JavaScript</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/advanced.html"><strong>17</strong><span>Wicket advanced topics</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/ajax.html"><strong>18</strong><span>Working with AJAX</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/jee.html"><strong>19</strong><span>Integration with enterprise containers</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/security.html"><strong>20</strong><span>Security with Wicket</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/testing.html"><strong>21</strong><span>Test Driven Development with Wicket</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/testingspring.html"><strong>22</strong><span>Test Driven Development with Wicket and Spring</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/bestpractices.html"><strong>23</strong><span>Wicket Best Practices</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/maven.html"><strong>24</strong><span>Working with Maven (Appendix)</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/wicketstuff.html"><strong>25</strong><span>Project WicketStuff (Appendix)</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/redirects.html"><strong>26</strong><span>Lost In Redirection With Apache Wicket (Appendix)</span></a> + </div> + + <div class="toc-item" style="margin-left:0"><a href="../guide/contributing.html"><strong>27</strong><span>Contributing to this guide (Appendix)</span></a> + </div> + + </div> + </div> + </li> + <li class="separator selected"> + <a id="ref-button" onclick="localToggle(); return false;" href="#">Quick Reference</a> + </li> + </ul> +</div> +<div id="header"> + <div class="images clearfix"> + + <span id="logo"><a href="/" target="_blank"><img height="80px" src="http://wicket.apache.org/guide/img/apache-wicket.png"/></a></span> + + + <span id="sponsor"><a href="http://www.apache.org/" target="_blank"><img height="60px" src="http://wicket.apache.org/guide/img/asf_logo.gif"/></a></span> + + </div> + <p>Free Online Guide for Apache Wicket framework</p> +</div> + + +<table id="colset" border="0" cellpadding="0" cellspacing="0"> + <tr> + <td id="col1"> + <div id="main" class="corner-all"> + + + <div class="toc-item prev-left"><a href="../guide/jee.html"><< <strong>19</strong><span>Integration with enterprise containers</span></a></div> + + + <span id='toggle-col1' class="toggle">(<a href="#" onclick="localToggle(); return false;">Quick Reference</a>)</span> + + + <div class="toc-item next-right"><a href="../guide/testing.html"><strong>21</strong><span>Test Driven Development with Wicket</span> >></a></div> + + + + <div class="project"> + <h1>20 Security with Wicket - Reference Documentation</h1> + + <p><strong>Authors:</strong> Andrea Del Bene, Carsten Hufe, Christian Kroemer, Daniel Bartl, Paul BorÈ</p> + + <p><strong>Version:</strong> 6.x</p> + + + </div> + + + <div id="table-of-content"> + <h2>Table of Contents</h2> + + <div class="toc-item" style="margin-left:0px"><a href="#security_1"><strong>20.1</strong><span>Authentication</span></a> + </div> + + <div class="toc-item" style="margin-left:0px"><a href="#security_2"><strong>20.2</strong><span>Authorizations</span></a> + </div> + + <div class="toc-item" style="margin-left:0px"><a href="#security_3"><strong>20.3</strong><span>Using HTTPS protocol</span></a> + </div> + + <div class="toc-item" style="margin-left:0px"><a href="#security_4"><strong>20.4</strong><span>Package Resource Guard</span></a> + </div> + + <div class="toc-item" style="margin-left:0px"><a href="#security_5"><strong>20.5</strong><span>Summary</span></a> + </div> + + </div> + + + + +<h1 id="security">20 Security with Wicket</h1> +Security is one of the most important non-functional requirements we must implement in our applications. This is particularly true for enterprise applications as they usually support multiple concurrent users, and therefore they need to have an access control policy.<p class="paragraph"/>In this chapter we will explore the security infrastructure provided by Wicket and we will learn how to use it to implement authentication and authorizations in our web applications. + + +<h2 id="security_1">20.1 Authentication</h2> +<p class="paragraph"/>The first step in implementing a security policy is assigning a trusted identity to our users, which means that we must authenticate them. Web applications usually adopt a form-based authentication with a login form that asks user for a unique username and the relative password:<p class="paragraph"/><img border="0" class="center" src="../img/wikipedia-login-form.png"></img><p class="paragraph"/>Wicket supports form-based authentication with session class <code>AuthenticatedWebSession</code> and application class <code>AuthenticatedWebApplication</code>, both placed inside package <code>org.apache.wicket.authroles.authentication</code>.<p class="paragraph"/><h3>AuthenticatedWebSession</h3><p class="paragraph"/>Class AuthenticatedWebSession comes with the following set of public methods to manage user authentication: +<ul class="star"> +<li><strong class="bold">authenticate(String username, String password)</strong>: this is an abstract method that must be implemented by every subclass of <code>AuthenticatedWebSession</code>. It should contain the actual code that checks for user's identity. It returns a boolean value which is true if authentication has succeeded or false otherwise.</li> +<li><strong class="bold">signIn(String username, String password)</strong>: this method internally calls authenticate and set the flag signedIn to true if authentication succeeds.</li> +<li><strong class="bold">isSignedIn()</strong>:getter method for flag signedIn.</li> +<li><strong class="bold">signOut()</strong>: sets the flag signedIn to false.</li> +<li><strong class="bold">invalidate()</strong>: calls signOut and invalidates session.</li> +</ul><p class="paragraph"/><blockquote class="warning"> +Remember that signOut does not discard any session-relative data. If we want to get rid of these data, we must invoke method invalidate instead of signOut. +</blockquote><p class="paragraph"/>Another abstract method we must implement when we use <code>AuthenticatedWebSession</code> is getRoles which is inherited from parent class <code>AbstractAuthenticatedWebSession</code>. This method can be ignored for now as it will be discussed later when we will talk about role-based authorization.<p class="paragraph"/><h3>AuthenticatedWebApplication</h3><p class="paragraph"/>Class AuthenticatedWebApplication provides the following methods to support form-based authentication: +<ul class="star"> +<li><strong class="bold">getWebSessionClass()</strong>: abstract method that returns the session class to use for this application. The returned class must be a subclass of <code>AbstractAuthenticatedWebSession</code>.</li> +<li><strong class="bold">getSignInPageClass()</strong>: abstract method that returns the page to use as sign in page when a user must be authenticated.</li> +<li><strong class="bold">restartResponseAtSignInPage()</strong>: forces the current response to restart at the sign in page. After we have used this method to redirect a user, we can make her/him return to the original page calling <code>Componet</code>'s method <code>continueToOriginalDestination()</code>.</li> +</ul><p class="paragraph"/>The other methods implemented inside <code>AuthenticatedWebApplication</code> will be introduced when we will talk about authorizations.<p class="paragraph"/><h3>A basic example of authentication</h3><p class="paragraph"/>Project <code>BasicAuthenticationExample</code> is a basic example of form-based authentication implemented with classes <code>AuthenticatedWebSession</code> and <code>AuthenticatedWebApplication</code>.<p class="paragraph"/>The homepage of the project contains only a link to page <code>AuthenticatedPage</code> which can be accessed only if user is signed in. The code of <code>AuthenticatedPage</code> is this following:<p class="paragraph"/><div class="code"><pre><span class="java-keyword">public</span> class AuthenticatedPage <span class="java-keyword">extends</span> WebPage { + @Override + <span class="java-keyword">protected</span> void onConfigure() { + AuthenticatedWebApplication app = (AuthenticatedWebApplication)Application.get(); + //<span class="java-keyword">if</span> user is not signed in, redirect him to sign in page + <span class="java-keyword">if</span>(!AuthenticatedWebSession.get().isSignedIn()) + app.restartResponseAtSignInPage(); + }<p class="paragraph"/> @Override + <span class="java-keyword">protected</span> void onInitialize() { + <span class="java-keyword">super</span>.onInitialize(); + add(<span class="java-keyword">new</span> Link(<span class="java-quote">"goToHomePage"</span>) {<p class="paragraph"/> @Override + <span class="java-keyword">public</span> void onClick() { + setResponsePage(getApplication().getHomePage()); + } + });<p class="paragraph"/> add(<span class="java-keyword">new</span> Link(<span class="java-quote">"logOut"</span>) {<p class="paragraph"/> @Override + <span class="java-keyword">public</span> void onClick() { + AuthenticatedWebSession.get().invalidate(); + setResponsePage(getApplication().getHomePage()); + } + }); + } +}</pre></div><p class="paragraph"/>Page <code>AuthenticatedPage</code> checks inside onConfigure if user is signed in and if not, it redirects her/him to the sign in page with method <code>restartResponseAtSignInPage</code>. The page contains also a link to the homepage and another link that signs out user.<p class="paragraph"/>The sign in page is implemented in class <code>SignInPage</code> and contains the form used to authenticate users:<p class="paragraph"/><div class="code"><pre><span class="java-keyword">public</span> class SignInPage <span class="java-keyword">extends</span> WebPage { + <span class="java-keyword">private</span> <span class="java-object">String</span> username; + <span class="java-keyword">private</span> <span class="java-object">String</span> password;<p class="paragraph"/> @Override + <span class="java-keyword">protected</span> void onInitialize() { + <span class="java-keyword">super</span>.onInitialize();<p class="paragraph"/> StatelessForm form = <span class="java-keyword">new</span> StatelessForm(<span class="java-quote">"form"</span>){ + @Override + <span class="java-keyword">protected</span> void onSubmit() { + <span class="java-keyword">if</span>(Strings.isEmpty(username)) + <span class="java-keyword">return</span>;<p class="paragraph"/> <span class="java-object">boolean</span> authResult = AuthenticatedWebSession.get().signIn(username, password); + //<span class="java-keyword">if</span> authentication succeeds redirect user to the requested page + <span class="java-keyword">if</span>(authResult) + continueToOriginalDestination(); + } + };<p class="paragraph"/> form.setDefaultModel(<span class="java-keyword">new</span> CompoundPropertyModel(<span class="java-keyword">this</span>));<p class="paragraph"/> form.add(<span class="java-keyword">new</span> TextField(<span class="java-quote">"username"</span>)); + form.add(<span class="java-keyword">new</span> PasswordTextField(<span class="java-quote">"password"</span>));<p class="paragraph"/> add(form); + } +}</pre></div><p class="paragraph"/>The form is responsible for handling user authentication inside its method onSubmit. The username and password are passed to <code>AuthenticatedWebSession</code>'s method <code>signIn(username, password)</code> and if authentication succeeds, the user is redirected to the original page with method <code>continueToOriginalDestination</code>.<p class="paragraph"/>The session class and the application class used in the project are reported here:<p class="paragraph"/><strong class="bold">Session class:</strong><p class="paragraph"/><div class="code"><pre><span class="java-keyword">public</span> class BasicAuthenticationSession <span class="java-keyword">extends</span> AuthenticatedWebSession {<p class="paragraph"/> <span class="java-keyword">public</span> BasicAuthenticationSession(Request request) { + <span class="java-keyword">super</span>(request); + }<p class="paragraph"/> @Override + <span class="java-keyword">public</span> <span class="java-object">boolean</span> authenticate(<span class="java-object">String</span> username, <span class="java-object">String</span> password) { + //user is authenticated <span class="java-keyword">if</span> both username and password are equal to 'wicketer' + <span class="java-keyword">return</span> username.equals(password) && username.equals(<span class="java-quote">"wicketer"</span>); + }<p class="paragraph"/> @Override + <span class="java-keyword">public</span> Roles getRoles() { + <span class="java-keyword">return</span> <span class="java-keyword">null</span>; + } +}</pre></div><p class="paragraph"/><strong class="bold">Application class:</strong><p class="paragraph"/><div class="code"><pre><span class="java-keyword">public</span> class WicketApplication <span class="java-keyword">extends</span> AuthenticatedWebApplication{ + @Override + <span class="java-keyword">public</span> <span class="java-object">Class</span><HomePage> getHomePage(){ + <span class="java-keyword">return</span> HomePage.class; + }<p class="paragraph"/> @Override + <span class="java-keyword">protected</span> <span class="java-object">Class</span><? <span class="java-keyword">extends</span> AbstractAuthenticatedWebSession> getWebSessionClass(){ + <span class="java-keyword">return</span> BasicAuthenticationSession.class; + }<p class="paragraph"/> @Override + <span class="java-keyword">protected</span> <span class="java-object">Class</span><? <span class="java-keyword">extends</span> WebPage> getSignInPageClass() { + <span class="java-keyword">return</span> SignInPage.class; + } +}</pre></div><p class="paragraph"/>The authentication logic inside authenticate has been kept quite trivial in order to make the code as clean as possible. Please note also that session class must have a constructor that accepts an instance of class <code>Request</code>.<p class="paragraph"/><h3>Redirecting user to an intermediate page</h3><p class="paragraph"/>Method <code>restartResponseAtSignInPage</code> is an example of redirecting user to an intermediate page before allowing him to access to the requested page. This method internally throws exception <code>org.apache.wicket.RestartResponseAtInterceptPageException</code> which saves the URL of the requested page into session metadata and then redirects user to the page passed as constructor parameter (the sign in page).<p class="paragraph"/>Component's method <code>redirectToInterceptPage(Page)</code> works in much the same way as <code>restartResponseAtSignInPage</code> but it allows us to specify which page to use as int ermediate page:<p class="paragraph"/><div class="code"><pre>redirectToInterceptPage(intermediatePage);</pre></div><p class="paragraph"/><blockquote class="note"> +Since both <code>restartResponseAtSignInPage</code> and <code>redirectToInterceptPage</code> internally throw an exception, the code placed after them will not be executed. +</blockquote> + + + +<h2 id="security_2">20.2 Authorizations</h2> +<p class="paragraph"/>The authorization support provided by Wicket is built around the concept of authorization strategy which is represented by interface <code>IAuthorizationStrategy</code> (in package <code>org.apache.wicket.authorization</code>):<p class="paragraph"/><div class="code"><pre><span class="java-keyword">public</span> <span class="java-keyword">interface</span> IAuthorizationStrategy +{ + //<span class="java-keyword">interface</span> methods + <T <span class="java-keyword">extends</span> IRequestableComponent> <span class="java-object">boolean</span> isInstantiationAuthorized(<span class="java-object">Class</span><T> componentClass); + <span class="java-object">boolean</span> isActionAuthorized(Component component, Action action);<p class="paragraph"/> //<span class="java-keyword">default</span> authorization strategy that allows everything + <span class="java-keyword">public</span> <span class="java-keyword">static</span> <span class="java-keyword">final</span> IAuthorizationStrategy ALLOW_ALL = <span class="java-keyword">new</span> IAuthorizationStrategy() + { + @Override + <span class="java-keyword">public</span> <T <span class="java-keyword">extends</span> IRequestableComponent> <span class="java-object">boolean</span> isInstantiationAuthorized(<span class="java-keyword">final</span> <span class="java-object">Class</span><T> c) + { + <span class="java-keyword">return</span> <span class="java-keyword">true</span>; + } + @Override + <span class="java-keyword">public</span> <span class="java-object">boolean</span> isActionAuthorized(Component c, Action action) + { + <span class="java-keyword">return</span> <span class="java-keyword">true</span>; + } + }; +}</pre></div><p class="paragraph"/>This interface defines two methods: +<ul class="star"> +<li>isInstantiationAuthorized checks if user is allowed to instantiate a given component.</li> +<li>isActionAuthorized checks if user is authorized to perform a given action on a component's instance. The standard actions checked by this method are defined into class Action and are Action.ENABLE and Action.RENDER.</li> +</ul><p class="paragraph"/>Inside <code>IAuthorizationStrategy</code> we can also find a default implementation of the interface (called ALLOW_ALL) that allows everyone to instantiate every component and perform every possible action on it. This is the default strategy adopted by class <code>Application</code>.<p class="paragraph"/>To change the authorization strategy in use we must register the desired implementation into security settings (interface <code>ISecuritySettings</code>) during initialization phase with method setAuthorization Strategy:<p class="paragraph"/><div class="code"><pre>//Application class code… + @Override + <span class="java-keyword">public</span> void init() + { + <span class="java-keyword">super</span>.init(); + getSecuritySettings(). + setAuthorizationStrategy(myAuthorizationStrategy); + } +//...</pre></div><p class="paragraph"/>If we want to combine the action of two or more authorization strategies we can chain them with strategy <code>CompoundAuthorizationStrategy</code> which implements composite pattern for authorization strategies.<p class="paragraph"/>Most of the times we won't need to implement an <code>IAuthorizationStrategy</code> from scratch as Wicket already comes with a set of built-in strategies. In the next paragraphs we will see some of these strategies that can be used to implement an effective and flexible security policy.<p class="paragraph"/><h3>SimplePageAuthorizationStrategy</h3><p class="paragraph"/>Abstract class SimplePageAuthorizationStrategy (in package <code>org.apache.wicket.authorization.strategies.page</code>) is a strategy that checks user authorizations calling abstract method <code>isAuthorized</code> only for those pages that are subclasses of a given supertype. If <code>isAuthorized</code> returns false, the user is redirected to th e sign in page specified as second constructor parameter:<p class="paragraph"/><div class="code"><pre>SimplePageAuthorizationStrategy authorizationStrategy = <span class="java-keyword">new</span> SimplePageAuthorizationStrategy( + PageClassToCheck.class, SignInPage.class) +{ + <span class="java-keyword">protected</span> <span class="java-object">boolean</span> isAuthorized() + { + //Authentication code… + } +};</pre></div><p class="paragraph"/>By default <code>SimplePageAuthorizationStrategy</code> checks for permissions only on pages. If we want to change this behavior and check also other kinds of components, we must override method <code>isActionAuthorized</code> and implement our custom logic inside it.<p class="paragraph"/><h3>Role-based strategies</h3><p class="paragraph"/>At the end of paragraph 20.1 we have introduced AbstractAuthenticatedWebSession's method getRoles which is provided to support role-based authorization returning the set of roles granted to the current user.<p class="paragraph"/>In Wicket roles are simple strings like âBASIC_USERâ or âADMINâ (they don't need to be capitalized) and they are handled with class <code>org.apache.wicket.authroles.authorization.strategies.role.Roles</code>. This class extends standard HashSet collection adding some functionalities to check whether the set contains one or more roles. Class <code>Roles</code> al ready defines roles Roles.USER and Roles.ADMIN.<p class="paragraph"/>The session class in the following example returns a custom âSIGNED_INâ role for every authenticated user and it adds an Roles.ADMIN role if username is equal to superuser:<p class="paragraph"/><div class="code"><pre>class BasicAuthenticationRolesSession <span class="java-keyword">extends</span> AuthenticatedWebSession { + <span class="java-keyword">private</span> <span class="java-object">String</span> userName;<p class="paragraph"/> <span class="java-keyword">public</span> BasicAuthenticationRolesSession(Request request) { + <span class="java-keyword">super</span>(request); + }<p class="paragraph"/> @Override + <span class="java-keyword">public</span> <span class="java-object">boolean</span> authenticate(<span class="java-object">String</span> username, <span class="java-object">String</span> password) { + <span class="java-object">boolean</span> authResult= <span class="java-keyword">false</span>;<p class="paragraph"/> authResult = //some authentication logic...<p class="paragraph"/> <span class="java-keyword">if</span>(authResult) + userName = username;<p class="paragraph"/> <span class="java-keyword">return</span> authResult; + }<p class="paragraph"/> @Override + <span class="java-keyword">public</span> Roles getRoles() { + Roles resultRoles = <span class="java-keyword">new</span> Roles();<p class="paragraph"/> <span class="java-keyword">if</span>(isSignedIn()) + resultRoles.add(<span class="java-quote">"SIGNED_IN"</span>);<p class="paragraph"/> <span class="java-keyword">if</span>(userName.equals(<span class="java-quote">"superuser"</span>)) + resultRoles.add(Roles.ADMIN);<p class="paragraph"/> <span class="java-keyword">return</span> resultRoles; + } +}</pre></div><p class="paragraph"/>Roles can be adopted to apply security restrictions on our pages and components. This can be done using one of the two built-in authorization strategies that extend super class <code>AbstractRoleAuthorizationStrategyWicket</code>: <code>MetaDataRoleAuthorizationStrategy</code> and <code>AnnotationsRoleAuthorizationStrategy</code><p class="paragraph"/>The difference between these two strategies is that <code>MetaDataRoleAuthorizationStrategy</code> handles role-based authorizations with Wicket metadata while <code>AnnotationsRoleAuthorizationStrategy</code> uses Java annotations.<p class="paragraph"/><blockquote class="note"> +Application class <code>AuthenticatedWebApplication</code> already sets <code>MetaDataRoleAuthorizationStrategy</code> and <code>AnnotationsRoleAuthorizationStrategy</code> as its own authorization strategies (it uses a compound strategy as we will see in paragraph 20.2).<p class="paragraph"/>The code that we will see in the next examples is for illustrative purpose only. If our application class inherits from <code>AuthenticatedWebApplication</code> we won't need to configure anything to use these two strategies. +</blockquote><p class="paragraph"/><h4>Using roles with metadata</h4><p class="paragraph"/>Strategy <code>MetaDataRoleAuthorizationStrategy</code> uses application and components metadata to implement role-based authorizations. The class defines a set of static methods authorize that can be used to specify which roles are allowed to instantiate a component and which roles can perform a given action on a component.<p class="paragraph"/>The following code snippet reports both application and session classes from project <code>MetaDataRolesStrategyExample</code> and illustrates how to use <code>MetaDataRoleAuthorizationStrategy</code> to allow access to a given page (AdminOnlyPage) only to ADMIN role:<p class="paragraph"/><strong class="bold">Application class:</strong><p class="paragraph"/><div class="code"><pre><span class="java-keyword">public</span> class WicketApplication <span class="java-keyword">extends</span> AuthenticatedWebApplication{ + @Override + <span class="java-keyword">public</span> <span class="java-object">Class</span><? <span class="java-keyword">extends</span> WebPage> getHomePage(){ + <span class="java-keyword">return</span> HomePage.class; + }<p class="paragraph"/> @Override + <span class="java-keyword">protected</span> <span class="java-object">Class</span><? <span class="java-keyword">extends</span> AbstractAuthenticatedWebSession> getWebSessionClass() { + <span class="java-keyword">return</span> BasicAuthenticationSession.class; + }<p class="paragraph"/> @Override + <span class="java-keyword">protected</span> <span class="java-object">Class</span><? <span class="java-keyword">extends</span> WebPage> getSignInPageClass() { + <span class="java-keyword">return</span> SignInPage.class; + }<p class="paragraph"/> @Override + <span class="java-keyword">public</span> void init(){ + getSecuritySettings().setAuthorizationStrategy(<span class="java-keyword">new</span> MetaDataRoleAuthorizationStrategy(<span class="java-keyword">this</span>)); + MetaDataRoleAuthorizationStrategy.authorize(AdminOnlyPage.class, Roles.ADMIN); + } +}</pre></div><p class="paragraph"/><strong class="bold">Session class:</strong><p class="paragraph"/><div class="code"><pre><span class="java-keyword">public</span> class BasicAuthenticationSession <span class="java-keyword">extends</span> AuthenticatedWebSession {<p class="paragraph"/> <span class="java-keyword">private</span> <span class="java-object">String</span> username;<p class="paragraph"/> <span class="java-keyword">public</span> BasicAuthenticationSession(Request request) { + <span class="java-keyword">super</span>(request); + }<p class="paragraph"/> @Override + <span class="java-keyword">public</span> <span class="java-object">boolean</span> authenticate(<span class="java-object">String</span> username, <span class="java-object">String</span> password) { + //user is authenticated <span class="java-keyword">if</span> username and password are equal + <span class="java-object">boolean</span> authResult = username.equals(password);<p class="paragraph"/> <span class="java-keyword">if</span>(authResult) + <span class="java-keyword">this</span>.username = username;<p class="paragraph"/> <span class="java-keyword">return</span> authResult; + }<p class="paragraph"/> <span class="java-keyword">public</span> Roles getRoles() { + Roles resultRoles = <span class="java-keyword">new</span> Roles(); + //<span class="java-keyword">if</span> user is signed in add the relative role + <span class="java-keyword">if</span>(isSignedIn()) + resultRoles.add(<span class="java-quote">"SIGNED_IN"</span>); + //<span class="java-keyword">if</span> username is equal to 'superuser' add the ADMIN role + <span class="java-keyword">if</span>(username!= <span class="java-keyword">null</span> && username.equals(<span class="java-quote">"superuser"</span>)) + resultRoles.add(Roles.ADMIN);<p class="paragraph"/> <span class="java-keyword">return</span> resultRoles; + }<p class="paragraph"/> @Override + <span class="java-keyword">public</span> void signOut() { + <span class="java-keyword">super</span>.signOut(); + username = <span class="java-keyword">null</span>; + } +}</pre></div><p class="paragraph"/>The code that instantiates <code>MetaDataRoleAuthorizationStrategy</code> and set it as application's strategy is inside application class method init.<p class="paragraph"/>Any subclass of <code>AbstractRoleAuthorizationStrategyWicket</code> needs an implementation of interface <code>IRoleCheckingStrategy</code> to be instantiated. For this purpose in the code above we used the application class itself because its base class <code>AuthenticatedWebApplication</code> already implements interface <code>IRoleCheckingStrategy</code>. By default <code>AuthenticatedWebApplication</code> checks for authorizations using the roles returned by the current <code>AbstractAuthenticatedWebSession</code>. As final step inside init we grant the access to page <code>AdminOnlyPage</code> to ADMIN role calling method authorize.<p class="paragraph"/>The code from session class has three interesting methods. The first is authenticate which considers as valid creden tials every pair of username and password having the same value. The second notable method is getRoles which returns role SIGNED_IN if user is authenticated and it adds role ADMIN if username is equal to superuser. Finally, we have method signOut which has been overridden in order to clean the username field used internally to generate roles.<p class="paragraph"/>Now if we run the project and we try to access to <code>AdminOnlyPage</code> from the home page without having the ADMIN role, we will be redirected to the default access-denied page used by Wicket:<p class="paragraph"/><img border="0" class="center" src="../img/authorization-access-denied.png"></img><p class="paragraph"/>The access-denied page can be customized using method <code>setAccessDeniedPage(Class<? extends Page>)</code> of setting interface <code>IApplicationSettings</code>:<p class="paragraph"/><div class="code"><pre>//Application class code… + @Override + <span class="java-keyword">public</span> void init(){ + getApplicationSettings().setAccessDeniedPage( + MyCustomAccessDeniedPage.class); + }</pre></div><p class="paragraph"/>Just like custom âPage expiredâ page (see chapter 6.2.5), also custom âAccess deniedâ page must be bookmarkable.<p class="paragraph"/><h4>Using roles with annotations</h4><p class="paragraph"/>Strategy <code>AnnotationsRoleAuthorizationStrategy</code> relies on two built-in annotations to handle role-based authorizations. These annotations are <code>AuthorizeInstantiation</code> and <code>AuthorizeAction</code>. As their names suggest the first annotation specifies which roles are allowed to instantiate the annotated component while the second must be used to indicate which roles are allowed to perform a specific action on the annotated component.<p class="paragraph"/>In the following example we use annotations to make a page accessible only to signed-in users and to enable it only if user has the ADMIN role:<p class="paragraph"/><div class="code"><pre>@AuthorizeInstantiation(<span class="java-quote">"SIGNED_IN"</spa n>) +@AuthorizeAction(action = <span class="java-quote">"ENABLE"</span>, roles = {<span class="java-quote">"ADMIN"</span>}) +<span class="java-keyword">public</span> class MyPage <span class="java-keyword">extends</span> WebPage { + //Page class code… +}</pre></div><p class="paragraph"/>Remember that when a component is not enabled, user can render it but he can neither click on its links nor interact with its forms.<p class="paragraph"/>Example project <code>AnnotationsRolesStrategyExample</code> is a revisited version of <code>MetaDataRolesStrategyExample</code> where we use <code>AnnotationsRoleAuthorizationStrategy</code> as authorization strategy. To ensure that page <code>AdminOnlyPage</code> is accessible only to ADMIN role we have used the following annotation:<p class="paragraph"/><div class="code"><pre>@AuthorizeInstantiation(<span class="java-quote">"ADMIN"</span>) +<span class="java-keyword">public</span> class AdminOnlyPage <span class="java-keyword">extends</span> WebPage { + //Page class code… +}</pre></div><p class="paragraph"/><h3>Catching an unauthorized component instantiation</h3><p class="paragraph"/>Interface IUnauthorizedComponentInstantiationListener (in package <code>org.apache.wicket.authorization</code>) is provided to give the chance to handle the case in which a user tries to instantiate a component without having the permissions to do it. The method defined inside this interface is <code>onUnauthorizedInstantiation(Component)</code> and it is executed whenever a user attempts to execute an unauthorized instantiation.<p class="paragraph"/>This listener must be registered into application's security settings with method setUnauthorized <code>ComponentInstantiationListener</code> defined by setting interface <code>ISecuritySettings</code>. In the following code snippet we register a listener that redirect user to a warning page if he tries to do a not-allowed instantiation:<p class="paragraph"/><div class="code"><pre><span class="java-keyword">public</ span> class WicketApplication <span class="java-keyword">extends</span> AuthenticatedWebApplication{ + //Application code… + @Override + <span class="java-keyword">public</span> void init(){ + getSecuritySettings().setUnauthorizedComponentInstantiationListener( + <span class="java-keyword">new</span> IUnauthorizedComponentInstantiationListener() {<p class="paragraph"/> @Override + <span class="java-keyword">public</span> void onUnauthorizedInstantiation(Component component) { + component.setResponsePage(AuthWarningPage.class); + } + }); + } +}</pre></div><p class="paragraph"/>In addition to interface <code>IRoleCheckingStrategy</code>, class <code>AuthenticatedWebApplication</code> implements also <code>IUnauthorizedComponentInstantiationListener</code> and registers itself as listener for unauthorized instantiations.<p class="paragraph"/>By default <code>AuthenticatedWebApplication</code> redirects users to sign-in page if they are not signed-in and they try to instantiate a restricted component. Otherwise, if users are already signed in but they are not allowed to instantiate a given component, an <code>UnauthorizedInstantiationException</code> will be thrown.<p class="paragraph"/><h3>Strategy RoleAuthorizationStrategy</h3><p class="paragraph"/>Class <code>RoleAuthorizationStrategy</code> is a compound strategy that combines both <code>MetaDataRoleAuthorizationStrategy</code> and <code>AnnotationsRoleAuthorizationStrategy</code>.<p class="paragraph"/>This is the strategy used internally by <code>AuthenticatedWebA pplication</code>. + + + +<h2 id="security_3">20.3 Using HTTPS protocol</h2> +<p class="paragraph"/>HTTPS is the standard technology adopted on Internet to create a secure communication channel between web applications and their users.<p class="paragraph"/>In Wicket we can easily protect our pages with HTTPS mounting a special request mapper called <code>HttpsMapper</code> and using annotation RequireHttps with those pages we want to serve over this protocol. Both these two entities are in package <code>org.apache.wicket.protocol.https</code>.<p class="paragraph"/>HttpsMapper wraps an existing mapper and redirects incoming requests to HTTPS if the related response must render a page containing annotation <code>RequireHttps</code>. Most of the times the wrapped mapper will be the root one, just like we saw before for <code>CryptoManager</code> in paragraph 8.6.6.<p class="paragraph"/>Another parameter needed to build a <code>HttpsMapper</code> is an instance of class <code>HttpsConfi</code>g. This class allows us to specify which ports must be used for HTTPS a nd HTTP. By default the port numbers used by these two protocols are respectively 443 and 80.<p class="paragraph"/>The following code is taken from project <code>HttpsProtocolExample</code> and illustrates how to enable HTTPS in our applications:<p class="paragraph"/><div class="code"><pre>//Application class code… +@Override +<span class="java-keyword">public</span> void init(){ + setRootRequestMapper(<span class="java-keyword">new</span> HttpsMapper(getRootRequestMapper(), + <span class="java-keyword">new</span> HttpsConfig(8080, 443))); +}</pre></div><p class="paragraph"/>Now we can use annotation RequireHttps to specify which pages must be served using HTTPS:<p class="paragraph"/><div class="code"><pre>@RequireHttps +<span class="java-keyword">public</span> class HomePage <span class="java-keyword">extends</span> WebPage { + <span class="java-keyword">public</span> HomePage(<span class="java-keyword">final</span> PageParameters parameters) { + <span class="java-keyword">super</span>(parameters); + } +}</pre></div><p class="paragraph"/>If we want to protect many pages with HTTPS without adding annotation <code>RequireHttps</code> to each of them, we can annotate a marker interface or a base page class and implement/extend it in any page we want to make secure:<p class="paragraph"/><div class="code"><pre>// Marker <span class="java-keyword">interface</span>: +@RequireHttps +<span class="java-keyword">public</span> <span class="java-keyword">interface</span> IMarker{ +}<p class="paragraph"/>// Base class: +@RequireHttps +<span class="java-keyword">public</span> class BaseClass <span class="java-keyword">extends</span> WebPage{ +//Page code… +}<p class="paragraph"/>// Secure page inheriting from BaseClass: +<span class="java-keyword">public</span> class HttpsPage <span class="java-keyword">extends</span> BaseClass{ +//Page code… +}<p class="paragraph"/>// Secure page implementing IMarker: +<span class="java-keyword">public</span> class HttpsPage <span class="java-keyword">implements</span> IMarker{ +//Page code… +}</pre></div> + + +<h2 id="security_4">20.4 Package Resource Guard</h2> +<p class="paragraph"/>Wicket internally uses an entity called package resource guard to protect package resources from external access. This entity is an implementation of interface <code>org.apache.wicket.markup.html.IPackageResourceGuard</code>.<p class="paragraph"/>By default Wicket applications use as package resource guard class <code>SecurePackageResourceGuard</code>, which allows to access only to the following file extensions (grouped by type):<p class="paragraph"/><table class="wiki-table" cellpadding="0" cellspacing="0" border="0"><tr><th>File</th><th>Extensions</th></tr><tr class="table-odd"><td><strong class="bold">JavaScript files</strong></td><td>.js</td></tr><tr class="table-even"><td><strong class="bold">CSS files</strong></td><td>.css</td></tr><tr class="table-odd"><td><strong class="bold">HTML pages</strong></td><td>.html</td></tr><tr class="table-even"><td><strong class="bold">Textual files</strong></td><td>.txt</td></tr><tr class="table-odd"><td><strong class="bo ld">Flash files</strong></td><td>.swf</td></tr><tr class="table-even"><td><strong class="bold">Picture files</strong></td><td>.png, .jpg, .jpeg, .gif, .ico, .cur, .bmp, .svg</td></tr><tr class="table-odd"><td><strong class="bold">Web font files</strong></td><td>.eot, .ttf, .woff</td></tr></table><p class="paragraph"/>To modify the set of allowed files formats we can add one or more patterns with method <code>addPattern(String)</code>. The rules to write a pattern are the following: +<ul class="star"> +<li>patterns start with either a "+" or a "-". In the first case the pattern will add one or more file to the set while starting a pattern with a â-â we exclude all the files matching the given pattern. For example pattern â-web.xmlâ excludes all web.xml files in all directories.</li> +<li>wildcard character â*â is supported as placeholder for zero or more characters. For example pattern â+*.mp4â adds all the mp4 files inside all directories.</li> +<li>subdirectories are supported as well. For example pattern â+documents/*.pdfâ adds all pdf files under âdocumentsâ directory. Character â*â can be used with directories to specify a nesting level. For example â+documents/*/*.pdfâ adds all pdf files placed one level below âdocumentsâ directory.</li> +<li>a double wildcard character â**â indicates zero or more subdirectories. For example pattern â+documents/**/*.pdfâ adds all pdf files placed inside âdocumentsâ directory or inside any of its subdirectories.</li> +</ul><p class="paragraph"/>Patterns that allow to access to every file with a given extensions (such as â+*.pdfâ) should be always avoided in favour of more restrictive expressions that contain a directory structure:<p class="paragraph"/><div class="code"><pre>//Application class code… +@Override +<span class="java-keyword">public</span> void init() +{ + IPackageResourceGuard packageResourceGuard = application.getResourceSettings() + .getPackageResourceGuard(); + <span class="java-keyword">if</span> (packageResourceGuard <span class="java-keyword">instanceof</span> SecurePackageResourceGuard) + { + SecurePackageResourceGuard guard = (SecurePackageResourceGuard) packageResourceGuard; + //Allow to access only to pdf files placed in the â<span class="java-keyword">public</span>â directory. + guard.addPattern(<span class="java-quote">"+<span class="java-keyword">public</span>/*.pdf"</span>); + } +}</pre></div> + + + +<h2 id="security_5">20.5 Summary</h2> +<p class="paragraph"/> In this chapter we have seen the components and the mechanisms that allow us to implement security policies in our Wicket-based applications. Wicket comes with an out of the box support for both authorization and authentication.<p class="paragraph"/>The central element of authorization mechanism is the interface <code>IAuthorizationStrategy</code> which decouples our components from any detail about security strategy. The implementations of this interface must decide if a user is allowed to instantiate a given page or component and if she/he can perform a given action on it.<p class="paragraph"/>Wicket natively supports role-based authorizations with strategies <code>MetaDataRoleAuthorizationStrategy</code> and <code>AnnotationsRoleAuthorizationStrategy</code>. The difference between these two strategies is that the first offers a programmatic approach for role handling while the second promotes a declarative approach using built-in annotations.<p class="parag raph"/>After having explored how Wicket internally implements authentication and authorization, in the last part of the chapter we have learnt how to configure our applications to support HTTPS and how to specify which pages must be served over this protocol.<p class="paragraph"/>In the last paragraph we have seen how Wicket protects package resources with a guard entity that allows us to decide which package resources can be accessed from users.<p class="paragraph"/><p class="paragraph"/> + + + <div style="clear:both;margin-top:15px;"></div> + + <div class="toc-item prev-left"><a href="../guide/jee.html"><< <strong>19</strong><span>Integration with enterprise containers</span></a></div> + + <div class="toc-item next-right"><a href="../guide/testing.html"><strong>21</strong><span>Test Driven Development with Wicket</span> >></a></div> + + <div style="clear:both"></div> + </div> + </td> + <td id="col2"> + <div class="local clearfix"> + <div class="local-title"> + <a href="../guide/index.html" target="mainFrame">Quick Reference</a> + <span class="toggle">(<a href="#" onclick="localToggle(); return false;">hide</a>)</span> + </div> + <div class="menu"> + + </div> + </div> + </td> + </tr> +</table> + +<div id="footer"> + +Copyright © 2013-2014 â <a href="http://www.apache.org/" target="_blank">The Apache Software Foundation</a> + â <b style="color:#E8590A !important;">(Generated on: 2014-01-28)</b> + + +</div> + +<script type="text/javascript" src="../js/docs.js"></script> + +</body> +</html>
