KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > security > application > EJBSecurityManager


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23 package com.sun.enterprise.security.application;
24
25 import java.io.File JavaDoc;
26 import java.lang.reflect.InvocationTargetException JavaDoc;
27 import java.net.URLEncoder JavaDoc;
28 import java.util.ArrayList JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.Set JavaDoc;
31 import java.util.HashSet JavaDoc;
32 import java.util.Hashtable JavaDoc;
33 import java.util.Map JavaDoc;
34 import java.util.HashMap JavaDoc;
35 import java.util.WeakHashMap JavaDoc;
36 import java.lang.reflect.Method JavaDoc;
37 import java.util.Collections JavaDoc;
38 import java.security.Permission JavaDoc;
39 import java.security.Principal JavaDoc;
40 import java.security.AccessController JavaDoc;
41 import java.security.AccessControlContext JavaDoc;
42 import java.security.CodeSource JavaDoc;
43 import javax.security.auth.Subject JavaDoc;
44 import javax.security.auth.SubjectDomainCombiner JavaDoc;
45 import java.security.ProtectionDomain JavaDoc;
46 import java.security.Permissions JavaDoc;
47 import java.security.PrivilegedAction JavaDoc;
48 import java.security.PrivilegedExceptionAction JavaDoc;
49 import java.net.URL JavaDoc;
50 import java.security.Policy JavaDoc;
51 import javax.security.jacc.EJBMethodPermission JavaDoc;
52 import javax.security.jacc.EJBRoleRefPermission JavaDoc;
53 import javax.security.jacc.PolicyConfigurationFactory JavaDoc;
54 import javax.security.jacc.PolicyConfiguration JavaDoc;
55 import javax.security.jacc.PolicyContext JavaDoc;
56 import javax.security.jacc.PolicyContextException JavaDoc;
57 import com.sun.ejb.Invocation;
58 import com.sun.enterprise.ComponentInvocation;
59 import com.sun.enterprise.InvocationManager;
60 import com.sun.enterprise.InvocationException;
61 import com.sun.enterprise.Switch;
62 import com.sun.enterprise.SecurityManager;
63 import com.sun.enterprise.deployment.*;
64 import com.sun.enterprise.deployment.interfaces.SecurityRoleMapperFactory;
65 import com.sun.enterprise.deployment.interfaces.SecurityRoleMapperFactoryMgr;
66 import com.sun.enterprise.deployment.web.SecurityRoleReference;
67 import com.sun.enterprise.security.SecurityContext;
68 import com.sun.enterprise.security.factory.SecurityManagerFactory;
69 import com.sun.enterprise.security.factory.FactoryForSecurityManagerFactory;
70 import com.sun.enterprise.security.factory.FactoryForSecurityManagerFactoryImpl;
71 import com.sun.enterprise.security.auth.LoginContextDriver;
72 import com.sun.enterprise.security.authorize.PolicyContextHandlerImpl;
73 import com.sun.enterprise.security.LoginException;
74 import com.sun.enterprise.security.authorize.*;
75 import com.sun.enterprise.security.audit.AuditManager;
76 import com.sun.enterprise.security.audit.AuditManagerFactory;
77 import com.sun.enterprise.security.CachedPermission;
78 import com.sun.enterprise.security.CachedPermissionImpl;
79 import com.sun.enterprise.security.PermissionCache;
80 import com.sun.enterprise.security.PermissionCacheFactory;
81 import com.sun.enterprise.util.LocalStringManagerImpl;
82 import com.sun.enterprise.util.TypeUtil;
83
84 // logging
85
import java.util.logging.*;
86 import com.sun.logging.LogDomains;
87
88 import java.security.ProtectionDomain JavaDoc;
89
90 /**
91  * This class is used by the EJB server to manage security. All
92  * the container object only call into this object for managing
93  * security. This class cannot be subclassed.
94  *
95  * An instance of this class should be created per deployment unit.
96  * @author Harpreet Singh
97  */

98 public final class EJBSecurityManager implements SecurityManager JavaDoc {
99
100     private static Logger _logger=null;
101     static {
102         _logger=LogDomains.getLogger(LogDomains.SECURITY_LOGGER);
103     }
104     private static LocalStringManagerImpl localStrings =
105     new LocalStringManagerImpl(EJBSecurityManager.class);
106     
107     private static AuditManager auditManager =
108             AuditManagerFactory.getAuditManagerInstance();
109
110     private static final PolicyContextHandlerImpl pcHandlerImpl =
111             (PolicyContextHandlerImpl)PolicyContextHandlerImpl.getInstance();
112
113     private static SecurityRoleMapperFactory roleMapperFactory =
114     SecurityRoleMapperFactoryMgr.getFactory();
115
116     private EjbDescriptor deploymentDescriptor = null;
117     private Switch theSwitch;
118     // Objects required for Run-AS
119
private RunAsIdentityDescriptor runAs = null;
120     
121     // jacc related
122
private static PolicyConfigurationFactory JavaDoc pcf = null;
123     private String JavaDoc ejbName = null;
124     // contextId id is the same as an appname. This will be used to get
125
// a PolicyConfiguration object per application.
126
private String JavaDoc contextId = null;
127     private String JavaDoc codebase = null;
128     private CodeSource JavaDoc codesource = null;
129     private String JavaDoc realmName = null;
130     // this stores the role ref permissions. So will not need to spend runtime
131
// resources generating permissions.
132
private Hashtable JavaDoc cacheRoleToPerm = new Hashtable JavaDoc();
133
134     // we use two protection domain caches until we decide how to
135
// set the codesource in the protection domain of system apps.
136
// PD's in protectionDomainCache have the (privileged) codesource
137
// of the EJBSecurityManager class. The PD used in pre-dispatch
138
// authorization decisions MUST not be constructed using a privileged
139
// codesource (or else all pre-distpatch access decisions will be granted).
140
private Map JavaDoc cacheProtectionDomain =
141     Collections.synchronizedMap(new WeakHashMap JavaDoc());
142     private Map JavaDoc protectionDomainCache =
143     Collections.synchronizedMap(new WeakHashMap JavaDoc());
144
145     private Map JavaDoc accessControlContextCache =
146     Collections.synchronizedMap(new WeakHashMap JavaDoc());
147
148     private PermissionCache uncheckedMethodPermissionCache = null;
149
150     private Policy JavaDoc policy = null;
151      
152     private static CodeSource JavaDoc managerCodeSource =
153     EJBSecurityManager.class.getProtectionDomain().getCodeSource();
154
155     private boolean isMdb;
156
157     /** Return an instance of EJBSecurityManager. This class is no longer
158      * instantiable directly.
159      * @return EJBSecurityManager EJBSM instance with the given descriptor
160      * information
161      */

162     public static EJBSecurityManager getInstance(Descriptor des)
163     throws Exception JavaDoc{
164     return new EJBSecurityManager(des);
165     }
166     /**
167      * This method creates a new security manager object......Dont instantiate
168      * directly.
169      */

170     private EJBSecurityManager(Descriptor ejbDescriptor)
171     throws Exception JavaDoc
172     {
173     if(ejbDescriptor == null || !(ejbDescriptor instanceof EjbDescriptor)) {
174         throw new IllegalArgumentException JavaDoc("Illegal Deployment Descriptor Information.");
175     }
176     this.deploymentDescriptor = (EjbDescriptor) ejbDescriptor;
177
178     this.isMdb = (EjbMessageBeanDescriptor.TYPE.equals(
179         this.deploymentDescriptor.getType()));
180
181     // get the default policy
182
policy = Policy.getPolicy();
183
184     boolean runas = !(deploymentDescriptor.getUsesCallerIdentity());
185     if (runas){
186         runAs = deploymentDescriptor.getRunAsIdentity();
187
188             // Note: runAs may be null even when runas==true if this EJB
189
// is an MDB.
190
if(runAs != null) {
191         if (_logger.isLoggable(Level.FINE)){
192             _logger.log(Level.FINE,deploymentDescriptor.getEjbClassName() +
193                  " will run-as: " + runAs.getPrincipal() +
194                  " (" + runAs.getRoleName() + ")");
195         }
196         }
197     }
198     
199     theSwitch = Switch.getSwitch();
200     initialize();
201     }
202     private static CodeSource JavaDoc getApplicationCodeSource(String JavaDoc pcid) throws Exception JavaDoc {
203     CodeSource JavaDoc result = null;
204     String JavaDoc archiveURI = "file:///" + pcid.replace(' ', '_');
205     try{
206         java.net.URI JavaDoc uri = null;
207         try{
208         uri = new java.net.URI JavaDoc(archiveURI);
209         if(uri != null){
210             result = new CodeSource JavaDoc(uri.toURL(),
211                             (java.security.cert.Certificate JavaDoc[]) null);
212         }
213         } catch(java.net.URISyntaxException JavaDoc use){
214         // manually create the URL
215
_logger.log(Level.SEVERE,"JACC: Error Creating URI ", use);
216         throw new RuntimeException JavaDoc(use);
217         }
218
219     } catch(java.net.MalformedURLException JavaDoc mue){
220         // should never come here.
221
_logger.log(Level.SEVERE,"JACC: ejbsm.codesourceerror", mue);
222         throw new RuntimeException JavaDoc(mue);
223     }
224     return result;
225     }
226
227     // obtains PolicyConfigurationFactory once for class
228
private static PolicyConfigurationFactory JavaDoc getPolicyFactory()
229     throws PolicyContextException JavaDoc {
230     synchronized (EJBSecurityManager.class) {
231         if (pcf == null) {
232         try {
233             pcf = PolicyConfigurationFactory.getPolicyConfigurationFactory();
234         } catch(ClassNotFoundException JavaDoc cnfe){
235             _logger.severe("jaccfactory.notfound");
236             throw new PolicyContextException JavaDoc(cnfe);
237         } catch(PolicyContextException JavaDoc pce){
238             _logger.severe("jaccfactory.notfound");
239             throw pce;
240         }
241         }
242     }
243     return pcf;
244     }
245
246     public boolean getUsesCallerIdentity() {
247         return (runAs == null);
248     }
249
250     public static void loadPolicyConfiguration(EjbDescriptor eDescriptor) throws Exception JavaDoc
251     {
252     String JavaDoc pcid = getContextID(eDescriptor);
253         String JavaDoc appName = eDescriptor.getApplication().getRegistrationName();
254         roleMapperFactory.setAppNameForContext(appName, pcid);
255     boolean inService = getPolicyFactory().inService(pcid);
256
257     // only load the policy configuration if it isn't already in service.
258
// Consequently, all things that deploy modules (as apposed to
259
// loading already deployed modules) must make sure pre-exiting
260
// pc is either in deleted or open state before this method
261
// is called. Note that policy statements are not
262
// removed to allow multiple EJB's to be represented by same pc.
263

264     if (!inService) {
265
266         // translate the deployment descriptor to configure the policy rules.
267

268         convertEJBMethodPermissions(eDescriptor,pcid);
269         convertEJBRoleReferences(eDescriptor,pcid);
270
271         if(_logger.isLoggable(Level.FINE)){
272         _logger.fine("JACC: policy translated for policy context:" +pcid);
273         }
274     }
275     }
276
277     public static String JavaDoc getContextID(EjbDescriptor ejbDesc) {
278         return getContextID(ejbDesc.getEjbBundleDescriptor());
279     }
280
281     public static String JavaDoc getContextID(EjbBundleDescriptor ejbBundleDesc) {
282         String JavaDoc cid = null;
283         if (ejbBundleDesc != null ) {
284             cid = ejbBundleDesc.getApplication().getRegistrationName() +
285                 '/' + ejbBundleDesc.getUniqueFriendlyId();
286         }
287         return cid;
288     }
289
290
291     private void initialize() throws Exception JavaDoc {
292     contextId = getContextID(deploymentDescriptor);
293         String JavaDoc appName = deploymentDescriptor.getApplication().getRegistrationName();
294         roleMapperFactory.setAppNameForContext(appName, contextId);
295     codesource = getApplicationCodeSource(contextId);
296     ejbName = deploymentDescriptor.getName();
297
298     realmName= deploymentDescriptor.getApplication().getRealm();
299
300         if (realmName == null) {
301             Set JavaDoc iorConfigs = deploymentDescriptor.getIORConfigurationDescriptors();
302             // iorConfigs is not null from implementation of EjbDescriptor
303
Iterator JavaDoc iter = iorConfigs.iterator();
304             if (iter != null) {
305                 // there should be at most one element in the loop from
306
// definition of dtd
307
while (iter.hasNext()) {
308                     EjbIORConfigurationDescriptor iorConfig =
309                            (EjbIORConfigurationDescriptor)iter.next();
310                     realmName = iorConfig.getRealmName();
311                 }
312             }
313         }
314
315     if(_logger.isLoggable(Level.FINE)){
316         _logger.fine("JACC: Context id (id under which all EJB's in application will be created) = " + contextId);
317         _logger.fine("Codebase (module id for ejb "+ejbName+") = "+ codebase);
318     }
319
320     // translate the deployment descriptor to populate the role-ref permission cache
321
addEJBRoleReferenceToCache(deploymentDescriptor);
322
323     // create and initialize the unchecked permission cache.
324
uncheckedMethodPermissionCache =
325                 PermissionCacheFactory.createPermissionCache(
326                             this.contextId, this.codesource,
327                 EJBMethodPermission JavaDoc.class,
328                 this.ejbName);
329     }
330
331     /** This method converts ejb role references to jacc permission objects
332      * and adds them to the policy configuration object
333      * It gets the list of role references from the ejb descriptor. For each
334      * such role reference, create a EJBRoleRefPermission and add it to the
335      * PolicyConfiguration object.
336      * @param EjbDescriptor, the ejb descriptor
337      * @param pcid, the policy context identifier
338      */

339     private static void
340     convertEJBRoleReferences(EjbDescriptor eDescriptor, String JavaDoc pcid)
341     throws PolicyContextException JavaDoc {
342
343     PolicyConfiguration JavaDoc pc =
344         getPolicyFactory().getPolicyConfiguration(pcid, false);
345
346     assert pc != null;
347                      
348     if (pc != null) {
349
350         String JavaDoc eName = eDescriptor.getName();
351
352         Iterator JavaDoc iroleref = eDescriptor.getRoleReferences().iterator();
353         while(iroleref.hasNext()){
354         SecurityRoleReference roleRef =
355             (SecurityRoleReference) iroleref.next();
356         String JavaDoc rolename = roleRef.getRolename();
357         EJBRoleRefPermission JavaDoc ejbrr =
358             new EJBRoleRefPermission JavaDoc(eName, rolename);
359         String JavaDoc rolelink = roleRef.getSecurityRoleLink().getName();
360
361         pc.addToRole(rolelink, ejbrr);
362
363         if(_logger.isLoggable(Level.FINE)){
364             _logger.fine("JACC: Converting role-ref -> "+roleRef.toString()+
365                  " to permission with name("+ejbrr.getName()+
366                  ") and actions ("+ejbrr.getActions()+
367                  ")" + "mapped to role ("+rolelink+")");
368         }
369         }
370     }
371     }
372
373     /** This method converts ejb role references to jacc permission objects
374      * and adds them to the corresponding permission cache.
375      * @param EjbDescriptor, the ejb descriptor
376      */

377     private void addEJBRoleReferenceToCache(EjbDescriptor eDescriptor) {
378
379     String JavaDoc eName = eDescriptor.getName();
380
381     Iterator JavaDoc iroleref = eDescriptor.getRoleReferences().iterator();
382     while(iroleref.hasNext()){
383         SecurityRoleReference roleRef =
384         (SecurityRoleReference) iroleref.next();
385         String JavaDoc rolename = roleRef.getRolename();
386         EJBRoleRefPermission JavaDoc ejbrr =
387         new EJBRoleRefPermission JavaDoc(eName, rolename);
388         String JavaDoc rolelink = roleRef.getSecurityRoleLink().getName();
389
390         cacheRoleToPerm.put(eName+"_"+rolename, ejbrr);
391
392         if(_logger.isLoggable(Level.FINE)){
393         _logger.fine("JACC: Converting role-ref -> "+roleRef.toString()+
394                  " to permission with name("+ejbrr.getName()+
395                  ") and actions ("+ejbrr.getActions()+
396                  ")" + "mapped to role ("+rolelink+")");
397         }
398     }
399     }
400
401     // utility to collect role permisisions in table of collections
402
private static HashMap JavaDoc addToRolePermissionsTable(HashMap JavaDoc table,
403                              MethodPermission JavaDoc mp,
404                              EJBMethodPermission JavaDoc ejbmp) {
405     if (mp.isRoleBased()){
406         if (table == null) {
407         table = new HashMap JavaDoc();
408         }
409         String JavaDoc roleName = mp.getRole().getName();
410         Permissions JavaDoc rolePermissions =
411         (Permissions JavaDoc) table.get(roleName);
412         if (rolePermissions == null) {
413         rolePermissions = new Permissions JavaDoc();
414         table.put(roleName,rolePermissions);
415         }
416         rolePermissions.add(ejbmp);
417         if(_logger.isLoggable(Level.FINE)){
418         _logger.fine("JACC DD conversion: EJBMethodPermission ->("+
419                  ejbmp.getName()+" "+ejbmp.getActions()+
420                  ")protected by role -> "+roleName);
421         }
422     }
423     return table;
424     }
425
426     // utility to collect unchecked permissions in collection
427
private static Permissions JavaDoc addToUncheckedPermissions(Permissions JavaDoc permissions,
428                              MethodPermission JavaDoc mp,
429                              EJBMethodPermission JavaDoc ejbmp) {
430     if(mp.isUnchecked()){
431         if (permissions == null) {
432         permissions = new Permissions JavaDoc();
433         }
434         permissions.add(ejbmp);
435         if(_logger.isLoggable(Level.FINE)){
436         _logger.fine("JACC DD conversion: EJBMethodPermission ->("
437                  +ejbmp.getName()+" "+ejbmp.getActions()+
438                  ") is (unchecked)");
439         }
440     }
441     return permissions;
442     }
443
444     // utility to collect excluded permissions in collection
445
private static Permissions JavaDoc addToExcludedPermissions(Permissions JavaDoc permissions,
446                             MethodPermission JavaDoc mp,
447                             EJBMethodPermission JavaDoc ejbmp) {
448     if(mp.isExcluded()){
449         if (permissions == null) {
450         permissions = new Permissions JavaDoc();
451         }
452         permissions.add(ejbmp);
453         if(_logger.isLoggable(Level.FINE)){
454         _logger.fine("JACC DD conversion: EJBMethodPermission ->("
455                  +ejbmp.getName()+" "+ejbmp.getActions()+
456                  ") is (excluded)");
457         }
458     }
459     return permissions;
460     }
461
462     /**
463      * This method converts the dd in two phases.
464      * Phase 1:
465      * gets a map representing the methodPermission elements exactly as they
466      * occured for the ejb in the dd. The map is keyed by method-permission
467      * element and each method-permission is mapped to a list of method
468      * elements representing the method elements of the method permision
469      * element. Each method element is converted to a corresponding
470      * EJBMethodPermission and added, based on its associated method-permission,
471      * to the policy configuration object.
472      * phase 2:
473      * configures additional EJBMethodPermission policy statements
474      * for the purpose of optimizing Permissions.implies matching by the
475      * policy provider. This phase also configures unchecked policy
476      * statements for any uncovered methods. This method gets the list
477      * of method descriptors for the ejb from the EjbDescriptor object.
478      * For each method descriptor, it will get a list of MethodPermission
479      * objects that signify the method permissions for the Method and
480      * convert each to a corresponding EJBMethodPermission to be added
481      * to the policy configuration object.
482      * @param EjbDescriptor, the ejb descriptor for this EJB.
483      * @param pcid, the policy context identifier.
484      */

485     private static void
486     convertEJBMethodPermissions (EjbDescriptor eDescriptor, String JavaDoc pcid)
487     throws PolicyContextException JavaDoc {
488
489     PolicyConfiguration JavaDoc pc =
490         getPolicyFactory().getPolicyConfiguration(pcid, false);
491
492     assert pc != null;
493
494     if (pc != null) {
495
496         String JavaDoc eName = eDescriptor.getName();
497
498         Permissions JavaDoc uncheckedPermissions = null;
499         Permissions JavaDoc excludedPermissions = null;
500         HashMap JavaDoc rolePermissionsTable = null;
501
502         EJBMethodPermission JavaDoc ejbmp = null;
503
504         // phase 1
505
Map JavaDoc mpMap = eDescriptor.getMethodPermissionsFromDD();
506         if (mpMap != null) {
507
508         Iterator JavaDoc mpIt = mpMap.keySet().iterator();
509
510         while(mpIt.hasNext()) {
511
512             MethodPermission JavaDoc mp = (MethodPermission JavaDoc)mpIt.next();
513
514             Iterator JavaDoc mdIt = ((ArrayList JavaDoc) mpMap.get(mp)).iterator();
515
516             while(mdIt.hasNext()) {
517
518             MethodDescriptor md = (MethodDescriptor) mdIt.next();
519
520             String JavaDoc mthdName = md.getName();
521             String JavaDoc mthdIntf = md.getEjbClassSymbol();
522             String JavaDoc mthdParams[] = md.getStyle() == 3 ?
523                 md.getParameterClassNames() : null;
524
525             ejbmp = new EJBMethodPermission JavaDoc(eName,mthdName.equals("*") ?
526                             null : mthdName,
527                             mthdIntf,mthdParams);
528             rolePermissionsTable =
529                 addToRolePermissionsTable(rolePermissionsTable,mp,ejbmp);
530
531             uncheckedPermissions =
532                 addToUncheckedPermissions(uncheckedPermissions,mp,ejbmp);
533
534             excludedPermissions =
535                 addToExcludedPermissions(excludedPermissions,mp,ejbmp);
536             }
537         }
538         }
539
540         // phase 2 - configures additional perms:
541
// . to optimize performance of Permissions.implies
542
// . to cause any uncovered methods to be unchecked
543

544         Iterator JavaDoc mdIt = eDescriptor.getMethodDescriptors().iterator();
545         while(mdIt.hasNext()) {
546
547         MethodDescriptor md = (MethodDescriptor)mdIt.next();
548         Method JavaDoc mthd = md.getMethod(eDescriptor);
549         String JavaDoc mthdIntf = md.getEjbClassSymbol();
550
551         if(mthd == null){
552             continue;
553         }
554
555         if(mthdIntf == null || mthdIntf.equals("")) {
556             _logger.severe("MethodDescriptor interface not defined - "+
557                    " ejbName: "+eName+
558                    " methodName: " +md.getName()+
559                    " methodParams: " +md.getParameterClassNames());
560             continue;
561         }
562
563         ejbmp = new EJBMethodPermission JavaDoc(eName,mthdIntf,mthd);
564     
565         Iterator JavaDoc mpIt = eDescriptor.getMethodPermissionsFor(md).iterator();
566
567         while(mpIt.hasNext()) {
568
569             MethodPermission JavaDoc mp = (MethodPermission JavaDoc) mpIt.next();
570             
571             rolePermissionsTable =
572             addToRolePermissionsTable(rolePermissionsTable,mp,ejbmp);
573
574             uncheckedPermissions =
575             addToUncheckedPermissions(uncheckedPermissions,mp,ejbmp);
576
577             excludedPermissions =
578             addToExcludedPermissions(excludedPermissions,mp,ejbmp);
579         }
580         }
581
582         if (uncheckedPermissions != null) {
583         pc.addToUncheckedPolicy(uncheckedPermissions);
584         }
585         if (excludedPermissions != null) {
586         pc.addToExcludedPolicy(excludedPermissions);
587         }
588         if (rolePermissionsTable != null) {
589         
590         Iterator JavaDoc roleIt = rolePermissionsTable.keySet().iterator();
591
592         while (roleIt.hasNext()) {
593             String JavaDoc roleName = (String JavaDoc) roleIt.next();
594             pc.addToRole(roleName,
595                  (Permissions JavaDoc)rolePermissionsTable.get(roleName));
596         }
597         }
598     }
599     }
600
601     private ProtectionDomain JavaDoc getCachedProtectionDomain(Set JavaDoc principalSet,
602                                boolean applicationCodeSource) {
603     
604     ProtectionDomain JavaDoc prdm = null;
605     Principal JavaDoc[] principals = null;
606  
607     /* Need to use the application codeSource for permission evaluations
608      * as the manager codesource is granted all permissions in server.policy.
609      * The manager codesource needs to be used for doPrivileged to allow system
610      * apps to have all permissions, but we either need to revert to
611      * real doAsPrivileged, or find a way to distinguish system apps.
612      */

613
614     CodeSource JavaDoc cs = null;
615
616     if (applicationCodeSource) {
617         prdm = (ProtectionDomain JavaDoc)cacheProtectionDomain.get(principalSet);
618         cs = codesource;
619     } else {
620         prdm = (ProtectionDomain JavaDoc)protectionDomainCache.get(principalSet);
621         cs = managerCodeSource;
622     }
623
624     if(prdm == null) {
625
626         principals = (principalSet == null ? null :
627               (Principal JavaDoc []) principalSet.toArray(new Principal JavaDoc[0]));
628     
629         prdm = new ProtectionDomain JavaDoc (cs, null, null, principals);
630
631         if (applicationCodeSource) {
632                 // form a new key set so that it does not share with others
633
cacheProtectionDomain.put(new HashSet JavaDoc(principalSet),prdm);
634         } else {
635                 // form a new key set so that it does not share with others
636
protectionDomainCache.put(new HashSet JavaDoc(principalSet),prdm);
637         }
638
639         _logger.fine("JACC: new ProtectionDomain added to cache");
640  
641     }
642     
643     if(_logger.isLoggable(Level.FINE)){
644         if (principalSet == null) {
645         _logger.fine("JACC: returning cached ProtectionDomain PrincipalSet: null");
646         } else {
647         StringBuffer JavaDoc pBuf = null;
648         principals = (Principal JavaDoc [])principalSet.toArray(new Principal JavaDoc[0]);
649         for (int i=0; i<principals.length; i++) {
650             if (i == 0) pBuf = new StringBuffer JavaDoc(principals[i].toString());
651             else pBuf.append(" " + principals[i].toString());
652         }
653         _logger.fine("JACC: returning cached ProtectionDomain - CodeSource: ("
654                  + cs + ") PrincipalSet: "+pBuf);
655         }
656     }
657     
658     return prdm;
659     }
660
661
662     /**
663      * This method is called by the EJB container to decide whether or not
664      * a method specified in the Invocation should be allowed.
665      * @param An invocation object that contains all the details of the
666      * invocation.
667      * @return A boolean value indicating if the client should be allowed
668      * to invoke the EJB.
669      */

670     public boolean authorize(Invocation inv) {
671         
672         if (inv.auth != null) {
673             return inv.auth.booleanValue();
674         }
675         
676     boolean ret=false;
677
678     CachedPermission cp = null;
679     Permission JavaDoc ejbmp = null;
680
681     if (inv.invocationInfo == null || inv.invocationInfo.cachedPermission == null) {
682         ejbmp = new EJBMethodPermission JavaDoc(ejbName,inv.getMethodInterface(),inv.method);
683         cp = new CachedPermissionImpl(uncheckedMethodPermissionCache,ejbmp);
684         if (inv.invocationInfo != null) {
685         inv.invocationInfo.cachedPermission = cp;
686         if (_logger.isLoggable(Level.FINE)){
687             _logger.fine("JACC: permission initialized in InvocationInfo: EJBMethodPermission (Name) = "+ ejbmp.getName() + " (Action) = "+ ejbmp.getActions());
688         }
689         }
690     } else {
691         cp = inv.invocationInfo.cachedPermission;
692         ejbmp = cp.getPermission();
693     }
694
695     String JavaDoc caller = null;
696         SecurityContext sc = null;
697
698     ret = cp.checkPermission();
699
700     if (!ret) {
701
702         pcHandlerImpl.getHandlerData().setInvocation(inv);
703         
704         sc = SecurityContext.getCurrent();
705   
706         Set JavaDoc principalSet = sc.getPrincipalSet();
707  
708         ProtectionDomain JavaDoc prdm = getCachedProtectionDomain(principalSet,true);
709    
710         try {
711         // set the policy context in the TLS.
712
String JavaDoc oldContextId = setPolicyContext(this.contextId);
713
714         try {
715
716             ret = policy.implies(prdm, ejbmp);
717  
718         } catch (SecurityException JavaDoc se){
719             _logger.log(Level.SEVERE,"JACC: Unexpected security exception on access decision",se);
720             ret = false;
721         } catch (Throwable JavaDoc t) {
722             _logger.log(Level.SEVERE,"JACC: Unexpected exception on access decision",t);
723             ret = false;
724         } finally {
725             resetPolicyContext(oldContextId,this.contextId);
726         }
727
728         } catch (Throwable JavaDoc t) {
729         _logger.log(Level.SEVERE,"JACC: Unexpected exception manipulating policy context",t);
730         ret = false;
731         }
732     }
733
734         inv.auth = (ret) ? Boolean.TRUE : Boolean.FALSE;
735
736     if (auditManager.isAuditOn()){
737             if (sc == null) {
738                 sc = SecurityContext.getCurrent();
739             }
740         caller = sc.getCallerPrincipal().getName();
741         auditManager.ejbInvocation(caller, ejbName, inv.method.toString(), ret);
742     }
743
744         if (ret && inv.isWebService && !inv.preInvokeDone) {
745             preInvoke(inv);
746         }
747
748         if(_logger.isLoggable(Level.FINE)){
749         _logger.fine("JACC: Access Control Decision Result: " +ret + " EJBMethodPermission (Name) = "+ ejbmp.getName() + " (Action) = "+ ejbmp.getActions() + " (Caller) = " + caller);
750     }
751   
752     return ret;
753     }
754
755     /**
756      * Checks if any method permissions are set. If they are not set
757      * it is possible that this is a J2ee 1.2 APP and we would need to
758      * grant permissions for execution anyways
759      */

760     private boolean areMethodPermissionsSet(){
761     boolean empty =
762         deploymentDescriptor.getPermissionedMethodsByPermission().isEmpty();
763     return !empty;
764     }
765
766     /**
767      * This method is used by MDB Container - Invocation Manager to setup
768      * the run-as identity information. It has to be coupled with
769      * the postSetRunAsIdentity method.
770      * This method is called for EJB/MDB Containers
771      */

772     public void preInvoke (ComponentInvocation inv){
773         boolean isWebService = false;
774         if (inv instanceof Invocation) {
775             isWebService = ((Invocation)inv).isWebService;
776         }
777
778         // if it is not a webservice or successful authorization
779
// and preInvoke is not call before
780
if ((!isWebService || (inv.auth != null && inv.auth.booleanValue()))
781                 && !inv.preInvokeDone) {
782         if (isMdb) {
783             SecurityContext.setUnauthenticatedContext();
784         }
785             if (runAs != null){
786             inv.setOldSecurityContext(SecurityContext.getCurrent());
787                 loginForRunAs();
788             }
789             inv.preInvokeDone = true;
790         }
791     }
792
793     /**
794      * This method is used by Message Driven Bean Container to remove
795      * the run-as identity information that was set up using the
796      * preSetRunAsIdentity method
797      */

798     public void postInvoke (ComponentInvocation inv){
799     if (runAs != null && inv.preInvokeDone){
800             final ComponentInvocation finv = inv;
801             AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
802                 public Object JavaDoc run() {
803                     SecurityContext.setCurrent (finv.getOldSecurityContext());
804                     return null;
805                 }
806             });
807     }
808     }
809
810     /**
811      * Logs in a principal for run-as. This method is called if the
812      * run-as principal is required. The user has already logged in -
813      * now it needs to change to the new principal. In order that all
814      * the correct permissions work - this method logs the new principal
815      * with no password -generating valid credentials.
816      */

817     private void loginForRunAs(){
818         AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
819             public Object JavaDoc run() {
820             LoginContextDriver.loginPrincipal (runAs.getPrincipal(), realmName);
821                 return null;
822             }
823         });
824     }
825
826     
827     /**
828      * This method returns a boolean value indicating whether or not the
829      * caller is in the specified role.
830      * @param The role name in the form of java.lang.String
831      * @return A boolean true/false depending on whether or not the caller
832      * has the specified role.
833      */

834     public boolean isCallerInRole(String JavaDoc role) {
835     /* In case of Run As - Should check isCallerInRole with
836      * respect to the old security context.
837      */

838
839     boolean ret= false;
840
841     if(_logger.isLoggable(Level.FINE)){
842         _logger.entering("EJBSecurityManager", "isCallerInRole", role);
843
844     }
845     EJBRoleRefPermission JavaDoc ejbrr =
846             (EJBRoleRefPermission JavaDoc)cacheRoleToPerm.get(ejbName+"_"+role);
847         
848     if(ejbrr == null){
849         ejbrr = new EJBRoleRefPermission JavaDoc(ejbName, role);
850     }
851
852     SecurityContext sc;
853     if (runAs != null) {
854         InvocationManager im = theSwitch.getInvocationManager();
855         ComponentInvocation ci = im.getCurrentInvocation();
856         sc = ci.getOldSecurityContext();
857     } else {
858         sc = SecurityContext.getCurrent();
859     }
860     Set JavaDoc principalSet = null;
861     if (sc != null) principalSet = sc.getPrincipalSet();
862  
863     ProtectionDomain JavaDoc prdm = getCachedProtectionDomain(principalSet,true);
864  
865     try {
866
867         ret = policy.implies(prdm, ejbrr);
868     } catch(SecurityException JavaDoc se){
869         _logger.log(Level.SEVERE,"JACC: Unexpected security exception isCallerInRole",se);
870         ret = false;
871     } catch (Throwable JavaDoc t) {
872         _logger.log(Level.SEVERE,"JACC: Unexpected exception isCallerInRole",t);
873         ret = false;
874     }
875  
876     if(_logger.isLoggable(Level.FINE)){
877         _logger.fine("JACC: isCallerInRole Result: " +ret + " EJBRoleRefPermission (Name) = "+ ejbrr.getName() + " (Action) = "+ ejbrr.getActions() + " (Codesource) = " + prdm.getCodeSource());
878     }
879   
880     return ret;
881     }
882
883     /**
884      * This method returns the Client Principal who initiated the current
885      * Invocation.
886      * @return A Principal object of the client who made this invocation.
887      * or null if the SecurityContext has not been established by the client.
888      */

889     public Principal JavaDoc getCallerPrincipal() {
890     SecurityContext sc = null;
891     if (runAs != null){ // Run As
892
/* return the principal associated with the old security
893          * context
894          */

895         InvocationManager im = theSwitch.getInvocationManager();
896         ComponentInvocation ci = im.getCurrentInvocation();
897
898         if (ci == null) {
899         throw new InvocationException(); // 4646060
900
}
901         sc = ci.getOldSecurityContext();
902             
903     } else{
904         // lets optimize a little. no need to look up oldsecctx
905
// its the same as the new one
906
sc = SecurityContext.getCurrent();
907     }
908  
909     Principal JavaDoc prin;
910  
911     if (sc != null) {
912         prin = sc.getCallerPrincipal();
913     } else {
914         prin = SecurityContext.getDefaultCallerPrincipal();
915     }
916     return prin;
917       }
918
919     public void destroy() {
920
921        try {
922
923            PolicyConfigurationFactory JavaDoc pcf = getPolicyFactory();
924        boolean wasInService = pcf.inService(this.contextId);
925
926        PolicyConfiguration JavaDoc
927            pc = pcf.getPolicyConfiguration(this.contextId, false);
928        // pc.delete() will be invoked during undeployment
929

930        if (wasInService) {
931            policy.refresh();
932                PermissionCacheFactory.removePermissionCache(uncheckedMethodPermissionCache);
933            uncheckedMethodPermissionCache = null;
934        }
935            roleMapperFactory.removeAppNameForContext(this.contextId);
936
937        } catch (PolicyContextException JavaDoc pce){
938            String JavaDoc msg = localStrings.getLocalString("ejbsm.could_not_delete",
939                                                     "Could not delete policy file during undeployment");
940            // Just log it.
941
_logger.log(Level.WARNING, msg, pce);
942        }
943
944         FactoryForSecurityManagerFactory ffsmf
945             = FactoryForSecurityManagerFactoryImpl.getInstance();
946         SecurityManagerFactory smf = ffsmf.getSecurityManagerFactory("ejb");
947         smf.removeSecurityManager(contextId);
948     }
949     /**
950      * This will return the subject associated with the current call. If the
951      * run as subject is in effect. It will return that subject. This is done
952      * to support the JACC specification which says if the runas principal is
953      * in effect, that principal should be used for making a component call.
954      * @return Subject the current subject. Null if this is not the run-as
955      * case
956      */

957     public Subject JavaDoc getCurrentSubject(){
958     // just get the security context will return the empt subject
959
// of the default securityContext when appropriate.
960
return SecurityContext.getCurrent().getSubject();
961     }
962
963     /* This method is used by SecurityUtil runMethod to run the
964      * action as the subject encapsulated in the current
965      * SecurityContext.
966      */

967     public Object JavaDoc doAsPrivileged(PrivilegedExceptionAction JavaDoc pea)
968     throws Throwable JavaDoc {
969     
970     SecurityContext sc = SecurityContext.getCurrent();
971     
972     Set JavaDoc principalSet = sc.getPrincipalSet();
973  
974     AccessControlContext JavaDoc acc =
975         (AccessControlContext JavaDoc)accessControlContextCache.get(principalSet);
976     
977     if(acc == null){
978  
979         final ProtectionDomain JavaDoc[] pdArray = new ProtectionDomain JavaDoc[1];
980         pdArray[0] = getCachedProtectionDomain(principalSet,false);
981
982         try{
983  
984         if (principalSet != null) {
985  
986             final Subject JavaDoc s = sc.getSubject();
987  
988             acc = (AccessControlContext JavaDoc)
989             AccessController.doPrivileged(new PrivilegedExceptionAction JavaDoc(){
990                 public java.lang.Object JavaDoc run() throws Exception JavaDoc{
991                     return new AccessControlContext JavaDoc
992                     (new AccessControlContext JavaDoc(pdArray),
993                      new SubjectDomainCombiner JavaDoc(s));
994                 }
995                 });
996         } else {
997             acc = new AccessControlContext JavaDoc(pdArray);
998         }
999
1000                // form a new key set so that it does not share with
1001
// cacheProtectionDomain and protectionDomainCache
1002
accessControlContextCache.put(new HashSet JavaDoc(principalSet),acc);
1003 
1004        _logger.fine("JACC: new AccessControlContext added to cache");
1005
1006        } catch(Exception JavaDoc e){
1007        _logger.log(Level.SEVERE,
1008                "java_security.security_context_exception",e);
1009        acc = null;
1010        throw e;
1011        }
1012    }
1013 
1014    Object JavaDoc rvalue = null;
1015
1016    String JavaDoc oldContextId = setPolicyContext(this.contextId);
1017
1018    if(_logger.isLoggable(Level.FINE)){
1019        _logger.fine("JACC: doAsPrivileged contextId("+this.contextId+")");
1020    }
1021
1022    try {
1023
1024        rvalue = AccessController.doPrivileged(pea,acc);
1025
1026    } finally {
1027        resetPolicyContext(oldContextId,this.contextId);
1028    }
1029
1030    return rvalue;
1031
1032    }
1033    
1034    /**
1035     * Runs a business method of an EJB withint the bean's policy context.
1036     * The original policy context is restored after method execution.
1037     * This method should only be used by com.sun.enterprise.security.SecurityUtil.
1038     * @param beanClassMethod the EJB business method
1039     * @param obj the EJB bean instance
1040     * @param oa parameters passed to beanClassMethod
1041     * @throws InvocationTargetException if the underlying method throws an exception
1042     * @throws Throwable other throwables in other cases
1043     * @return return value from beanClassMethod
1044     */

1045    public Object JavaDoc runMethod(Method JavaDoc beanClassMethod, Object JavaDoc obj, Object JavaDoc[] oa)
1046            throws Throwable JavaDoc {
1047        String JavaDoc oldCtxID = setPolicyContext(this.contextId);
1048        Object JavaDoc ret = null;
1049        try {
1050            ret = beanClassMethod.invoke(obj, oa);
1051        } finally {
1052            resetPolicyContext(oldCtxID, this.contextId);
1053        }
1054        return ret;
1055    }
1056 
1057    private static void resetPolicyContext(final String JavaDoc newV, String JavaDoc oldV)
1058    throws Throwable JavaDoc {
1059    if (oldV != newV && newV != null && (oldV == null || !oldV.equals(newV))) {
1060
1061        if(_logger.isLoggable(Level.FINE)){
1062        _logger.fine("JACC: Changing Policy Context ID: oldV = "
1063                 + oldV + " newV = " + newV);
1064        }
1065        try {
1066        AccessController.doPrivileged(new PrivilegedExceptionAction JavaDoc(){
1067            public java.lang.Object JavaDoc run() throws Exception JavaDoc{
1068                PolicyContext.setContextID(newV);
1069                return null;
1070            }
1071            });
1072        } catch (java.security.PrivilegedActionException JavaDoc pae) {
1073        Throwable JavaDoc cause = pae.getCause();
1074        if( cause instanceof java.security.AccessControlException JavaDoc) {
1075            _logger.log(Level.SEVERE,"setPolicy SecurityPermission required to call PolicyContext.setContextID",cause);
1076        } else {
1077            _logger.log(Level.SEVERE,"Unexpected Exception while setting PolicyContext",cause);
1078        }
1079        throw cause;
1080        }
1081    }
1082    }
1083
1084    private static String JavaDoc setPolicyContext(String JavaDoc newV) throws Throwable JavaDoc {
1085
1086    String JavaDoc oldV = PolicyContext.getContextID();
1087
1088    resetPolicyContext(newV,oldV);
1089
1090    return oldV;
1091    }
1092
1093}
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
Popular Tags