KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > web > security > WebSecurityManager


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
24 package com.sun.web.security;
25
26 import java.io.File JavaDoc;
27 import java.security.*;
28 import java.util.Set JavaDoc;
29 import java.util.HashSet JavaDoc;
30 import java.util.List JavaDoc;
31 import java.util.ArrayList JavaDoc;
32 import java.util.Iterator JavaDoc;
33 import java.util.Map JavaDoc;
34 import java.util.WeakHashMap JavaDoc;
35 import java.util.Collections JavaDoc;
36 import java.lang.*;
37 import java.net.URL JavaDoc;
38 import java.net.URLEncoder JavaDoc;
39 import java.net.URI JavaDoc;
40
41 import javax.servlet.http.HttpServletRequest JavaDoc;
42 import javax.security.jacc.*;
43
44 import java.util.logging.*;
45 import java.util.HashMap JavaDoc;
46 import java.util.Map JavaDoc;
47 import com.sun.logging.LogDomains;
48 import com.sun.web.security.WebPermissionUtil;
49 import com.sun.enterprise.deployment.WebBundleDescriptor;
50 import com.sun.enterprise.security.authorize.*;
51 import com.sun.enterprise.security.CachedPermission;
52 import com.sun.enterprise.security.CachedPermissionImpl;
53 import com.sun.enterprise.security.PermissionCache;
54 import com.sun.enterprise.security.PermissionCacheFactory;
55 import com.sun.enterprise.security.SecurityContext;
56 import com.sun.enterprise.security.audit.AuditManager;
57 import com.sun.enterprise.security.audit.AuditManagerFactory;
58 import com.sun.enterprise.security.authorize.PolicyContextHandlerImpl;
59 import com.sun.enterprise.web.WebContainer;
60 import com.sun.enterprise.deployment.runtime.common.SecurityRoleMapping;
61 import com.sun.enterprise.deployment.PrincipalImpl;
62 import com.sun.enterprise.deployment.Group;
63 import com.sun.enterprise.config.serverbeans.*;
64 import com.sun.enterprise.config.*;
65 import com.sun.enterprise.server.ApplicationServer;
66 import com.sun.enterprise.deployment.web.LoginConfiguration;
67 import com.sun.enterprise.deployment.runtime.web.SunWebApp;
68 import com.sun.enterprise.deployment.interfaces.SecurityRoleMapper;
69 import com.sun.enterprise.deployment.interfaces.SecurityRoleMapperFactory;
70 import com.sun.enterprise.deployment.interfaces.SecurityRoleMapperFactoryMgr;
71 import org.apache.catalina.HttpRequest;
72
73 /**
74  * The class implements the JSR 115 - JavaTM Authorization Contract for Containers.
75  * This class is a companion class of EJBSecurityManager.
76  *
77  * All the security decisions required to allow access to a resource are defined
78  * in that class.
79  *
80  * @author Jean-Francois Arcand
81  * @author Harpreet Singh.
82  * @todo introduce a new class called AbstractSecurityManager. Move functionality
83  * from this class and EJBSecurityManager class and extend this class from
84  * AbstractSecurityManager
85  */

86 public class WebSecurityManager {
87     private static Logger logger =
88     Logger.getLogger(LogDomains.SECURITY_LOGGER);
89
90     private static AuditManager auditManager =
91         AuditManagerFactory.getAuditManagerInstance();
92     private static final String JavaDoc RESOURCE = "hasResourcePermission";
93     private static final String JavaDoc USERDATA = "hasUserDataPermission";
94     private static final String JavaDoc ROLEREF = "hasRoleRefPermission";
95
96     private static final String JavaDoc DEFAULT_PATTERN = "/";
97     private static final String JavaDoc EMPTY_STRING = "";
98  
99     private static final PolicyContextHandlerImpl pcHandlerImpl =
100             (PolicyContextHandlerImpl)PolicyContextHandlerImpl.getInstance();
101     
102     private static final Map JavaDoc ADMIN_PRINCIPAL = new HashMap JavaDoc();
103     private static final Map JavaDoc ADMIN_GROUP = new HashMap JavaDoc();
104
105     // The context ID associated with this instance. This is the name
106
// of the application
107
private String JavaDoc CONTEXT_ID = null;
108     private String JavaDoc CODEBASE = null;
109     
110     // The JACC policy provider.
111
protected Policy policy = Policy.getPolicy();
112
113     protected PolicyConfiguration policyConfiguration = null;
114     protected PolicyConfigurationFactory policyConfigurationFactory = null;
115     protected CodeSource codesource = null;
116
117     // protection domain cache
118
private Map JavaDoc protectionDomainCache =
119         Collections.synchronizedMap(new WeakHashMap JavaDoc());
120
121     private static WebResourcePermission allResources =
122     new WebResourcePermission("/*",(String JavaDoc) null);
123
124     private static WebUserDataPermission allConnections =
125     new WebUserDataPermission("/*",null);
126
127     private static Permission[] protoPerms = {
128         allResources,
129     allConnections
130     };
131
132     // permissions tied to unchecked permission cache, and used
133
// to determine if the effective policy is grant all
134
// WebUserData and WebResource permisions.
135
private CachedPermission allResourcesCP = null;
136      
137     private CachedPermission allConnectionsCP = null;
138  
139     // unchecked permission cache
140
private PermissionCache uncheckedPermissionCache = null;
141     
142     private static Set JavaDoc defaultPrincipalSet =
143     SecurityContext.getDefaultSecurityContext().getPrincipalSet();
144
145     private static SecurityRoleMapperFactory factory =
146     SecurityRoleMapperFactoryMgr.getFactory();
147
148     // WebBundledescriptor
149
private WebBundleDescriptor wbd = null;
150     // Create a WebSecurityObject
151
public WebSecurityManager(WebBundleDescriptor wbd) throws PolicyContextException {
152         this.wbd = wbd;
153         this.CONTEXT_ID = getContextID(wbd);
154         String JavaDoc appname = getAppId();
155         factory.setAppNameForContext(appname, CONTEXT_ID);
156         initialise();
157     }
158
159     private String JavaDoc removeSpaces(String JavaDoc withSpaces){
160         return withSpaces.replace(' ', '_');
161     }
162     // fix for CR 6155144
163
// used to get the policy context id. Also used by the RealmAdapter
164
public static String JavaDoc getContextID(WebBundleDescriptor wbd) {
165         String JavaDoc cid = null;
166         if (wbd != null ) {
167             String JavaDoc moduleId = wbd.getUniqueFriendlyId();
168             cid = wbd.getApplication().getRegistrationName() +
169                 '/' + wbd.getUniqueFriendlyId();
170         }
171         return cid;
172    }
173       
174     private void initialise() throws PolicyContextException {
175        String JavaDoc appName = wbd.getApplication().getRegistrationName();
176         CODEBASE = removeSpaces(CONTEXT_ID) ;
177         if(WebContainer.ADMIN_VS.equals(getVirtualServers(appName))){
178             LoginConfiguration lgConf = wbd.getLoginConfiguration();
179             if (lgConf != null){
180                 String JavaDoc realmName = lgConf.getRealmName();
181                 SunWebApp sunDes = wbd.getSunDescriptor();
182                 if(sunDes != null){
183                     SecurityRoleMapping[] sr = sunDes.getSecurityRoleMapping();
184                     if(sr != null){
185                         for(int i=0; i<sr.length; i++){
186                             String JavaDoc[] principal = sr[i].getPrincipalName();
187                             if(principal != null){
188                                 for(int plen=0;plen<principal.length; plen++ ){
189                                     ADMIN_PRINCIPAL.put(realmName+principal[plen], new PrincipalImpl(principal[plen]));
190                                 }
191                             }
192                             List JavaDoc<String JavaDoc> groups = sr[i].getGroupNames();
193                             for(int glen = 0; glen < groups.size(); glen++ ){
194                                 ADMIN_GROUP.put(realmName+groups.get(glen), new Group(groups.get(glen))) ;
195                             }
196                         }
197                     }
198                 }
199             }
200         }
201  
202         // will require stuff in hash format for reference later on.
203
try{
204             java.net.URI JavaDoc uri = null;
205             try{
206         if(logger.isLoggable(Level.FINE))
207             logger.log(Level.FINE, "[Web-Security] Creating a Codebase URI with = "+CODEBASE);
208         uri = new java.net.URI JavaDoc("file:///"+ CODEBASE);
209         if(uri != null){
210             codesource = new CodeSource(new URL JavaDoc(uri.toString()),
211                             (java.security.cert.Certificate JavaDoc[]) null);
212         }
213         
214             } catch(java.net.URISyntaxException JavaDoc use){
215                 // manually create the URL
216
logger.log(Level.FINE, "[Web-Security] Error Creating URI ", use);
217                 throw new RuntimeException JavaDoc(use);
218             }
219
220         } catch(java.net.MalformedURLException JavaDoc mue){
221             logger.log(Level.SEVERE, "ejbsm.codesourceerror", mue);
222             throw new RuntimeException JavaDoc(mue);
223         }
224
225         if(logger.isLoggable(Level.FINE)){
226             logger.fine("[Web-Security] Context id (id under which WEB component in application will be created) = "+ CONTEXT_ID);
227             logger.fine("[Web-Security] Codebase (module id for web component) "+ CODEBASE);
228         }
229
230     boolean inService = getFactory().inService(CONTEXT_ID);
231
232     // only regenerate policy file if it isn't already in service
233
// Consequently all things that deploy modules (as apposed to
234
// loading already deployed modules) must make sure pre-exiting
235
// pc is either in deleted or open state before this method
236
// (i.e. initialise) is called. That is, before constructing
237
// the WebSecurityManager. Note that policy statements are not
238
// removed to allow multiple web modules to be represented by same pc.
239

240     if (!inService) {
241         policyConfiguration = getFactory().getPolicyConfiguration(CONTEXT_ID,false);
242         generatePermissions();
243     }
244  
245     if (uncheckedPermissionCache == null) {
246         uncheckedPermissionCache =
247         PermissionCacheFactory.createPermissionCache
248         (this.CONTEXT_ID, codesource, protoPerms, null);
249
250         if (uncheckedPermissionCache != null) {
251  
252         allResourcesCP =
253             new CachedPermissionImpl(uncheckedPermissionCache,
254                          allResources);
255         allConnectionsCP =
256             new CachedPermissionImpl(uncheckedPermissionCache,
257                          allConnections);
258         }
259
260     } else {
261         uncheckedPermissionCache.reset();
262     }
263  
264     }
265     // this will change too - get the application id name
266
private String JavaDoc getAppId() {
267         return wbd.getApplication().getRegistrationName();
268     }
269
270     /*
271      * Invoke the <code>Policy</code> to determine if the <code>Permission</code>
272      * object has security permission.
273      * @param perm an instance of <code>Permission</code>.
274      * @param principalSet a set containing the principals to check for authorization
275      * @return true if granted, false if denied.
276      */

277     protected boolean checkPermission(Permission perm, Set JavaDoc principalSet) {
278          
279         try{
280  
281         // NOTE: there is an assumption here, that this setting of the PC will
282
// remain in affect through the component dispatch, and that the
283
// component will not call into any other policy contexts.
284
// even so, could likely reset on failed check.
285

286         setPolicyContext(CONTEXT_ID);
287  
288     } catch(Throwable JavaDoc t){
289         logger.log(Level.FINE, "[Web-Security] Web Permission Access Denied.",t);
290         return false;
291     }
292  
293         boolean ret = false;
294
295     if (uncheckedPermissionCache != null) {
296         ret = uncheckedPermissionCache.checkPermission(perm);
297     }
298
299     if (!ret) {
300
301         ProtectionDomain prdm =
302         (ProtectionDomain)protectionDomainCache.get(principalSet);
303   
304         if (prdm == null) {
305
306         Principal[] principals = null;
307                 principals = (principalSet == null ? null :
308                       (Principal []) principalSet.toArray(new Principal[0]));
309
310         if(logger.isLoggable(Level.FINE)){
311             logger.log(Level.FINE,"[Web-Security] Generating a protection domain for Permission check.");
312
313                     for (int i=0; i<principals.length; i++){
314                         logger.log(Level.FINE, "[Web-Security] Checking with Principal : "+ principals[i].toString());
315                     }
316         }
317
318         prdm = new ProtectionDomain(codesource, null, null,principals);
319         protectionDomainCache.put(principalSet,prdm);
320         }
321
322         if(logger.isLoggable(Level.FINE)){
323         logger.log(Level.FINE, "[Web-Security] Codesource with Web URL: " + codesource.getLocation().toString());
324         logger.log(Level.FINE, "[Web-Security] Checking Web Permission with Principals : "+ principalSetToString(principalSet));
325         logger.log(Level.FINE, "[Web-Security] Web Permission = " +perm.toString());
326         }
327   
328         ret = policy.implies(prdm, perm);
329     }
330
331         return ret;
332     }
333     
334     protected PolicyConfigurationFactory getFactory() throws PolicyContextException{
335         if (policyConfigurationFactory == null){
336             try{
337                 policyConfigurationFactory = PolicyConfigurationFactory.getPolicyConfigurationFactory();
338             } catch(java.lang.ClassNotFoundException JavaDoc ex){
339                 // FIX ME: Need to create an approriate exception
340
throw new PolicyContextException(ex);
341             }
342         }
343         return policyConfigurationFactory;
344     }
345     
346     private WebResourcePermission createWebResourcePermission(
347             HttpServletRequest JavaDoc httpsr) {
348         String JavaDoc originalUri = httpsr.getRequestURI();
349         String JavaDoc mappedUri = (((HttpRequest) httpsr).getRequestPathMB() != null) ?
350             ((HttpRequest) httpsr).getRequestPathMB().toString() : null;
351         if (mappedUri == null) {
352             if (logger.isLoggable(Level.FINE)){
353                 logger.log(Level.FINE,"[Web-Security] mappedUri is null");
354             }
355             throw new RuntimeException JavaDoc("Fatal Error in creating WebResourcePermission");
356         }
357         if(mappedUri.equals("/")) {
358             mappedUri = EMPTY_STRING;
359         }
360         WebResourcePermission perm = new WebResourcePermission(
361                 mappedUri, httpsr.getMethod());
362         return perm;
363     }
364     
365     /**
366      * Perform access control based on the <code>HttpServletRequest</code>.
367      * Return <code>true</code> if this constraint is satisfied and processing
368      * should continue, or <code>false</code> otherwise.
369      * @return true is the resource is granted, false if denied
370      */

371     public boolean hasResourcePermission(HttpServletRequest JavaDoc httpsr){
372     SecurityContext sc = getSecurityContext(httpsr.getUserPrincipal());
373         WebResourcePermission perm = createWebResourcePermission(httpsr);
374         setSecurityInfo(httpsr);
375         boolean isGranted = checkPermission(perm,sc.getPrincipalSet());
376     SecurityContext.setCurrent(sc);
377         if(logger.isLoggable(Level.FINE)){
378             logger.log(Level.FINE,"[Web-Security] hasResource isGranted: " + isGranted);
379             logger.log(Level.FINE,"[Web-Security] hasResource perm: " + perm);
380         }
381         if(auditManager.isAuditOn()){
382             Principal prin = httpsr.getUserPrincipal();
383             String JavaDoc user = (prin != null) ? prin.getName(): null;
384             auditManager.webInvocation(user, httpsr, RESOURCE, isGranted);
385         }
386         return isGranted;
387     }
388     
389     
390     /*
391      * Return <code>true</code> if the specified servletName has the specified
392      * security role, within the context of the WebRoleRefPermission;
393      * otherwise return
394      * <code>false</code>.
395      *
396      * @param principal servletName the resource's name.
397      * @param principal Principal for whom the role is to be checked
398      * @param role Security role to be checked
399      * @return true is the resource is granted, false if denied
400      */

401     public boolean hasRoleRefPermission(String JavaDoc servletName, String JavaDoc role, Principal p) {
402     Set JavaDoc principalSet = getSecurityContext(p).getPrincipalSet();
403         WebRoleRefPermission perm = new WebRoleRefPermission(servletName, role);
404         boolean isGranted = checkPermission(perm,principalSet);
405         if(logger.isLoggable(Level.FINE)){
406             logger.log(Level.FINE,"[Web-Security] hasRoleRef perm: " + perm);
407             logger.log(Level.FINE,"[Web-Security] hasRoleRef isGranted: " + isGranted);
408         }
409         return isGranted;
410     }
411
412     
413     /*
414      * Enforce any user data constraint required by the security constraint
415      * guarding this request URI. Return <code>true</code> if this constraint
416      * was not violated and processing should continue, or <code>false</code>
417      * if we have created a response already.
418      *
419      * @return true is the user is granted, false if denied.
420      */

421     public int hasUserDataPermission(HttpServletRequest JavaDoc httpsr){
422         setSecurityInfo(httpsr);
423         WebUserDataPermission perm = new WebUserDataPermission(httpsr);
424         boolean isGranted = checkPermission(perm, defaultPrincipalSet);
425         int result = 0;
426        
427         if ( isGranted ) {
428             result = 1;
429         }
430  
431         if(logger.isLoggable(Level.FINE)){
432             logger.log(Level.FINE,"[Web-Security] hasUserDataPermission perm: " + perm);
433             logger.log(Level.FINE,"[Web-Security] hasUserDataPermission isGranted: " + isGranted);
434         }
435
436         if(auditManager.isAuditOn()){
437             Principal prin = httpsr.getUserPrincipal();
438             String JavaDoc user = (prin != null) ? prin.getName(): null;
439             auditManager.webInvocation(user, httpsr, USERDATA, isGranted);
440         }
441
442         if ( !isGranted ) {
443
444              perm = new WebUserDataPermission
445          ( perm.getName(),
446            new String JavaDoc[] { httpsr.getMethod() },
447            "CONFIDENTIAL" );
448
449              isGranted = checkPermission(perm, defaultPrincipalSet);
450
451              if (isGranted)
452                 result = -1;
453         }
454         
455         return result;
456     }
457
458     private void generatePermissions(){
459         try{
460             WebPermissionUtil.processConstraints(wbd, policyConfiguration);
461             WebPermissionUtil.createWebRoleRefPermission(wbd, policyConfiguration);
462         } catch (PolicyContextException pce){
463             logger.log(Level.FINE,"[Web-Security] FATAL Permission Generation: " + pce.getMessage());
464             throw new RuntimeException JavaDoc("Fatal error creating web permissions", pce);
465         }
466     }
467     
468     public void destroy() throws PolicyContextException {
469         boolean wasInService = getFactory().inService(CONTEXT_ID);
470     if (policyConfiguration == null) {
471         policyConfiguration = getFactory().
472         getPolicyConfiguration(CONTEXT_ID,false);
473     }
474         if (wasInService) {
475             policy.refresh();
476             PermissionCacheFactory.removePermissionCache
477         (uncheckedPermissionCache);
478             uncheckedPermissionCache = null;
479         }
480         factory.removeAppNameForContext(CONTEXT_ID);
481         // pc.delete() will be invoked during undeployment
482
//policyConfiguration.delete();
483
}
484    
485     private static String JavaDoc setPolicyContext(final String JavaDoc ctxID) throws Throwable JavaDoc {
486     String JavaDoc old = PolicyContext.getContextID();
487     if (old != ctxID &&
488         (old == null || ctxID == null || !old.equals(ctxID))) {
489   
490         if(logger.isLoggable(Level.FINE)){
491         logger.fine("[Web-Security] Setting Policy Context ID: old = " + old +
492                 " ctxID = " + ctxID);
493         }
494   
495         try {
496         AccessController.doPrivileged(new PrivilegedExceptionAction(){
497             public java.lang.Object JavaDoc run() throws Exception JavaDoc{
498             PolicyContext.setContextID(ctxID);
499             return null;
500             }
501         });
502         } catch (java.security.PrivilegedActionException JavaDoc pae) {
503         Throwable JavaDoc cause = pae.getCause();
504         if( cause instanceof java.security.AccessControlException JavaDoc) {
505             logger.log(Level.SEVERE,"[Web-Security] setPolicy SecurityPermission required to call PolicyContext.setContextID",cause);
506         } else {
507             logger.log(Level.SEVERE,"[Web-Security] Unexpected Exception while setting policy context",cause);
508         }
509         throw cause;
510         }
511     } else if(logger.isLoggable(Level.FINE)){
512         logger.fine("[Web-Security] Policy Context ID was: " + old);
513     }
514     return old;
515     }
516     
517     /**
518      * This is an private method for transforming principal into a SecurityContext
519      * @param principal expected to be a WebPrincipal
520      * @return SecurityContext
521      */

522     private SecurityContext getSecurityContext(Principal principal) {
523         SecurityContext secContext = null;
524         if (principal != null) {
525         if (principal instanceof WebPrincipal){
526         WebPrincipal wp = (WebPrincipal)principal;
527         secContext = wp.getSecurityContext();
528         }else {
529         secContext = new SecurityContext(principal.getName(),null);
530         }
531         }
532     if (secContext == null) {
533             secContext = SecurityContext.getDefaultSecurityContext();
534         }
535     return secContext;
536     }
537
538     /**
539      * This is an private method for policy context handler data info
540      * @param httpRequest
541      */

542     private void setSecurityInfo(HttpServletRequest JavaDoc httpRequest) {
543         if (httpRequest != null) {
544             pcHandlerImpl.getHandlerData().setHttpServletRequest(httpRequest);
545         }
546     }
547
548     private String JavaDoc principalSetToString(Set JavaDoc principalSet) {
549     String JavaDoc result = null;
550     if (principalSet != null) {
551         Principal[] principals =
552         (Principal []) principalSet.toArray(new Principal[0]);
553         for (int i =0; i<principals.length; i++) {
554         if (i == 0) {
555             result = principals[i].toString();
556         } else {
557             result = result + ", "+ new String JavaDoc(principals[i].toString());
558         }
559         }
560     }
561     return result;
562     }
563     
564     private String JavaDoc getVirtualServers(String JavaDoc appName) {
565         String JavaDoc ret = null;
566         try {
567             ConfigContext ctx =
568                 ApplicationServer.getServerContext().getConfigContext();
569             ret = ServerBeansFactory
570                     .getVirtualServersByAppName(ctx, appName);
571         } catch (ConfigException ce) {
572             logger.log(Level.FINE, "Cannot get virtual server for " + appName, ce);
573         }
574         return ret;
575     }
576     
577     public static Principal getAdminPrincipal(String JavaDoc username, String JavaDoc realmName){
578         return (Principal)ADMIN_PRINCIPAL.get(realmName+username);
579     }
580     public static Principal getAdminGroup(String JavaDoc group, String JavaDoc realmName){
581         return (Principal)ADMIN_GROUP.get(realmName+group);
582     }
583     
584     public boolean hasNoConstrainedResources() {
585     if (allResourcesCP != null && allConnectionsCP != null) {
586         boolean x = allResourcesCP.checkPermission();
587         boolean y = allConnectionsCP.checkPermission();
588         return x && y;
589         }
590     return false;
591     }
592 }
593
Popular Tags