KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > geronimo > tomcat > realm > TomcatGeronimoRealm


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

17 package org.apache.geronimo.tomcat.realm;
18
19 import org.apache.catalina.Context;
20 import org.apache.catalina.LifecycleException;
21 import org.apache.catalina.connector.Request;
22 import org.apache.catalina.connector.Response;
23 import org.apache.catalina.deploy.LoginConfig;
24 import org.apache.catalina.deploy.SecurityConstraint;
25 import org.apache.catalina.realm.JAASRealm;
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28 import org.apache.geronimo.security.ContextManager;
29 import org.apache.geronimo.security.jacc.PolicyContextHandlerContainerSubject;
30 import org.apache.geronimo.security.realm.providers.CertificateChainCallbackHandler;
31 import org.apache.geronimo.security.realm.providers.PasswordCallbackHandler;
32 import org.apache.geronimo.tomcat.JAASTomcatPrincipal;
33
34 import javax.security.auth.Subject JavaDoc;
35 import javax.security.auth.callback.CallbackHandler JavaDoc;
36 import javax.security.auth.login.AccountExpiredException JavaDoc;
37 import javax.security.auth.login.CredentialExpiredException JavaDoc;
38 import javax.security.auth.login.FailedLoginException JavaDoc;
39 import javax.security.auth.login.LoginContext JavaDoc;
40 import javax.security.auth.login.LoginException JavaDoc;
41 import javax.security.jacc.PolicyContext JavaDoc;
42 import javax.security.jacc.PolicyContextException JavaDoc;
43 import javax.security.jacc.WebResourcePermission JavaDoc;
44 import javax.security.jacc.WebRoleRefPermission JavaDoc;
45 import javax.security.jacc.WebUserDataPermission JavaDoc;
46
47 import java.io.IOException JavaDoc;
48 import java.security.AccessControlContext JavaDoc;
49 import java.security.AccessControlException JavaDoc;
50 import java.security.Principal JavaDoc;
51 import java.security.cert.X509Certificate JavaDoc;
52
53
54 public class TomcatGeronimoRealm extends JAASRealm {
55
56     private static final Log log = LogFactory.getLog(TomcatGeronimoRealm.class);
57
58     private static ThreadLocal JavaDoc currentRequestWrapperName = new ThreadLocal JavaDoc();
59
60     /**
61      * Descriptive information about this <code>Realm</code> implementation.
62      */

63     protected static final String JavaDoc info = "org.apache.geronimo.tomcat.TomcatGeronimoRealm/1.0";
64
65     /**
66      * Descriptive information about this <code>Realm</code> implementation.
67      */

68     protected static final String JavaDoc name = "TomcatGeronimoRealm";
69
70     public TomcatGeronimoRealm() {
71
72      }
73
74     public static String JavaDoc setRequestWrapperName(String JavaDoc requestWrapperName) {
75         String JavaDoc old = (String JavaDoc) currentRequestWrapperName.get();
76         currentRequestWrapperName.set(requestWrapperName);
77         return old;
78     }
79
80     /**
81      * Enforce any user data constraint required by the security constraint
82      * guarding this request URI. Return <code>true</code> if this constraint
83      * was not violated and processing should continue, or <code>false</code>
84      * if we have created a response already.
85      *
86      * @param request Request we are processing
87      * @param response Response we are creating
88      * @param constraints Security constraint being checked
89      * @throws IOException if an input/output error occurs
90      */

91     public boolean hasUserDataPermission(Request request,
92                                          Response response,
93                                          SecurityConstraint[] constraints)
94             throws IOException JavaDoc {
95
96         //Get an authenticated subject, if there is one
97
Subject subject = null;
98         try {
99
100             //We will use the PolicyContextHandlerContainerSubject.HANDLER_KEY to see if a user
101
//has authenticated, since a request.getUserPrincipal() will not pick up the user
102
//unless its using a cached session.
103
subject = (Subject) PolicyContext.getContext(PolicyContextHandlerContainerSubject.HANDLER_KEY);
104
105         } catch (PolicyContextException JavaDoc e) {
106             log.error(e);
107         }
108
109         //If nothing has authenticated yet, do the normal
110
if (subject == null)
111             return super.hasUserDataPermission(request, response, constraints);
112
113         ContextManager.setCallers(subject, subject);
114
115         try {
116
117             AccessControlContext JavaDoc acc = ContextManager.getCurrentContext();
118
119             /**
120              * JACC v1.0 secion 4.1.1
121              */

122             WebUserDataPermission JavaDoc wudp = new WebUserDataPermission JavaDoc(request);
123             acc.checkPermission(wudp);
124
125         } catch (AccessControlException JavaDoc ace) {
126             response.sendError(Response.SC_FORBIDDEN);
127             return false;
128         }
129
130         return true;
131     }
132
133     /**
134      * Perform access control based on the specified authorization constraint.
135      * Return <code>true</code> if this constraint is satisfied and processing
136      * should continue, or <code>false</code> otherwise.
137      *
138      * @param request Request we are processing
139      * @param response Response we are creating
140      * @param constraints Security constraints we are enforcing
141      * @param context The Context to which client of this class is attached.
142      * @throws java.io.IOException if an input/output error occurs
143      */

144     public boolean hasResourcePermission(Request request,
145                                          Response response,
146                                          SecurityConstraint[] constraints,
147                                          Context context)
148             throws IOException JavaDoc {
149
150         // Specifically allow access to the form login and form error pages
151
// and the "j_security_check" action
152
LoginConfig config = context.getLoginConfig();
153         if ((config != null) &&
154             (org.apache.catalina.realm.Constants.FORM_METHOD.equals(config.getAuthMethod()))) {
155             String JavaDoc requestURI = request.getDecodedRequestURI();
156             String JavaDoc loginPage = context.getPath() + config.getLoginPage();
157             if (loginPage.equals(requestURI)) {
158                 if (log.isDebugEnabled())
159                     log.debug(" Allow access to login page " + loginPage);
160                 return (true);
161             }
162             String JavaDoc errorPage = context.getPath() + config.getErrorPage();
163             if (errorPage.equals(requestURI)) {
164                 if (log.isDebugEnabled())
165                     log.debug(" Allow access to error page " + errorPage);
166                 return (true);
167             }
168             if (requestURI.endsWith(org.apache.catalina.realm.Constants.FORM_ACTION)) {
169                 if (log.isDebugEnabled())
170                     log.debug(" Allow access to username/password submission");
171                 return (true);
172             }
173         }
174         
175         //Set the current wrapper name (Servlet mapping)
176
currentRequestWrapperName.set(request.getWrapper().getName());
177
178         // Which user principal have we already authenticated?
179
Principal principal = request.getUserPrincipal();
180
181         //If we have no principal, then we should use the default.
182
if (principal == null) {
183             return request.isSecure();
184
185         } else {
186             Subject currentCaller = ((JAASTomcatPrincipal) principal).getSubject();
187             ContextManager.setCallers(currentCaller, currentCaller);
188         }
189
190         try {
191
192             AccessControlContext JavaDoc acc = ContextManager.getCurrentContext();
193
194
195             /**
196              * JACC v1.0 section 4.1.2
197              */

198             acc.checkPermission(new WebResourcePermission JavaDoc(request));
199
200         } catch (AccessControlException JavaDoc ace) {
201             response.sendError(Response.SC_FORBIDDEN);
202             return false;
203         }
204
205         return true;
206
207     }
208
209     /**
210      * Return <code>true</code> if the specified Principal has the specified
211      * security role, within the context of this Realm; otherwise return
212      * <code>false</code>.
213      *
214      * @param principal Principal for whom the role is to be checked
215      * @param role Security role to be checked
216      */

217     public boolean hasRole(Principal principal, String JavaDoc role) {
218
219         if ((principal == null) || (role == null) || !(principal instanceof JAASTomcatPrincipal)) {
220             return false;
221         }
222
223         String JavaDoc name = (String JavaDoc)currentRequestWrapperName.get();
224
225         /**
226          * JACC v1.0 secion B.19
227          */

228         if (name == null || name.equals("jsp")) {
229             name = "";
230         }
231
232         //Set the caller
233
Subject currentCaller = ((JAASTomcatPrincipal) principal).getSubject();
234         ContextManager.setCallers(currentCaller, currentCaller);
235
236         AccessControlContext JavaDoc acc = ContextManager.getCurrentContext();
237
238         try {
239             /**
240              * JACC v1.0 section 4.1.3
241              */

242             acc.checkPermission(new WebRoleRefPermission JavaDoc(name, role));
243         } catch (AccessControlException JavaDoc e) {
244             return false;
245         }
246
247         return true;
248     }
249
250     /**
251      * Return the <code>Principal</code> associated with the specified
252      * username and credentials, if there is one; otherwise return
253      * <code>null</code>.
254      * <p/>
255      * If there are any errors with the JDBC connection, executing the query or
256      * anything we return null (don't authenticate). This event is also logged,
257      * and the connection will be closed so that a subsequent request will
258      * automatically re-open it.
259      *
260      * @param username Username of the <code>Principal</code> to look up
261      * @param credentials Password or other credentials to use in authenticating this
262      * username
263      */

264     public Principal authenticate(String JavaDoc username, String JavaDoc credentials) {
265
266         char[] cred = credentials == null? null: credentials.toCharArray();
267         CallbackHandler callbackHandler = new PasswordCallbackHandler(username, cred);
268         return authenticate(callbackHandler, username);
269     }
270
271     public Principal authenticate(X509Certificate JavaDoc[] certs) {
272         if (certs == null || certs.length == 0) {
273             return null;
274         }
275         CallbackHandler callbackHandler = new CertificateChainCallbackHandler(certs);
276         String JavaDoc principalName = certs[0].getSubjectX500Principal().getName();
277         return authenticate(callbackHandler, principalName);
278     }
279
280     public Principal authenticate(CallbackHandler callbackHandler, String JavaDoc principalName) {
281
282         // Establish a LoginContext to use for authentication
283
try {
284
285             if ( (principalName!=null) && (!principalName.equals("")) ) {
286               LoginContext JavaDoc loginContext = null;
287               if (appName == null)
288                   appName = "Tomcat";
289
290               if (log.isDebugEnabled())
291                   log.debug(sm.getString("jaasRealm.beginLogin", principalName, appName));
292
293               // What if the LoginModule is in the container class loader ?
294
ClassLoader JavaDoc ocl = null;
295
296               if (isUseContextClassLoader()) {
297                   ocl = Thread.currentThread().getContextClassLoader();
298                   Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
299               }
300
301               try {
302                   loginContext = new LoginContext JavaDoc(appName, callbackHandler);
303               } catch (Throwable JavaDoc e) {
304                   log.error(sm.getString("jaasRealm.unexpectedError"), e);
305                   return (null);
306               } finally {
307                   if (isUseContextClassLoader()) {
308                       Thread.currentThread().setContextClassLoader(ocl);
309                   }
310               }
311
312               if (log.isDebugEnabled())
313                   log.debug("Login context created " + principalName);
314
315               // Negotiate a login via this LoginContext
316
Subject subject;
317               try {
318                   loginContext.login();
319                   Subject tempSubject = loginContext.getSubject();
320                   if (tempSubject == null) {
321                       if (log.isDebugEnabled())
322                           log.debug(sm.getString("jaasRealm.failedLogin", principalName));
323                       return (null);
324                   }
325
326                   subject = ContextManager.getServerSideSubject(tempSubject);
327                   if (subject == null) {
328                       if (log.isDebugEnabled())
329                           log.debug(sm.getString("jaasRealm.failedLogin", principalName));
330                       return (null);
331                   }
332
333                   ContextManager.setCallers(subject, subject);
334
335               } catch (AccountExpiredException JavaDoc e) {
336                   if (log.isDebugEnabled())
337                       log.debug(sm.getString("jaasRealm.accountExpired", principalName));
338                   return (null);
339               } catch (CredentialExpiredException JavaDoc e) {
340                   if (log.isDebugEnabled())
341                       log.debug(sm.getString("jaasRealm.credentialExpired", principalName));
342                   return (null);
343               } catch (FailedLoginException JavaDoc e) {
344                   if (log.isDebugEnabled())
345                       log.debug(sm.getString("jaasRealm.failedLogin", principalName));
346                   return (null);
347               } catch (LoginException JavaDoc e) {
348                   log.warn(sm.getString("jaasRealm.loginException", principalName), e);
349                   return (null);
350               } catch (Throwable JavaDoc e) {
351                   log.error(sm.getString("jaasRealm.unexpectedError"), e);
352                   return (null);
353               }
354
355               if (log.isDebugEnabled())
356                   log.debug(sm.getString("jaasRealm.loginContextCreated", principalName));
357
358               // Return the appropriate Principal for this authenticated Subject
359
/* Principal principal = createPrincipal(username, subject);
360               if (principal == null) {
361                   log.debug(sm.getString("jaasRealm.authenticateFailure", username));
362                   return (null);
363               }
364               if (log.isDebugEnabled()) {
365                   log.debug(sm.getString("jaasRealm.authenticateSuccess", username));
366               }
367   */

368               JAASTomcatPrincipal jaasPrincipal = new JAASTomcatPrincipal(principalName);
369               jaasPrincipal.setSubject(subject);
370
371               return (jaasPrincipal);
372             }
373             else {
374                 if (log.isDebugEnabled())
375                     log.debug("Login Failed - null userID");
376                 return null;
377             }
378
379         } catch (Throwable JavaDoc t) {
380             log.error("error ", t);
381             return null;
382         }
383     }
384     /**
385      * Prepare for active use of the public methods of this <code>Component</code>.
386      *
387      * @throws org.apache.catalina.LifecycleException
388      * if this component detects a fatal error
389      * that prevents it from being started
390      */

391     public void start() throws LifecycleException {
392
393         // Perform normal superclass initialization
394
super.start();
395
396     }
397
398     /**
399      * Gracefully shut down active use of the public methods of this <code>Component</code>.
400      *
401      * @throws LifecycleException if this component detects a fatal error
402      * that needs to be reported
403      */

404     public void stop() throws LifecycleException {
405
406         // Perform normal superclass finalization
407
super.stop();
408
409     }
410 }
411
Popular Tags