KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cactus > client > authentication > FormAuthentication


1 /*
2  * ========================================================================
3  *
4  * Copyright 2001-2004 The Apache Software Foundation.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * ========================================================================
19  */

20 package org.apache.cactus.client.authentication;
21
22 import java.net.HttpURLConnection JavaDoc;
23 import java.net.MalformedURLException JavaDoc;
24 import java.net.URL JavaDoc;
25
26 import org.apache.cactus.Cookie;
27 import org.apache.cactus.WebRequest;
28 import org.apache.cactus.internal.WebRequestImpl;
29 import org.apache.cactus.internal.client.connector.http.HttpClientConnectionHelper;
30 import org.apache.cactus.internal.configuration.Configuration;
31 import org.apache.cactus.internal.configuration.WebConfiguration;
32 import org.apache.cactus.util.ChainedRuntimeException;
33 import org.apache.commons.httpclient.HttpMethod;
34 import org.apache.commons.httpclient.HttpState;
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37
38 /**
39  * Form-based authentication implementation. An instance of this class
40  * can be reused across several tests as it caches the session cookie.
41  * Thus the first time it is used to authenticate the user, it calls
42  * the security URL (which is by default the context URL prepended by
43  * "j_security_check"), caches the returned session cookie and adds the
44  * cookie for the next request. The second time it is called, it simply
45  * addes the session cookie for the next request.
46  *
47  * @since 1.5
48  *
49  * @version $Id: FormAuthentication.java,v 1.1 2004/05/22 11:34:48 vmassol Exp $
50  */

51 public class FormAuthentication extends AbstractAuthentication
52 {
53     /**
54      * The logger.
55      */

56     private static final Log LOGGER =
57         LogFactory.getLog(FormAuthentication.class);
58
59     /**
60      * The expected HTTP response status code when the authentication
61      * is succeeded.
62      */

63     private int expectedAuthResponse = HttpURLConnection.HTTP_MOVED_TEMP;
64
65     /**
66      * The URL to use when attempting to log in, if for whatever reason
67      * the default URL is incorrect.
68      */

69     private URL JavaDoc securityCheckURL;
70
71     /**
72      * The cookie name of the session.
73      */

74     private String JavaDoc sessionCookieName = "JSESSIONID";
75
76     /**
77      * We store the session cookie.
78      */

79     private Cookie jsessionCookie;
80
81     /**
82      * {@link WebRequest} object that will be used to connect to the
83      * security URL.
84      */

85     private WebRequest securityRequest = new WebRequestImpl();
86       
87     /**
88      * @param theName user name of the Credential
89      * @param thePassword user password of the Credential
90      */

91     public FormAuthentication(String JavaDoc theName, String JavaDoc thePassword)
92     {
93         super(theName, thePassword);
94     }
95     
96     /**
97      * @see Authentication#configure
98      */

99     public void configure(HttpState theState, HttpMethod theMethod,
100         WebRequest theRequest, Configuration theConfiguration)
101     {
102         // Only authenticate the first time this instance is used.
103
if (this.jsessionCookie == null)
104         {
105            authenticate(theRequest, theConfiguration);
106         }
107
108         // Sets the session id cookie for the next request.
109
if (this.jsessionCookie != null)
110         {
111             theRequest.addCookie(this.jsessionCookie);
112         }
113     }
114
115     /**
116      * @return the {@link WebRequest} that will be used to connect to the
117      * security URL. It can be used to add additional HTTP parameters such
118      * as proprietary ones required by some containers.
119      */

120     public WebRequest getSecurityRequest()
121     {
122         return this.securityRequest;
123     }
124     
125     /**
126      * This sets the URL to use when attempting to log in. This method is used
127      * if for whatever reason the default URL is incorrect.
128      *
129      * @param theUrl A URL to use to attempt to login.
130      */

131     public void setSecurityCheckURL(URL JavaDoc theUrl)
132     {
133         this.securityCheckURL = theUrl;
134     }
135     
136     /**
137      * This returns the URL to use when attempting to log in. By default, it's
138      * the context URL defined in the Cactus configuration with
139      * "/j_security_check" appended.
140      *
141      * @param theConfiguration the Cactus configuration
142      * @return the URL that is being used to attempt to login.
143      */

144     public URL JavaDoc getSecurityCheckURL(Configuration theConfiguration)
145     {
146         if (this.securityCheckURL == null)
147         {
148             // Configure default
149
String JavaDoc stringUrl =
150                 ((WebConfiguration) theConfiguration).getContextURL()
151                 + "/j_security_check";
152
153             try
154             {
155                 this.securityCheckURL = new URL JavaDoc(stringUrl);
156             }
157             catch (MalformedURLException JavaDoc e)
158             {
159                 throw new ChainedRuntimeException(
160                     "Unable to create default Security Check URL ["
161                     + stringUrl + "]");
162             }
163         }
164
165         LOGGER.debug("Using security check URL [" + this.securityCheckURL
166             + "]");
167
168         return securityCheckURL;
169     }
170
171
172     /**
173      * Get the cookie name of the session.
174      * @return the cookie name of the session
175      */

176     private String JavaDoc getSessionCookieName()
177     {
178         return this.sessionCookieName;
179     }
180
181     /**
182      * Set the cookie name of the session to theName.
183      * If theName is null, the change request will be ignored.
184      * The default is &quot;<code>JSESSIONID</code>&quot;.
185      * @param theName the cookie name of the session
186      */

187     public void setSessionCookieName(String JavaDoc theName)
188     {
189         if (theName != null)
190         {
191             this.sessionCookieName = theName;
192         }
193     }
194
195
196     /**
197      * Get the expected HTTP response status code for an authentication request
198      * which should be successful.
199      * @return the expected HTTP response status code
200      */

201     protected int getExpectedAuthResponse()
202     {
203         return this.expectedAuthResponse;
204     }
205
206     /**
207      * Set the expected HTTP response status code for an authentication request
208      * which should be successful.
209      * The default is HttpURLConnection.HTTP_MOVED_TEMP.
210      * @param theExpectedCode the expected HTTP response status code value
211      */

212     public void setExpectedAuthResponse(int theExpectedCode)
213     {
214         this.expectedAuthResponse = theExpectedCode;
215     }
216
217
218     /**
219      * Get a cookie required to be set by set-cookie header field.
220      * @param theConnection a {@link HttpURLConnection}
221      * @param theTarget the target cookie name
222      * @return the {@link Cookie}
223      */

224     private Cookie getCookie(HttpURLConnection JavaDoc theConnection, String JavaDoc theTarget)
225     {
226         // Check (possible multiple) cookies for a target.
227
int i = 1;
228         String JavaDoc key = theConnection.getHeaderFieldKey(i);
229         while (key != null)
230         {
231             if (key.equalsIgnoreCase("set-cookie"))
232             {
233                 // Cookie is in the form:
234
// "NAME=VALUE; expires=DATE; path=PATH;
235
// domain=DOMAIN_NAME; secure"
236
// The only thing we care about is finding a cookie with
237
// the name "JSESSIONID" and caching the value.
238
String JavaDoc cookiestr = theConnection.getHeaderField(i);
239                 String JavaDoc nameValue = cookiestr.substring(0,
240                     cookiestr.indexOf(";"));
241                 int equalsChar = nameValue.indexOf("=");
242                 String JavaDoc name = nameValue.substring(0, equalsChar);
243                 String JavaDoc value = nameValue.substring(equalsChar + 1);
244                 if (name.equalsIgnoreCase(theTarget))
245                 {
246                     return new Cookie(theConnection.getURL().getHost(),
247                         name, value);
248                 }
249             }
250             key = theConnection.getHeaderFieldKey(++i);
251         }
252         return null;
253     }
254
255
256     /**
257      * Check if the pre-auth step can be considered as succeeded or not.
258      * As default, the step considered as succeeded
259      * if the response status code of <code>theConnection</code>
260      * is less than 400.
261      *
262      * @param theConnection a <code>HttpURLConnection</code> value
263      * @exception Exception if the pre-auth step should be considered as failed
264      */

265     protected void checkPreAuthResponse(HttpURLConnection JavaDoc theConnection)
266         throws Exception JavaDoc
267     {
268         if (theConnection.getResponseCode() >= 400)
269         {
270             throw new Exception JavaDoc("Received a status code ["
271                 + theConnection.getResponseCode()
272                 + "] and was expecting less than 400");
273         }
274     }
275
276
277     /**
278      * Get login session cookie.
279      * This is the first step to start login session:
280      * <dl>
281      * <dt> C-&gt;S: </dt>
282      * <dd> try to connect to a restricted resource </dd>
283      * <dt> S-&gt;C: </dt>
284      * <dd> redirect or forward to the login page with set-cookie header </dd>
285      * </ol>
286      * @param theRequest a request to connect to a restricted resource
287      * @param theConfiguration a <code>Configuration</code> value
288      * @return the <code>Cookie</code>
289      */

290     private Cookie getSecureSessionIdCookie(WebRequest theRequest,
291         Configuration theConfiguration)
292     {
293         HttpURLConnection JavaDoc connection;
294         String JavaDoc resource = null;
295
296         try
297         {
298             // Create a helper that will connect to a restricted resource.
299
WebConfiguration webConfig = (WebConfiguration) theConfiguration;
300             resource = webConfig.getRedirectorURL(theRequest);
301
302             HttpClientConnectionHelper helper =
303                 new HttpClientConnectionHelper(resource);
304
305             WebRequest request =
306                 new WebRequestImpl((WebConfiguration) theConfiguration);
307
308             // Make the connection using a default web request.
309
connection = helper.connect(request, theConfiguration);
310
311             checkPreAuthResponse(connection);
312         }
313         catch (Throwable JavaDoc e)
314         {
315             throw new ChainedRuntimeException(
316                 "Failed to connect to the secured redirector: " + resource, e);
317         }
318
319         return getCookie(connection, getSessionCookieName());
320     }
321
322
323     /**
324      * Check if the auth step can be considered as succeeded or not.
325      * As default, the step considered as succeeded
326      * if the response status code of <code>theConnection</code>
327      * equals <code>getExpectedAuthResponse()</code>.
328      *
329      * @param theConnection a <code>HttpURLConnection</code> value
330      * @exception Exception if the auth step should be considered as failed
331      */

332     protected void checkAuthResponse(HttpURLConnection JavaDoc theConnection)
333         throws Exception JavaDoc
334     {
335         if (theConnection.getResponseCode() != getExpectedAuthResponse())
336         {
337             throw new Exception JavaDoc("Received a status code ["
338                 + theConnection.getResponseCode()
339                 + "] and was expecting a ["
340                 + getExpectedAuthResponse() + "]");
341         }
342     }
343
344
345     /**
346      * Authenticate the principal by calling the security URL.
347      *
348      * @param theRequest the web request used to connect to the Redirector
349      * @param theConfiguration the Cactus configuration
350      */

351     public void authenticate(WebRequest theRequest,
352         Configuration theConfiguration)
353     {
354         this.jsessionCookie = getSecureSessionIdCookie(theRequest,
355             theConfiguration);
356     
357         try
358         {
359             // Create a helper that will connect to the security check URL.
360
HttpClientConnectionHelper helper =
361                 new HttpClientConnectionHelper(
362                     getSecurityCheckURL(theConfiguration).toString());
363
364             // Configure a web request with the JSESSIONID cookie,
365
// the username and the password.
366
WebRequest request = getSecurityRequest();
367             ((WebRequestImpl) request).setConfiguration(theConfiguration);
368             request.addCookie(this.jsessionCookie);
369             request.addParameter("j_username", getName(),
370                 WebRequest.POST_METHOD);
371             request.addParameter("j_password", getPassword(),
372                 WebRequest.POST_METHOD);
373
374             // Make the connection using the configured web request.
375
HttpURLConnection JavaDoc connection = helper.connect(request,
376                 theConfiguration);
377
378             checkAuthResponse(connection);
379         }
380         catch (Throwable JavaDoc e)
381         {
382             this.jsessionCookie = null;
383             throw new ChainedRuntimeException(
384                 "Failed to authenticate the principal", e);
385         }
386     }
387 }
388
Popular Tags