View Javadoc

1   /*
2    * $Id: LoginFilter.java 269 2005-08-10 17:49:22Z josem $
3    *
4    * Tarsis
5    * Copyright (C) 2002 Talika Open Source Group
6    *
7    * This program is free software; you can redistribute it and/or modify
8    * it under the terms of the GNU General Public License as published by
9    * the Free Software Foundation; either version 2 of the License, or
10   * (at your option) any later version.
11   *
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Public License for more details.
16   *
17   * You should have received a copy of the GNU General Public License
18   * along with this program; if not, write to the Free Software
19   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20   *
21   */
22  
23  package org.talika.tarsis.filters.security;
24  
25  import java.io.IOException;
26  
27  import javax.servlet.FilterChain;
28  import javax.servlet.FilterConfig;
29  import javax.servlet.ServletException;
30  import javax.servlet.ServletRequest;
31  import javax.servlet.ServletResponse;
32  import javax.servlet.UnavailableException;
33  import javax.servlet.http.HttpServletRequest;
34  
35  import org.talika.tarsis.Globals;
36  import org.talika.tarsis.command.Command;
37  import org.talika.tarsis.filters.CommandFilter;
38  import org.talika.tarsis.security.AuthenticationFailedException;
39  import org.talika.tarsis.security.AuthenticationRequiredException;
40  import org.talika.tarsis.security.Authenticator;
41  import org.talika.tarsis.security.Authorizator;
42  import org.talika.tarsis.security.SecuritySession;
43  import org.talika.tarsis.security.SecuritySessionManager;
44  
45  /**
46   * Login filter checks if client's request has a valid security session and if not
47   * tries to authenticate client.
48   *
49   * @author  Jose M. Palomar
50   * @version $Revision: 269 $
51   */
52  public final class LoginFilter extends CommandFilter {
53  
54      // Constants
55      /**
56       * Login page parameter name.
57       */
58      public static final String LOGIN_PAGE_PARAM = "loginPage";
59  
60      /**
61       * Number login of tries parameter name.
62       */
63      public static final String LOGIN_TRIES_PARAM = "loginTries";
64  
65      /**
66       * Default number login of tries.
67       */
68      private static final int DEFAULT_LOGIN_TRIES = 3;
69  
70      // Fields
71      /**
72       * Login page.
73       */
74      private String loginPage;
75  
76      /**
77       * Login tries.
78       */
79      private int loginTries;
80  
81      /**
82       * Tarsis authenticator.
83       */
84      private Authenticator authenticator;
85  
86      /**
87       * Tarsis authorizator.
88       */
89      private Authorizator authorizator;
90  
91      /**
92       * Tarsis session manager.
93       */
94      private SecuritySessionManager securitySessionManager;
95  
96      // Methods
97      /**
98       * Called by the web container to indicate to a filter that it is being placed
99       * into service.<br>
100      * <br>
101      * Initialization consits in:
102      * <ol>
103      * <li>Calling super <code>int</code> method.</li>
104      * <li>Retrieves login page parameter.</li>
105      * <li>Retrieves login tries parameter.</li>
106      * <li>Stores in a local variable authenticator instance.</li>
107      * <li>Stores in a local variable authorizator instance.</li>
108      * <li>Stores in a local variable security session manager instance.</li>
109      * </ol>
110      *
111      * @param filterConfig FilterConfig filter configutarion.
112      * @throws ServletException if an exception has occurred that interferes with the
113      * filter's normal operation
114      * @see javax.servlet.Filter#init(FilterConfig)
115      */
116     public void init(FilterConfig filterConfig) throws ServletException {
117         super.init(filterConfig);
118 
119         this.loginPage = filterConfig.getInitParameter(LOGIN_PAGE_PARAM);
120         if (this.loginPage == null) {
121             throw new UnavailableException("Invalid loginPage value");
122         }
123 
124         String loginTriesStr = filterConfig.getInitParameter(LOGIN_TRIES_PARAM);
125         if (loginTriesStr != null) {
126 
127             try {
128                 this.loginTries = Integer.parseInt(loginTriesStr);
129             }
130             catch (NumberFormatException nfe) {
131                 this.loginTries = DEFAULT_LOGIN_TRIES;
132             }
133 
134         }
135         else {
136             this.loginTries = DEFAULT_LOGIN_TRIES;
137         }
138 
139         this.securitySessionManager = SecuritySessionManager.getInstance();
140         this.authenticator = getContext().getAuthenticator();
141         this.authorizator = getContext().getAuthorizator();
142 
143     }
144 
145     /**
146      * Checks if client's request has a valid security session and if not tries to
147      * authenticate client.<br>
148      * <br>
149      * Filter checks if command is restricted, then checks if there is a valid
150      * security session, if there is continue with next filter in chain.<br>
151      * If not saves current request for later resume and forwards to login page. In
152      * next invocation obtains username and password from login request and tries to
153      * authenticate client with them. Repeats proccess number of times in login tries.
154      * If authentication is valid resumes saved request.
155      *
156      * @param request ServletRequest the <code>ServletRequest</code> object
157      * that contains the client's request.
158      * @param response ServletResponse the <code>ServletResponse</code> object
159      * that contains the servlet's response.
160      * @param chain FilterChain invocation chain of filtered request.
161      * @throws IOException if an input or output exception occurs
162      * @throws ServletException if an exception has occurred that interferes with the
163      * filter's normal operation
164      * @see javax.servlet.Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
165      */
166     public void doFilter(ServletRequest request, ServletResponse response,
167     FilterChain chain)
168     throws IOException, ServletException {
169 
170         if (getLogger().isDebugEnabled()) {
171             getLogger().logDebug(getFilterConfig().getFilterName() + ": invoked");
172         }
173 
174         try {
175 
176             // Check command existence
177             Command cmd = findCommand(request);
178 
179             // Get LoginSession if exists
180             LoginSession loginSession = getLoginSession((HttpServletRequest) request);
181 
182             // Get username and password sent.
183             String username = request.getParameter(Globals.USERNAME_PARAMETER);
184             String password = request.getParameter(Globals.PASSWORD_PARAMETER);
185 
186             // Is restricted command?
187             if (((cmd != null) && authorizator.isRestricted(cmd)) ||
188                 ((username != null) || (password != null))) {
189 
190                 // Is security session valid?
191                 if (!securitySessionManager.isSecuritySessionValid((HttpServletRequest) request)) {
192 
193                     try {
194 
195                         processLogin((HttpServletRequest) request, username, password);
196 
197                     }
198                     catch (AuthenticationFailedException afe) {
199 
200                         loginSession.incTries();
201                         if (loginSession.getTries() > this.loginTries) {
202                             throw new AuthenticationRequiredException();
203                         }
204                         else {
205                             request.getRequestDispatcher(this.loginPage).forward(request, response);
206                             return;
207                         }
208 
209                     }
210 
211                     // Resume request
212                     chain.doFilter(new LoginRequestWrapper((HttpServletRequest) request,
213                                                            loginSession.getParameters(),
214                                                            loginSession.getAttributes()),
215                                    response);
216 
217                 }
218 
219             }
220             else {
221                 chain.doFilter(request, response);
222             }
223 
224         }
225         catch (ServletException se) {
226             throw se;
227         }
228         catch (Throwable t) {
229             throw new ServletException(t);
230         }
231 
232     }
233 
234     /**
235      * Tries to log client using username and password. If authentication is correct
236      * creates a new <code>SecuritySession</code> and stores it in client's
237      * <code>HttpSession</code>.
238      *
239      * @param request HttpServletRequest client's request.
240      * @param username String user name.
241      * @param password String user password.
242      * @throws AuthenticationFailedException if can't authenticate user using given
243      * username and passowrd.
244      */
245     protected void processLogin(HttpServletRequest request, String username, String password)
246     throws AuthenticationFailedException {
247 
248        if ((username != null) && (password != null)) {
249 
250             SecuritySession securitySession =
251                                 authenticator.login(username, password);
252 
253             securitySessionManager.saveSecuritySession(request, securitySession);
254 
255             removeLoginSession(request);
256 
257         }
258         else {
259             throw new AuthenticationFailedException();
260         }
261 
262     }
263 
264     /**
265      * Retrieves <code>LoginSession</code> from client's request.
266      *
267      * @param request HttpServletRequest client's request.
268      * @return LoginSession session obtained or <code>null</code>.
269      */
270     private LoginSession getLoginSession(HttpServletRequest request) {
271         LoginSession loginSession =  (LoginSession) request.getSession().getAttribute(Globals.LOGIN_SESSION_ATTR);
272         if (loginSession == null) {
273             loginSession = new LoginSession(request);
274             request.getSession().setAttribute(Globals.LOGIN_SESSION_ATTR, loginSession);
275         }
276         return loginSession;
277     }
278 
279     /**
280      * Removes <code>LoginSession</code> from client's request.
281      *
282      * @param request HttpServletRequest client's request.
283      */
284     private void removeLoginSession(HttpServletRequest request) {
285         request.removeAttribute(Globals.LOGIN_SESSION_ATTR);
286     }
287 
288 }