KickJava   Java API By Example, From Geeks To Geeks.

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


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.Principal JavaDoc;
27 import java.security.Permission JavaDoc;
28 import java.security.ProtectionDomain JavaDoc;
29 import java.security.Policy JavaDoc;
30 import java.security.CodeSource JavaDoc;
31 import java.util.Set JavaDoc;
32 import java.util.List JavaDoc;
33
34 import javax.security.jacc.WebUserDataPermission JavaDoc;
35 import javax.security.jacc.PolicyContext JavaDoc;
36 import javax.security.jacc.WebResourcePermission JavaDoc;
37 import javax.security.jacc.WebRoleRefPermission JavaDoc;
38 import javax.security.jacc.PolicyContextException JavaDoc;
39 import javax.security.auth.Subject JavaDoc;
40 import javax.servlet.http.HttpServletRequest JavaDoc;
41 import javax.servlet.http.HttpServletResponse JavaDoc;
42
43 import org.apache.catalina.Context;
44 import org.apache.catalina.Wrapper;
45 import org.apache.catalina.connector.Request;
46 import org.apache.catalina.connector.Response;
47 import org.apache.catalina.deploy.SecurityConstraint;
48 import org.jboss.logging.Logger;
49 import org.jboss.metadata.WebMetaData;
50 import org.jboss.metadata.SecurityRoleRefMetaData;
51
52 /** A subclass of JBossSecurityMgrRealm that peforms authorization based on
53  * the JACC permissions and active Policy implementation.
54  *
55  * @author Scott.Stark@jboss.org
56  * @author Anil.Saldhana@jboss.org
57  * @version $Revision: 45586 $
58  */

59 public class JaccAuthorizationRealm extends JBossSecurityMgrRealm
60 {
61    static Logger log = Logger.getLogger(JaccAuthorizationRealm.class);
62
63    /** The JACC PolicyContext key for the current Subject */
64    private static final String JavaDoc SUBJECT_CONTEXT_KEY = "javax.security.auth.Subject.container";
65    /** The current servlet request */
66    private static ThreadLocal JavaDoc activeRequest = new ThreadLocal JavaDoc();
67    private boolean trace;
68    private Policy JavaDoc policy;
69
70    /**
71     * JBAS-2519:Delegate to JACC provider for unsecured resources in web.xml
72     */

73    private boolean unprotectedResourceDelegation = false;
74    private String JavaDoc securityConstraintProviderClass = "";
75
76    public JaccAuthorizationRealm()
77    {
78       policy = Policy.getPolicy();
79       trace = log.isTraceEnabled();
80    }
81
82    public boolean hasResourcePermission(Request JavaDoc request, Response JavaDoc response,
83       SecurityConstraint[] securityConstraints, Context JavaDoc context)
84       throws IOException JavaDoc
85    {
86       Wrapper servlet = request.getWrapper();
87       if (servlet != null)
88       {
89          activeRequest.set(getServletName(servlet));
90       }
91       Principal JavaDoc requestPrincipal = request.getPrincipal();
92       HttpServletRequest JavaDoc httpRequest = request.getRequest();
93       String JavaDoc uri = requestURI(request);
94       WebResourcePermission JavaDoc perm = new WebResourcePermission JavaDoc(uri, httpRequest.getMethod());
95       boolean allowed = checkSecurityAssociation(perm, requestPrincipal);
96       if( trace )
97          log.trace("hasResourcePermission, perm="+perm+", allowed="+allowed);
98       if( allowed == false )
99       {
100          response.sendError(HttpServletResponse.SC_FORBIDDEN,
101             sm.getString("realmBase.forbidden"));
102       }
103       return allowed;
104    }
105
106    public boolean hasRole(Principal JavaDoc principal, String JavaDoc name)
107    {
108       //
109
String JavaDoc servletName = (String JavaDoc) activeRequest.get();
110       WebMetaData metaData = (WebMetaData) SecurityAssociationValve.activeWebMetaData.get();
111       List JavaDoc roleRefs = metaData.getSecurityRoleRefs(servletName);
112       String JavaDoc roleName = name;
113       int len = roleRefs != null ? roleRefs.size() : 0;
114       for(int n = 0; n < len; n ++)
115       {
116          SecurityRoleRefMetaData ref = (SecurityRoleRefMetaData) roleRefs.get(n);
117          if( ref.getLink().equals(name) )
118          {
119             roleName = ref.getName();
120             break;
121          }
122       }
123       
124       WebRoleRefPermission JavaDoc perm = new WebRoleRefPermission JavaDoc(servletName, roleName);
125       Principal JavaDoc[] principals = {principal};
126       Set JavaDoc roles = getPrincipalRoles(principal);
127       if( roles != null )
128       {
129          principals = new Principal JavaDoc[roles.size()];
130          roles.toArray(principals);
131       }
132       boolean allowed = checkSecurityAssociation(perm, principals);
133       if( trace )
134          log.trace("hasRole, perm="+perm+", allowed="+allowed);
135       return allowed;
136    }
137
138    public boolean hasUserDataPermission(Request JavaDoc request, Response JavaDoc response,
139       SecurityConstraint[] constraints) throws IOException JavaDoc
140    {
141       HttpServletRequest JavaDoc httpRequest = request.getRequest();
142       Principal JavaDoc requestPrincpal = request.getPrincipal();
143       establishSubjectContext(requestPrincpal);
144       String JavaDoc uri = requestURI(request);
145       WebUserDataPermission JavaDoc perm = new WebUserDataPermission JavaDoc(uri, httpRequest.getMethod());
146       if( trace )
147          log.trace("hasUserDataPermission, p="+perm);
148       boolean ok = false;
149       try
150       {
151          Principal JavaDoc[] principals = null;
152          ok = checkSecurityAssociation(perm, principals);
153       }
154       catch(Exception JavaDoc e)
155       {
156          if( trace )
157             log.trace("Failed to checkSecurityAssociation", e);
158       }
159
160       /* If the constraint is not valid delegate to super to redirect to the
161       ssl port if allowed
162       */

163       if( ok == false )
164          ok = super.hasUserDataPermission(request, response, constraints);
165       return ok;
166    }
167
168    /**
169     * Get the Security Constraints Provider Class
170     * @return
171     */

172    public String JavaDoc getSecurityConstraintProviderClass()
173    {
174       return securityConstraintProviderClass;
175    }
176
177    /**
178     * Set the Security Constraints Provider Class
179     * @param securityConstraintProviderClass
180     */

181    public void setSecurityConstraintProviderClass(String JavaDoc securityConstraintProviderClass)
182    {
183       this.securityConstraintProviderClass = securityConstraintProviderClass;
184    }
185
186    /**
187     * Whether the delegation to JACC provider
188     * for unprotected resources is enabled
189     *
190     * @return
191     */

192    public boolean isUnprotectedResourceDelegation()
193    {
194       return unprotectedResourceDelegation;
195    }
196
197    /**
198     * Set whether the delegation to JACC provider
199     * for unprotected resources must be enabled
200     *
201     * @param unprotectedResourceDelegation
202     */

203    public void setUnprotectedResourceDelegation(boolean unprotectedResourceDelegation)
204    {
205       this.unprotectedResourceDelegation = unprotectedResourceDelegation;
206    }
207    
208    /**
209     * JBAS-2519:Delegate to JACC provider for unsecured resources in web.xml
210     */

211    public SecurityConstraint[] findSecurityConstraints(Request JavaDoc request, Context JavaDoc context)
212    {
213       SecurityConstraint[] scarr = super.findSecurityConstraints(request, context);
214       if( (scarr == null || scarr.length == 0)
215             && this.unprotectedResourceDelegation)
216       {
217          scarr = getSecurityConstraintsFromProvider(request, context);
218       }
219       return scarr;
220    }
221
222    /** See if the given JACC permission is implied using the caller as
223     * obtained from either the
224     * PolicyContext.getContext(javax.security.auth.Subject.container) or
225     * the info associated with the requestPrincipal.
226     *
227     * @param perm - the JACC permission to check
228     * @param requestPrincpal - the http request getPrincipal
229     * @return true if the permission is allowed, false otherwise
230     */

231    private boolean checkSecurityAssociation(Permission JavaDoc perm, Principal JavaDoc requestPrincpal)
232    {
233       // Get the caller
234
Subject JavaDoc caller = establishSubjectContext(requestPrincpal);
235
236       // Get the caller principals, its null if there is no caller
237
Principal JavaDoc[] principals = null;
238       if( caller != null )
239       {
240          if( trace )
241             log.trace("No active subject found, using ");
242          Set JavaDoc principalsSet = caller.getPrincipals();
243          principals = new Principal JavaDoc[principalsSet.size()];
244          principalsSet.toArray(principals);
245       }
246       return checkSecurityAssociation(perm, principals);
247    }
248    /** See if the given permission is implied by the Policy. This calls
249     * Policy.implies(pd, perm) with the ProtectionDomain built from the
250     * active CodeSource set by the JaccContextValve, and the given
251     * principals.
252     *
253     * @param perm - the JACC permission to evaluate
254     * @param principals - the possibly null set of principals for the caller
255     * @return true if the permission is allowed, false otherwise
256     */

257    private boolean checkSecurityAssociation(Permission JavaDoc perm, Principal JavaDoc[] principals)
258    {
259       CodeSource JavaDoc webCS = (CodeSource JavaDoc) JaccContextValve.activeCS.get();
260       ProtectionDomain JavaDoc pd = new ProtectionDomain JavaDoc(webCS, null, null, principals);
261       boolean allowed = policy.implies(pd, perm);
262       if( trace )
263       {
264          String JavaDoc msg = (allowed ? "Allowed: " : "Denied: ") +perm;
265          log.trace(msg);
266       }
267       return allowed;
268    }
269
270    /**
271     * Ensure that the JACC PolicyContext Subject handler has access to the
272     * authenticated Subject. The caching of the authentication state by tomcat
273     * means that we need to retrieve the Subject from the JBossGenericPrincipal
274     * if the realm was not invoked to authenticate the caller.
275     *
276     * @param principal - the http request getPrincipal
277     * @return the authenticated Subject is there is one, null otherwise
278     */

279    private Subject JavaDoc establishSubjectContext(Principal JavaDoc principal)
280    {
281       Subject JavaDoc caller = null;
282       try
283       {
284          caller = (Subject JavaDoc) PolicyContext.getContext(SUBJECT_CONTEXT_KEY);
285       }
286       catch (PolicyContextException JavaDoc e)
287       {
288          if( trace )
289             log.trace("Failed to get subject from PolicyContext", e);
290       }
291
292       if( caller == null )
293       {
294          // Test the request principal that may come from the session cache
295
if( principal instanceof JBossGenericPrincipal )
296          {
297             JBossGenericPrincipal jgp = (JBossGenericPrincipal) principal;
298             caller = jgp.getSubject();
299             //
300
if (trace)
301                log.trace("Restoring principal info from cache");
302             SecurityAssociationActions.setPrincipalInfo(jgp.getAuthPrincipal(),
303                jgp.getCredentials(), jgp.getSubject());
304          }
305       }
306       return caller;
307    }
308    
309    /**
310     * Jacc Specification : Appendix
311     * B.19 Calling isUserInRole from JSP not mapped to a Servlet
312     * Checking a WebRoleRefPermission requires the name of a Servlet to
313     * identify the scope of the reference to role translation. The name of a
314     * scoping servlet has not been established for an unmapped JSP.
315     *
316     * Resolution- For every security role in the web application add a
317     * WebRoleRefPermission to the corresponding role. The name of all such
318     * permissions shall be the empty string, and the actions of each
319     * permission shall be the corresponding role name.
320     * When checking a WebRoleRefPermission from a JSP not mapped to a servlet,
321     * use a permission with the empty string as its name and with the argument to is
322     * UserInRole as its actions.
323     *
324     * @param servlet Wrapper
325     * @return empty string if it is for an unmapped jsp or name of the servlet for others
326     */

327    private String JavaDoc getServletName(Wrapper servlet)
328    {
329       //For jsp, the mapping will be (*.jsp, *.jspx)
330
String JavaDoc[] mappings = servlet.findMappings();
331       if(trace)
332          log.trace("[getServletName:servletmappings="+mappings +
333                ":servlet.getName()="+servlet.getName()+"]");
334       if("jsp".equals(servlet.getName())
335             && (mappings != null && mappings[0].indexOf("*.jsp")> -1))
336       return "";
337       else
338          return servlet.getName();
339    }
340    
341    /**
342     * Get a set of SecurityConstraints from either the PolicyProvider
343     * or the securityConstraintProviderClass class, via reflection
344     *
345     * @param request
346     * @param context
347     * @return an array of SecurityConstraints
348     */

349    private SecurityConstraint[] getSecurityConstraintsFromProvider(Request JavaDoc request, Context JavaDoc context)
350    {
351       SecurityConstraint[] scarr = null;
352       Class JavaDoc[] sig = {Request JavaDoc.class, Context JavaDoc.class};
353       Object JavaDoc[] args = {request, context};
354       
355       Method JavaDoc findsc = null;
356       
357       //Try the Policy Provider
358
try
359       {
360          findsc = policy.getClass().getMethod("findSecurityConstraints", sig);
361          scarr = (SecurityConstraint[])findsc.invoke(policy, args);
362       }catch(Throwable JavaDoc t)
363       {
364          if(trace)
365             log.error("Error obtaining security constraints from policy",t);
366 }
367       //If the policy provider did not provide the security constraints
368
//check if a seperate SC provider is plugged in
369
if(scarr == null || scarr.length == 0)
370       {
371          if(securityConstraintProviderClass == "" ||
372                securityConstraintProviderClass.length() == 0)
373          {
374             if(trace)
375                log.trace("unprotectedResourceDelegation is true "+
376                "but securityConstraintProviderClass is empty");
377          }
378          else
379             //Try to call the method on the provider class
380
try
381          {
382                Class JavaDoc clazz = Thread.currentThread().getContextClassLoader().loadClass(securityConstraintProviderClass);
383                Object JavaDoc obj = clazz.newInstance();
384                findsc = clazz.getMethod("findSecurityConstraints", sig);
385                if(trace)
386                   log.trace("findSecurityConstraints method found in securityConstraintProviderClass");
387                scarr = (SecurityConstraint[])findsc.invoke(obj, args);
388          }
389          catch (Throwable JavaDoc t)
390          {
391             log.error("Error instantiating "+securityConstraintProviderClass,t);
392          }
393       }
394       return scarr;
395    }
396
397    /**
398     * Get the canonical request uri from the request mapping data requestPath
399     * @param request
400     * @return the request URI path
401     */

402    static String JavaDoc requestURI(Request JavaDoc request)
403    {
404       String JavaDoc uri = request.getMappingData().requestPath.getString();
405       if( uri == null || uri.equals("/") )
406       {
407          uri = "";
408       }
409       return uri;
410    }
411    
412 }
413
Popular Tags