KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > web > tomcat > security > JBossWebRealm


1 /*
2   * JBoss, Home of Professional Open Source
3   * Copyright 2005, JBoss Inc., and individual contributors as indicated
4   * by the @authors tag. See the copyright.txt in the distribution for a
5   * full listing of individual contributors.
6   *
7   * This is free software; you can redistribute it and/or modify it
8   * under the terms of the GNU Lesser General Public License as
9   * published by the Free Software Foundation; either version 2.1 of
10   * the License, or (at your option) any later version.
11   *
12   * This software 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 GNU
15   * Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this software; if not, write to the Free
19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21   */

22 package org.jboss.web.tomcat.security;
23
24 import java.io.IOException JavaDoc;
25 import java.lang.reflect.Method JavaDoc;
26 import java.security.Policy JavaDoc;
27 import java.security.Principal JavaDoc;
28 import java.security.cert.X509Certificate JavaDoc;
29 import java.util.ArrayList JavaDoc;
30 import java.util.Collections JavaDoc;
31 import java.util.HashMap JavaDoc;
32 import java.util.HashSet JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.List JavaDoc;
35 import java.util.Map JavaDoc;
36 import java.util.Set JavaDoc;
37
38 import javax.naming.Context JavaDoc;
39 import javax.naming.InitialContext JavaDoc;
40 import javax.naming.NamingException JavaDoc;
41 import javax.security.auth.Subject JavaDoc;
42 import javax.security.jacc.PolicyContext JavaDoc;
43 import javax.security.jacc.PolicyContextException JavaDoc;
44 import javax.servlet.http.HttpServletRequest JavaDoc;
45 import javax.servlet.http.HttpServletResponse JavaDoc;
46
47 import org.apache.catalina.Wrapper;
48 import org.apache.catalina.connector.Request;
49 import org.apache.catalina.connector.Response;
50 import org.apache.catalina.deploy.SecurityConstraint;
51 import org.apache.catalina.realm.GenericPrincipal;
52 import org.apache.catalina.realm.RealmBase;
53 import org.jboss.logging.Logger;
54 import org.jboss.metadata.SecurityRoleRefMetaData;
55 import org.jboss.metadata.WebMetaData;
56 import org.jboss.security.AuthorizationManager;
57 import org.jboss.security.CertificatePrincipal;
58 import org.jboss.security.RealmMapping;
59 import org.jboss.security.SecurityConstants;
60 import org.jboss.security.SecurityContext;
61 import org.jboss.security.SimplePrincipal;
62 import org.jboss.security.SubjectSecurityManager;
63 import org.jboss.security.SecurityContext.SubjectInfo;
64 import org.jboss.security.audit.AuditContext;
65 import org.jboss.security.audit.AuditEvent;
66 import org.jboss.security.audit.AuditLevel;
67 import org.jboss.security.audit.AuditManager;
68 import org.jboss.security.auth.callback.CallbackHandlerPolicyContextHandler;
69 import org.jboss.security.auth.certs.SubjectDNMapping;
70 import org.jboss.security.authorization.AuthorizationContext;
71 import org.jboss.security.authorization.AuthorizationException;
72 import org.jboss.security.authorization.ResourceKeys;
73 import org.jboss.security.plugins.JBossSecurityContext;
74 import org.jboss.web.tomcat.security.authorization.WebResource;
75
76 //$Id: JBossWebRealm.java 58442 2006-11-16 06:28:15Z anil.saldhana@jboss.com $
77

78 /**
79  * Implementation of the Tomcat Realm Interface.
80  * The Realm implementation handles authentication and authorization
81  * using the JBossSX security framework. It relies on the JNDI ENC namespace
82  * setup by the AbstractWebContainer. In particular, it uses the java:comp/env/security
83  * subcontext to access the security manager interfaces for authentication.
84  * @author <a HREF="mailto:Anil.Saldhana@jboss.org">Anil Saldhana</a>
85  * @since Jul 10, 2006
86  * @version $Revision: 58442 $
87  */

88 public class JBossWebRealm extends RealmBase
89 {
90    static Logger log = Logger.getLogger(JBossWebRealm.class);
91    /**
92     * The converter from X509 cert chain to Princpal
93     */

94    protected CertificatePrincipal certMapping = new SubjectDNMapping();
95    /**
96     * The JBossSecurityMgrRealm category trace flag
97     */

98    private boolean trace = log.isTraceEnabled();
99    
100    /** The current servlet request */
101    private static ThreadLocal JavaDoc activeRequest = new ThreadLocal JavaDoc();
102    
103    /** The JACC PolicyContext key for the current Subject */
104    private static final String JavaDoc SUBJECT_CONTEXT_KEY = "javax.security.auth.Subject.container";
105    
106    protected String JavaDoc securityDomain = SecurityConstants.DEFAULT_WEB_APPLICATION_POLICY;
107    
108    /**
109     * JBAS-2519:Delegate to JACC provider for unsecured resources in web.xml
110     */

111    protected boolean unprotectedResourceDelegation = false;
112    protected String JavaDoc securityConstraintProviderClass = "";
113    
114    /** Should Security Audit be done **/
115    protected boolean enableAudit = true;
116    
117    /** Should RealmBase Authorization decision be considered or not?
118     * false - consider, true - do not consider
119     */

120    protected boolean ignoreBaseDecision = false;
121    
122    /**
123     * Set the class name of the CertificatePrincipal used for mapping X509 cert
124     * chains to a Princpal.
125     *
126     * @param className the CertificatePrincipal implementation class that must
127     * have a no-arg ctor.
128     * @see org.jboss.security.CertificatePrincipal
129     */

130    public void setCertificatePrincipal(String JavaDoc className)
131    {
132       try
133       {
134          ClassLoader JavaDoc loader = Thread.currentThread().getContextClassLoader();
135          Class JavaDoc cpClass = loader.loadClass(className);
136          certMapping = (CertificatePrincipal) cpClass.newInstance();
137       }
138       catch (Exception JavaDoc e)
139       {
140          log.error("Failed to load CertificatePrincipal: " + className, e);
141          certMapping = new SubjectDNMapping();
142       }
143    }
144
145    public void setSecurityConstraintProviderClass(String JavaDoc securityConstraintProviderClass)
146    {
147       this.securityConstraintProviderClass = securityConstraintProviderClass;
148    }
149
150    /**
151     * Override the security domain driving the authorization for the realm
152     * @param securityDomain
153     */

154    public void setSecurityDomain(String JavaDoc securityDomain)
155    {
156       this.securityDomain = securityDomain;
157    }
158
159    public void setUnprotectedResourceDelegation(boolean unprotectedResourceDelegation)
160    {
161       this.unprotectedResourceDelegation = unprotectedResourceDelegation;
162    }
163
164    public void setEnableAudit(boolean enableAudit)
165    {
166       this.enableAudit = enableAudit;
167    }
168
169    public void setIgnoreBaseDecision(boolean ignoreBaseDecision)
170    {
171       this.ignoreBaseDecision = ignoreBaseDecision;
172    }
173    
174    //*************************************************************************
175
// Realm.Authenticate Methods
176
//*************************************************************************
177

178
179 /**
180     * Return the Principal associated with the specified chain of X509 client
181     * certificates. If there is none, return <code>null</code>.
182     *
183     * @param certs Array of client certificates, with the first one in the array
184     * being the certificate of the client itself.
185     */

186    public Principal JavaDoc authenticate(X509Certificate JavaDoc[] certs)
187    {
188       Principal JavaDoc principal = null;
189       Context JavaDoc securityCtx = getSecurityContext();
190       if (securityCtx == null)
191       {
192          if (trace)
193          {
194             log.trace("No security context for authenticate(X509Certificate[])");
195          }
196          return null;
197       }
198
199       try
200       {
201          // Get the JBoss security manager from the ENC context
202
SubjectSecurityManager securityMgr = (SubjectSecurityManager) securityCtx.lookup("securityMgr");
203          Subject JavaDoc subject = new Subject JavaDoc();
204          principal = certMapping.toPrinicipal(certs);
205          if (securityMgr.isValid(principal, certs, subject))
206          {
207             if (trace)
208             {
209                log.trace("User: " + principal + " is authenticated");
210             }
211             SecurityAssociationActions.setPrincipalInfo(principal, certs, subject);
212             
213             securityDomain = securityMgr.getSecurityDomain();
214             //Establish the Security Context
215
this.establishSecurityContext(securityDomain,
216                   principal, certs, subject);
217             
218             // Get the CallerPrincipal mapping
219
RealmMapping realmMapping = (RealmMapping) securityCtx.lookup("realmMapping");
220             Principal JavaDoc oldPrincipal = principal;
221             principal = realmMapping.getPrincipal(oldPrincipal);
222             if (trace)
223             {
224                log.trace("Mapped from input principal: " + oldPrincipal
225                   + "to: " + principal);
226             }
227             // Get the caching principal
228
principal = getCachingPrincpal(realmMapping, oldPrincipal,
229                principal, certs, subject);
230             if(enableAudit)
231                successAudit(oldPrincipal,principal);
232          }
233          else
234          {
235             if (trace)
236             {
237                log.trace("User: " + principal + " is NOT authenticated");
238             }
239             if(enableAudit)
240                failureAudit(principal);
241             principal = null;
242          }
243       }
244       catch (NamingException JavaDoc e)
245       {
246          log.error("Error during authenticate", e);
247          if(enableAudit)
248             errorAudit(principal,e);
249       }
250       return principal;
251    }
252    
253    /**
254     * Return the Principal associated with the specified username, which matches
255     * the digest calculated using the given parameters using the method
256     * described in RFC 2069; otherwise return <code>null</code>.
257     *
258     * @param username Username of the Principal to look up
259     * @param digest Digest which has been submitted by the client
260     * @param nonce Unique (or supposedly unique) token which has been used for
261     * this request
262     * @param nc client nonce reuse count
263     * @param cnonce client token
264     * @param qop quality of protection
265     * @param realm Realm name
266     * @param md5a2 Second MD5 digest used to calculate the digest : MD5(Method +
267     * ":" + uri)
268     */

269    public Principal JavaDoc authenticate(String JavaDoc username, String JavaDoc digest, String JavaDoc nonce,
270       String JavaDoc nc, String JavaDoc cnonce, String JavaDoc qop, String JavaDoc realm, String JavaDoc md5a2)
271    {
272       Principal JavaDoc principal = null;
273       Context JavaDoc securityCtx = getSecurityContext();
274       if (securityCtx == null)
275       {
276          if (trace)
277          {
278             log.trace("No security context for authenticate(String, String)");
279          }
280          return null;
281       }
282
283       Principal JavaDoc caller = (Principal JavaDoc) SecurityAssociationValve.userPrincipal.get();
284       if (caller == null && username == null && digest == null)
285       {
286          return null;
287       }
288
289       try
290       {
291          DigestCallbackHandler handler = new DigestCallbackHandler(username, nonce,
292             nc, cnonce, qop, realm, md5a2);
293          CallbackHandlerPolicyContextHandler.setCallbackHandler(handler);
294
295          // Get the JBoss security manager from the ENC context
296
SubjectSecurityManager securityMgr = (SubjectSecurityManager) securityCtx.lookup("securityMgr");
297          principal = new SimplePrincipal(username);
298          Subject JavaDoc subject = new Subject JavaDoc();
299          if (securityMgr.isValid(principal, digest, subject))
300          {
301             log.trace("User: " + username + " is authenticated");
302             SecurityAssociationActions.setPrincipalInfo(principal, digest, subject);
303             securityDomain = securityMgr.getSecurityDomain();
304             //Establish the Security Context
305
this.establishSecurityContext(securityDomain,
306                   principal, digest, subject);
307             
308             // Get the CallerPrincipal mapping
309
RealmMapping realmMapping = (RealmMapping) securityCtx.lookup("realmMapping");
310             Principal JavaDoc oldPrincipal = principal;
311             principal = realmMapping.getPrincipal(oldPrincipal);
312             if (trace)
313             {
314                log.trace("Mapped from input principal: " + oldPrincipal
315                   + "to: " + principal);
316             }
317             // Get the caching principal
318
principal = getCachingPrincpal(realmMapping, oldPrincipal,
319                principal, digest, subject);
320             if(enableAudit)
321                successAudit(oldPrincipal,principal);
322          }
323          else
324          {
325             if(enableAudit)
326                failureAudit(principal);
327             principal = null;
328             if (trace)
329             {
330                log.trace("User: " + username + " is NOT authenticated");
331             }
332          }
333       }
334       catch (NamingException JavaDoc e)
335       {
336          principal = null;
337          log.error("Error during authenticate", e);
338          if(enableAudit)
339             errorAudit(principal,e);
340       }
341       finally
342       {
343          CallbackHandlerPolicyContextHandler.setCallbackHandler(null);
344       }
345       if (trace)
346       {
347          log.trace("End authenticate, principal=" + principal);
348       }
349       return principal;
350    }
351
352    /**
353     * Return the Principal associated with the specified username and
354     * credentials, if there is one; otherwise return <code>null</code>.
355     *
356     * @param username Username of the Principal to look up
357     * @param credentials Password or other credentials to use in authenticating
358     * this username
359     */

360    public Principal JavaDoc authenticate(String JavaDoc username, String JavaDoc credentials)
361    {
362       if (trace)
363       {
364          log.trace("Begin authenticate, username=" + username);
365       }
366       Principal JavaDoc principal = null;
367       Context JavaDoc securityCtx = getSecurityContext();
368       if (securityCtx == null)
369       {
370          if (trace)
371          {
372             log.trace("No security context for authenticate(String, String)");
373          }
374          return null;
375       }
376
377       Principal JavaDoc caller = (Principal JavaDoc) SecurityAssociationValve.userPrincipal.get();
378       if (caller == null && username == null && credentials == null)
379       {
380          return null;
381       }
382
383       try
384       {
385          // Get the JBoss security manager from the ENC context
386
SubjectSecurityManager securityMgr = (SubjectSecurityManager) securityCtx.lookup("securityMgr");
387          principal = new SimplePrincipal(username);
388          Subject JavaDoc subject = new Subject JavaDoc();
389          if (securityMgr.isValid(principal, credentials, subject))
390          {
391             log.trace("User: " + username + " is authenticated");
392             SecurityAssociationActions.setPrincipalInfo(principal, credentials, subject);
393             securityDomain = securityMgr.getSecurityDomain();
394             //Establish the Security Context
395
this.establishSecurityContext(securityDomain,
396                   principal, credentials, subject);
397             // Get the CallerPrincipal mapping
398
RealmMapping realmMapping = (RealmMapping) securityCtx.lookup("realmMapping");
399             Principal JavaDoc oldPrincipal = principal;
400             principal = realmMapping.getPrincipal(oldPrincipal);
401             if (trace)
402             {
403                log.trace("Mapped from input principal: " + oldPrincipal
404                   + "to: " + principal);
405             }
406             // Get the caching principal
407
principal = getCachingPrincpal(realmMapping, oldPrincipal,
408                principal, credentials, subject);
409             if(enableAudit)
410                successAudit(oldPrincipal,principal);
411          }
412          else
413          {
414             if(enableAudit)
415                failureAudit(principal);
416             if (trace)
417             {
418                log.trace("User: " + username + " is NOT authenticated");
419             }
420             principal = null;
421          }
422       }
423       catch (NamingException JavaDoc e)
424       {
425          principal = null;
426          log.error("Error during authenticate", e);
427          if(enableAudit)
428             errorAudit(principal,e);
429       }
430       if (trace)
431       {
432          log.trace("End authenticate, principal=" + principal);
433       }
434       return principal;
435    }
436    
437    /**
438     * Return the Principal associated with the specified username and
439     * credentials, if there is one; otherwise return <code>null</code>.
440     *
441     * @param username Username of the Principal to look up
442     * @param credentials Password or other credentials to use in authenticating
443     * this username
444     */

445    public Principal JavaDoc authenticate(String JavaDoc username, byte[] credentials)
446    {
447       return authenticate(username, new String JavaDoc(credentials));
448    }
449    
450    //*************************************************************************
451
// Realm.hasXXX Methods
452
//*************************************************************************
453
/**
454     * JBAS-2519:Delegate to JACC provider for unsecured resources in web.xml
455     */

456    public SecurityConstraint[] findSecurityConstraints(Request JavaDoc request,
457          org.apache.catalina.Context context)
458    {
459       SecurityConstraint[] scarr = super.findSecurityConstraints(request, context);
460       if( (scarr == null || scarr.length == 0)
461             && this.unprotectedResourceDelegation)
462       {
463          scarr = getSecurityConstraintsFromProvider(request, context);
464       }
465       return scarr;
466    }
467    
468    /**
469     * @see RealmBase#hasResourcePermission(Request, Response, SecurityConstraint[],
470     * org.apache.catalina.Context)
471     */

472    public boolean hasResourcePermission(Request JavaDoc request, Response JavaDoc response,
473          SecurityConstraint[] securityConstraints, org.apache.catalina.Context context)
474    throws IOException JavaDoc
475    {
476       Wrapper servlet = request.getWrapper();
477       if (servlet != null)
478       {
479          activeRequest.set(getServletName(servlet));
480       }
481       
482       boolean baseDecision = ignoreBaseDecision ? true :
483                    super.hasResourcePermission(request,response,
484                                       securityConstraints, context);
485       
486       Subject JavaDoc caller = this.establishSubjectContext(request.getPrincipal());
487
488       Map JavaDoc map = new HashMap JavaDoc();
489       map.put(ResourceKeys.WEB_REQUEST, request);
490       map.put(ResourceKeys.WEB_RESPONSE, response);
491       map.put(ResourceKeys.WEB_SECURITY_CONSTRAINTS, securityConstraints);
492       map.put(ResourceKeys.WEB_CONTEXT, context);
493       map.put(ResourceKeys.CALLER_SUBJECT, caller);
494       map.put(ResourceKeys.RESOURCE_PERM_CHECK, Boolean.TRUE);
495       int permit = authorize(map);
496       boolean authzDecision = (permit == AuthorizationContext.PERMIT);
497       boolean finalDecision = baseDecision && authzDecision;
498       if(trace)
499          log.trace("hasResourcePerm:RealmBase says:" + baseDecision +
500                "::Authz framework says:" + authzDecision + ":final=" + finalDecision);
501       if( finalDecision == false )
502       {
503          response.sendError(HttpServletResponse.SC_FORBIDDEN,
504                sm.getString("realmBase.forbidden"));
505       }
506       return finalDecision;
507    }
508    
509    /**
510     * Returns <code>true</code> if the specified user <code>Principal</code> has
511     * the specified security role, within the context of this
512     * <code>Realm</code>; otherwise return <code>false</code>. This will be true
513     * when an associated role <code>Principal</code> can be found whose
514     * <code>getName</code> method returns a <code>String</code> equalling the
515     * specified role.
516     *
517     * @param principal <code>Principal</code> for whom the role is to be
518     * checked
519     * @param role Security role to be checked
520     */

521    public boolean hasRole(Principal JavaDoc principal, String JavaDoc role)
522    {
523       String JavaDoc servletName = (String JavaDoc) activeRequest.get();
524       if(servletName == null)
525          throw new IllegalStateException JavaDoc("servletName is null");
526       WebMetaData metaData = (WebMetaData) SecurityAssociationValve.activeWebMetaData.get();
527       String JavaDoc roleName = role;
528       
529       /**
530        * If the metaData is null, this is an internal call made by RealmBase.hasResourcePermission
531        */

532       if(metaData != null)
533       {
534          List JavaDoc roleRefs = metaData.getSecurityRoleRefs(servletName);
535          int len = roleRefs != null ? roleRefs.size() : 0;
536          for(int n = 0; n < len; n ++)
537          {
538             SecurityRoleRefMetaData ref = (SecurityRoleRefMetaData) roleRefs.get(n);
539             if( ref.getLink().equals(role) )
540             {
541                roleName = ref.getName();
542                break;
543             }
544          }
545       }
546        
547       boolean baseDecision = ignoreBaseDecision ? true : super.hasRole(principal, role);
548       Map JavaDoc map = new HashMap JavaDoc();
549       map.put(ResourceKeys.ROLENAME, roleName);
550       map.put(ResourceKeys.HASROLE_PRINCIPAL, principal);
551       map.put(ResourceKeys.ROLEREF_PERM_CHECK, Boolean.TRUE);
552       map.put(ResourceKeys.SERVLET_NAME, servletName);
553       map.put(ResourceKeys.PRINCIPAL_ROLES, this.getPrincipalRoles(principal));
554       int permit = authorize(map);
555       boolean authzDecision = (permit == AuthorizationContext.PERMIT);
556       boolean finalDecision = baseDecision && authzDecision;
557       if(trace)
558          log.trace("hasRole:RealmBase says:" + baseDecision +
559                "::Authz framework says:" + authzDecision + ":final=" + finalDecision);
560        
561       return finalDecision;
562    }
563    
564    /**
565     * @see RealmBase#hasUserDataPermission(Request, Response, SecurityConstraint[])
566     */

567    public boolean hasUserDataPermission(Request JavaDoc request, Response JavaDoc response,
568          SecurityConstraint[] constraints) throws IOException JavaDoc
569    {
570       Principal JavaDoc requestPrincipal = request.getPrincipal();
571       establishSubjectContext(requestPrincipal);
572       Map JavaDoc map = new HashMap JavaDoc();
573       map.put(ResourceKeys.WEB_REQUEST, request);
574       map.put(ResourceKeys.WEB_RESPONSE, response);
575       map.put(ResourceKeys.WEB_SECURITY_CONSTRAINTS, constraints);
576       map.put(ResourceKeys.USERDATA_PERM_CHECK, Boolean.TRUE);
577       int permit = authorize(map);
578       boolean ok = (permit == AuthorizationContext.PERMIT);
579       
580       /* If the constraint is not valid delegate to super to redirect to the
581          ssl port if allowed
582        */

583       if( ok == false )
584          ok = super.hasUserDataPermission(request, response, constraints);
585       return ok;
586    }
587    
588    //*****************************************************************************
589
// PROTECTED METHODS
590
//*****************************************************************************
591
/**
592     * Create the session principal tomcat will cache to avoid callouts to this
593     * Realm.
594     *
595     * @param realmMapping - the role mapping security manager
596     * @param authPrincipal - the principal used for authentication and stored in
597     * the security manager cache
598     * @param callerPrincipal - the possibly different caller principal
599     * representation of the authenticated principal
600     * @param credential - the credential used for authentication
601     * @return the tomcat session principal wrapper
602     */

603    protected Principal JavaDoc getCachingPrincpal(RealmMapping realmMapping,
604       Principal JavaDoc authPrincipal, Principal JavaDoc callerPrincipal, Object JavaDoc credential,
605       Subject JavaDoc subject)
606    {
607       // Cache the user roles in the principal
608
Set JavaDoc userRoles = realmMapping.getUserRoles(authPrincipal);
609       ArrayList JavaDoc roles = new ArrayList JavaDoc();
610       if (userRoles != null)
611       {
612          Iterator JavaDoc iterator = userRoles.iterator();
613          while (iterator.hasNext())
614          {
615             Principal JavaDoc role = (Principal JavaDoc) iterator.next();
616             roles.add(role.getName());
617          }
618       }
619       JBossGenericPrincipal gp = new JBossGenericPrincipal(this, subject,
620          authPrincipal, callerPrincipal, credential, roles, userRoles);
621       return gp;
622    }
623    
624    /**
625     * Return a short name for this Realm implementation, for use in log
626     * messages.
627     */

628    protected String JavaDoc getName()
629    {
630       return getClass().getName();
631    }
632    
633    /**
634     * Return the password associated with the given principal's user name.
635     */

636    protected String JavaDoc getPassword(String JavaDoc username)
637    {
638       String JavaDoc password = null;
639       return password;
640    }
641  
642    /**
643     * Return the Principal associated with the given user name.
644     */

645    protected Principal JavaDoc getPrincipal(String JavaDoc username)
646    {
647       return new SimplePrincipal(username);
648    }
649    
650    
651    
652    /**
653     * Get the canonical request uri from the request mapping data requestPath
654     * @param request
655     * @return the request URI path
656     */

657    static String JavaDoc requestURI(Request JavaDoc request)
658    {
659       String JavaDoc uri = request.getMappingData().requestPath.getString();
660       if( uri == null || uri.equals("/") )
661       {
662          uri = "";
663       }
664       return uri;
665    }
666    
667  
668    /**
669     * Access the set of role Princpals associated with the given caller princpal.
670     *
671     * @param principal - the Principal mapped from the authentication principal
672     * and visible from the HttpServletRequest.getUserPrincipal
673     * @return a possible null Set<Principal> for the caller roles
674     */

675    protected Set JavaDoc getPrincipalRoles(Principal JavaDoc principal)
676    {
677       if( (principal instanceof GenericPrincipal) == false )
678          throw new IllegalStateException JavaDoc("Expected GenericPrincipal, but saw: "+principal.getClass());
679       GenericPrincipal gp = (GenericPrincipal) principal;
680       String JavaDoc[] roleNames = gp.getRoles();
681       Set JavaDoc userRoles = new HashSet JavaDoc();
682       if( roleNames != null )
683       {
684          for(int n = 0; n < roleNames.length; n ++)
685          {
686             SimplePrincipal sp = new SimplePrincipal(roleNames[n]);
687             userRoles.add(sp);
688          }
689       }
690       return userRoles;
691    }
692    
693    //*****************************************************************************
694
// PRIVATE METHODS
695
//*****************************************************************************
696
private int authorize(Map JavaDoc map)
697    {
698       AuthorizationManager authzMgr = this.getAuthorizationManager();
699       if(authzMgr == null)
700          throw new IllegalStateException JavaDoc("Authorization manager is null");
701
702       map.put(ResourceKeys.AUTHORIZATION_MANAGER, authzMgr);
703       Map JavaDoc readOnlyMap = Collections.unmodifiableMap(map);
704       WebResource webResource = new WebResource(readOnlyMap);
705       int permit = AuthorizationContext.DENY;
706       try
707       {
708          permit = authzMgr.authorize(webResource);
709          String JavaDoc level = (permit == AuthorizationContext.PERMIT ? AuditLevel.SUCCESS : AuditLevel.FAILURE);
710          authorizationAudit(level,webResource);
711       }
712       catch (AuthorizationException e)
713       {
714         if(trace)
715            log.trace("hasResourcePermission:",e);
716         permit = AuthorizationContext.DENY;
717         authorizationAudit(AuditLevel.ERROR,webResource);
718       }
719       return permit;
720    }
721    
722    /**
723     * Ensure that the JACC PolicyContext Subject handler has access to the
724     * authenticated Subject. The caching of the authentication state by tomcat
725     * means that we need to retrieve the Subject from the JBossGenericPrincipal
726     * if the realm was not invoked to authenticate the caller.
727     *
728     * @param principal - the http request getPrincipal
729     * @return the authenticated Subject is there is one, null otherwise
730     */

731    private Subject JavaDoc establishSubjectContext(Principal JavaDoc principal)
732    {
733       Subject JavaDoc caller = null;
734       try
735       {
736          caller = (Subject JavaDoc) PolicyContext.getContext(SUBJECT_CONTEXT_KEY);
737       }
738       catch (PolicyContextException JavaDoc e)
739       {
740          if( trace )
741             log.trace("Failed to get subject from PolicyContext", e);
742       }
743
744       if( caller == null )
745       {
746          // Test the request principal that may come from the session cache
747
if( principal instanceof JBossGenericPrincipal )
748          {
749             JBossGenericPrincipal jgp = (JBossGenericPrincipal) principal;
750             caller = jgp.getSubject();
751             //
752
if (trace)
753                log.trace("Restoring principal info from cache");
754             SecurityAssociationActions.setPrincipalInfo(jgp.getAuthPrincipal(),
755                jgp.getCredentials(), jgp.getSubject());
756          }
757       }
758       return caller;
759    }
760    
761    /**
762     * Get the Authorization Manager for the security domain
763     * @return
764     */

765    private AuthorizationManager getAuthorizationManager()
766    {
767       AuthorizationManager am = null;
768       try
769       {
770          am = (AuthorizationManager)getSecurityContext().lookup("authorizationMgr");
771       }
772       catch (Exception JavaDoc e)
773       {
774          if(trace)
775             log.trace("Lookup of authorization manager failed", e);
776       }
777       return am;
778    }
779    
780    private Context JavaDoc getSecurityContext()
781    {
782       Context JavaDoc securityCtx = null;
783       // Get the JBoss security manager from the ENC context
784
try
785       {
786          InitialContext JavaDoc iniCtx = new InitialContext JavaDoc();
787          securityCtx = (Context JavaDoc) iniCtx.lookup("java:comp/env/security");
788       }
789       catch (NamingException JavaDoc e)
790       {
791          // Apparently there is no security context?
792
}
793       return securityCtx;
794    }
795    
796    /**
797     * Get a set of SecurityConstraints from either the PolicyProvider
798     * or the securityConstraintProviderClass class, via reflection
799     *
800     * @param request
801     * @param context
802     * @return an array of SecurityConstraints
803     */

804    private SecurityConstraint[] getSecurityConstraintsFromProvider(Request JavaDoc request,
805          org.apache.catalina.Context context)
806    {
807       SecurityConstraint[] scarr = null;
808       Class JavaDoc[] sig = {Request JavaDoc.class, Context JavaDoc.class};
809       Object JavaDoc[] args = {request, context};
810       
811       Method JavaDoc findsc = null;
812       
813       //Try the Policy Provider
814
try
815       {
816          Policy JavaDoc policy = Policy.getPolicy();
817          findsc = policy.getClass().getMethod("findSecurityConstraints", sig);
818          scarr = (SecurityConstraint[])findsc.invoke(policy, args);
819       }catch(Throwable JavaDoc t)
820       {
821          if(trace)
822             log.error("Error obtaining security constraints from policy",t);
823 }
824       //If the policy provider did not provide the security constraints
825
//check if a seperate SC provider is plugged in
826
if(scarr == null || scarr.length == 0)
827       {
828          if(securityConstraintProviderClass == "" ||
829                securityConstraintProviderClass.length() == 0)
830          {
831             if(trace)
832                log.trace("unprotectedResourceDelegation is true "+
833                "but securityConstraintProviderClass is empty");
834          }
835          else
836             //Try to call the method on the provider class
837
try
838          {
839                Class JavaDoc clazz = Thread.currentThread().getContextClassLoader().loadClass(securityConstraintProviderClass);
840                Object JavaDoc obj = clazz.newInstance();
841                findsc = clazz.getMethod("findSecurityConstraints", sig);
842                if(trace)
843                   log.trace("findSecurityConstraints method found in securityConstraintProviderClass");
844                scarr = (SecurityConstraint[])findsc.invoke(obj, args);
845          }
846          catch (Throwable JavaDoc t)
847          {
848             log.error("Error instantiating "+securityConstraintProviderClass,t);
849          }
850       }
851       return scarr;
852    }
853    
854    /**
855     * Jacc Specification : Appendix
856     * B.19 Calling isUserInRole from JSP not mapped to a Servlet
857     * Checking a WebRoleRefPermission requires the name of a Servlet to
858     * identify the scope of the reference to role translation. The name of a
859     * scoping servlet has not been established for an unmapped JSP.
860     *
861     * Resolution- For every security role in the web application add a
862     * WebRoleRefPermission to the corresponding role. The name of all such
863     * permissions shall be the empty string, and the actions of each
864     * permission shall be the corresponding role name.
865     * When checking a WebRoleRefPermission from a JSP not mapped to a servlet,
866     * use a permission with the empty string as its name and with the argument to is
867     * UserInRole as its actions.
868     *
869     * @param servlet Wrapper
870     * @return empty string if it is for an unmapped jsp or name of the servlet for others
871     */

872    private String JavaDoc getServletName(Wrapper servlet)
873    {
874       //For jsp, the mapping will be (*.jsp, *.jspx)
875
String JavaDoc[] mappings = servlet.findMappings();
876       if(trace)
877          log.trace("[getServletName:servletmappings="+mappings +
878                ":servlet.getName()="+servlet.getName()+"]");
879       if("jsp".equals(servlet.getName())
880             && (mappings != null && mappings[0].indexOf("*.jsp")> -1))
881          return "";
882       else
883          return servlet.getName();
884    }
885    
886    private void audit(String JavaDoc level,
887          Map JavaDoc contextMap, Exception JavaDoc e)
888    {
889       String JavaDoc requestInfo = "";
890       try
891       {
892          HttpServletRequest JavaDoc hsr = (HttpServletRequest JavaDoc)PolicyContext.getContext(SecurityConstants.WEB_REQUEST_KEY);
893          requestInfo = WebUtil.deriveUsefulInfo(hsr);
894          contextMap.put("request", requestInfo);
895       }
896       catch (PolicyContextException JavaDoc pe)
897       {
898          if(trace)
899             log.trace("Error obtaining the servlet request:", pe);
900       }
901       contextMap.put("Source", getClass().getName());
902       SecurityContext sc = SecurityAssociationActions.getSecurityContext(securityDomain);
903       AuditContext ac = sc != null ? sc.getAuditContext():
904                    AuditManager.getAuditContext(securityDomain);
905       AuditEvent ae = new AuditEvent(level);
906       ae.setContextMap(contextMap);
907       ae.setUnderlyingException(e);
908       ac.audit(ae);
909    }
910    
911    private void successAudit(Principal JavaDoc callerPrincipal, Principal JavaDoc principal)
912    {
913       Map JavaDoc cmap = new HashMap JavaDoc();
914       cmap.put("principal", principal);
915       cmap.put("CallerPrincipal", callerPrincipal);
916       audit(AuditLevel.SUCCESS,cmap,null);
917    }
918    
919    private void failureAudit(Principal JavaDoc principal)
920    {
921       Map JavaDoc cmap = new HashMap JavaDoc();
922       cmap.put("principal", principal);
923       audit(AuditLevel.FAILURE,cmap,null);
924    }
925    
926    private void errorAudit(Principal JavaDoc principal, Exception JavaDoc e)
927    {
928       Map JavaDoc cmap = new HashMap JavaDoc();
929       cmap.put("principal", principal);
930       audit(AuditLevel.ERROR,cmap,e);
931    }
932    
933    private void authorizationAudit(String JavaDoc level, WebResource resource)
934    {
935       if(!enableAudit)
936          return;
937       Map JavaDoc cmap = new HashMap JavaDoc();
938       cmap.putAll(resource.getMap());
939       audit(level,cmap,null);
940    }
941    
942    //Security Context
943
private void establishSecurityContext(String JavaDoc domain, Principal JavaDoc p, Object JavaDoc cred,
944          Subject JavaDoc subject)
945    {
946       JBossSecurityContext jsc = new JBossSecurityContext(domain);
947       SubjectInfo si = jsc.new SubjectInfo();
948       si.setAuthenticatedSubject(subject);
949       si.setAuthenticationCredential(cred);
950       si.setAuthenticationPrincipal(p);
951       jsc.setSubjectInfo(si);
952       SecurityAssociationActions.setSecurityContext(jsc, domain);
953       if(trace)
954          log.trace("Established Security Context for " + domain);
955    }
956 }
957
Popular Tags