001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 2004-2005 Bull S.A.
004: * Contact: jonas-team@objectweb.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: PermissionManager.java 8321 2006-05-09 14:18:10Z benoitf $
023: * --------------------------------------------------------------------------
024: */package org.objectweb.jonas.web.lib;
025:
026: import java.net.MalformedURLException;
027: import java.net.URI;
028: import java.net.URISyntaxException;
029: import java.net.URL;
030: import java.security.CodeSource;
031: import java.security.Permission;
032: import java.security.PermissionCollection;
033: import java.security.Principal;
034: import java.security.ProtectionDomain;
035: import java.security.cert.Certificate;
036: import java.util.ArrayList;
037: import java.util.Collection;
038: import java.util.Iterator;
039: import java.util.List;
040: import java.util.Map;
041:
042: import javax.security.jacc.PolicyContext;
043: import javax.security.jacc.PolicyContextException;
044: import javax.security.jacc.WebResourcePermission;
045: import javax.security.jacc.WebRoleRefPermission;
046: import javax.security.jacc.WebUserDataPermission;
047: import javax.servlet.http.HttpServletRequest;
048:
049: import org.objectweb.jonas.common.Log;
050: import org.objectweb.jonas.security.jacc.JPolicyContextHandlerCurrent;
051: import org.objectweb.jonas.security.jacc.JPolicyContextHandlerData;
052: import org.objectweb.jonas.security.jacc.JPolicyUserRoleMapping;
053:
054: import org.objectweb.jonas_lib.deployment.api.SecurityRoleRefDesc;
055: import org.objectweb.jonas_lib.security.AbsPermissionManager;
056: import org.objectweb.jonas_lib.security.PermissionManagerException;
057: import org.objectweb.jonas_web.deployment.api.SecurityConstraintListDesc;
058: import org.objectweb.jonas_web.deployment.api.SecurityRoleDesc;
059: import org.objectweb.jonas_web.deployment.api.ServletDesc;
060: import org.objectweb.jonas_web.deployment.api.WebContainerDeploymentDesc;
061: import org.objectweb.util.monolog.api.BasicLevel;
062: import org.objectweb.util.monolog.api.Logger;
063:
064: /**
065: * Defines a PermissionManager class which will manage JACC permissions for a
066: * web-app
067: * @author Florent Benoit
068: */
069: public class PermissionManager extends AbsPermissionManager {
070:
071: /**
072: * Logger used
073: */
074: private static Logger logger = null;
075:
076: /**
077: * Deployment desc of the module
078: */
079: private WebContainerDeploymentDesc webContainerDeploymentDesc = null;
080:
081: /**
082: * Default Constructor
083: * @param webContainerDeploymentDesc EJB deployment Descriptor
084: * @param contextId context ID used for PolicyContext
085: * @param remove - remove the policy context when creating a new one.
086: * @throws PermissionManagerException if permissions can't be set
087: */
088: public PermissionManager(
089: final WebContainerDeploymentDesc webContainerDeploymentDesc,
090: final String contextId, boolean remove)
091: throws PermissionManagerException {
092: super (contextId, remove);
093: this .webContainerDeploymentDesc = webContainerDeploymentDesc;
094: logger = Log.getLogger(Log.JONAS_WEB_PREFIX);
095: }
096:
097: /**
098: * 3.1.3.Translating Servlet Deployment Descriptors A reference to a
099: * PolicyConfiguration object must be obtained by calling the
100: * getPolicyConfiguration method on the PolicyConfigurationFactory
101: * implementation class of the provider configured into the container. The
102: * policy context identifier used in the call to the getPolicyConfiguration
103: * method must be a String composed as described in Section 3.1.2, Servlet
104: * Policy Context Identifiers, on page 19. The value true must be passed as
105: * the second parameter in the call to getPolicyConfiguration to ensure that
106: * any and all policy statements are removed from the policy context
107: * associated with the returned PolicyConfiguration. The security-constraint
108: * and securityrole-ref elements in the deployment descriptor must be
109: * translated into permissions and added to the PolicyConfiguration object
110: * as defined in the following sections.
111: * @throws PermissionManagerException if permissions can't be set
112: */
113: public void translateServletDeploymentDescriptor()
114: throws PermissionManagerException {
115: translateSecurityConstraintElements();
116: translateServletSecurityRoleRef();
117: }
118:
119: /**
120: * 3.1.3.1 Translating security-constraint elements The paragraphs of this
121: * section describe the translation of security-constraints into
122: * WebResourcePermission and WebUserDataPermission objects constructed using
123: * qualified URL pattern names. In the exceptional case, as defined in
124: * Qualified URL Pattern Names, where a pattern is made irrelevant by a
125: * qualifying pattern, the permission instantiations that would result from
126: * the translation of the pattern, as described below, must not be
127: * performed. Otherwise, the translation of URL patterns in security
128: * constraints must yield an equivalent translation to the translation that
129: * would result from following the instructions in the remainder of this
130: * section. [...]
131: * @throws PermissionManagerException if permissions can't be set
132: */
133: protected void translateSecurityConstraintElements()
134: throws PermissionManagerException {
135: if (webContainerDeploymentDesc == null
136: || getPolicyConfiguration() == null) {
137: throw new PermissionManagerException(
138: "PolicyConfiguration or webContainerbDeploymentDesc is null");
139: }
140:
141: SecurityConstraintListDesc securityConstraintListDesc = webContainerDeploymentDesc
142: .getSecurityConstraintListDesc();
143: PermissionCollection excludedPermissions = securityConstraintListDesc
144: .getExcludedPermissions();
145: PermissionCollection uncheckedPermissions = securityConstraintListDesc
146: .getUncheckedPermissions();
147: PermissionCollection rolePermissions = null;
148: String roleName = null;
149: Map roleMapPermissions = securityConstraintListDesc
150: .getPermissionsByRole();
151:
152: try {
153: getPolicyConfiguration().addToExcludedPolicy(
154: excludedPermissions);
155: getPolicyConfiguration().addToUncheckedPolicy(
156: uncheckedPermissions);
157:
158: for (Iterator rolesIt = roleMapPermissions.keySet()
159: .iterator(); rolesIt.hasNext();) {
160: roleName = (String) rolesIt.next();
161: rolePermissions = (PermissionCollection) roleMapPermissions
162: .get(roleName);
163: getPolicyConfiguration().addToRole(roleName,
164: rolePermissions);
165: }
166: } catch (PolicyContextException pce) {
167: throw new PermissionManagerException(
168: "Can not add add permissions to policy", pce);
169: }
170: }
171:
172: /**
173: * 3.1.3.2 Translating Servlet security-role-ref Elements For each
174: * security-role-ref appearing in the deployment descriptor a corresponding
175: * WebRoleRefPermission must be added to the corresponding role. The name of
176: * the WebRoleRefPermission must be the servlet-name in whose context the
177: * security-role-ref is defined. The actions of the WebRoleRefPermission
178: * must be the value of the role-name (that is the reference), appearing in
179: * the security-role-ref. The deployment tools must call the addToRole
180: * method on the PolicyConfiguration object to add the WebRoleRefPermission
181: * object resulting from the translation to the role identified in the
182: * role-link appearing in the security-role-ref. Additional
183: * WebRoleRefPermission objects must be added to the PolicyConfiguration as
184: * follows. For each servlet element in the deployment descriptor a
185: * WebRoleRefPermission must be added to each security-role whose name does
186: * not appear as the role-name in a security-role-ref within the servlet
187: * element. The name of each such WebRoleRefPermission must be the
188: * servlet-name of the corresponding servlet element. The actions (that is,
189: * reference) of each such WebRoleRefPermission must be the corresponding
190: * (non-appearing) role-name. The resulting permissions must be added to the
191: * corresponding roles by calling the addToRole method on the
192: * PolicyConfiguration object.
193: * @throws PermissionManagerException if permissions can't be set
194: */
195: protected void translateServletSecurityRoleRef()
196: throws PermissionManagerException {
197: if (webContainerDeploymentDesc == null
198: || getPolicyConfiguration() == null) {
199: throw new PermissionManagerException(
200: "PolicyConfiguration or webContainerbDeploymentDesc is null");
201: }
202:
203: Collection servlets = webContainerDeploymentDesc
204: .getServletDescList();
205:
206: // List of roles which appear as role-name in a security-role-ref
207: List rolesAppearedInSecurityRoleRef = new ArrayList();
208:
209: /*
210: * For each security-role-ref appearing in the deployment descriptor a
211: * corresponding WebRoleRefPermission must be added to the corresponding
212: * role. The name of the WebRoleRefPermission must be the servlet-name
213: * in whose context the security-role-ref is defined. The actions of the
214: * WebRoleRefPermission must be the value of the role-name (that is the
215: * reference), appearing in the security-role-ref
216: */
217: ServletDesc servletDesc = null;
218: String servletName = null;
219: List roleRefs = null;
220: SecurityRoleRefDesc securityRoleRefDesc = null;
221: for (Iterator itServlet = servlets.iterator(); itServlet
222: .hasNext();) {
223: servletDesc = (ServletDesc) itServlet.next();
224: roleRefs = servletDesc.getSecurityRoleRefList();
225: servletName = servletDesc.getServletName();
226: for (Iterator itRoleRef = roleRefs.iterator(); itRoleRef
227: .hasNext();) {
228: securityRoleRefDesc = (SecurityRoleRefDesc) itRoleRef
229: .next();
230: /*
231: * The deployment tools must call the addToRole method on the
232: * PolicyConfiguration object to add the WebRoleRefPermission
233: * object resulting from the translation to the role identified
234: * in the role-link appearing in the security-role-ref.
235: */
236: Permission webRoleRefPermission = securityRoleRefDesc
237: .getWebRoleRefPermission();
238:
239: // Role has appear
240: rolesAppearedInSecurityRoleRef.add(securityRoleRefDesc
241: .getRoleName());
242:
243: try {
244: getPolicyConfiguration().addToRole(
245: securityRoleRefDesc.getRoleLink(),
246: webRoleRefPermission);
247: } catch (PolicyContextException pce) {
248: throw new PermissionManagerException(
249: "Can not add add permission '"
250: + webRoleRefPermission
251: + "' to policy", pce);
252: }
253: }
254: }
255:
256: /*
257: * Additional WebRoleRefPermission objects must be added to the
258: * PolicyConfiguration as follows. For each servlet element in the
259: * deployment descriptor a WebRoleRefPermission must be added to each
260: * security-role whose name does not appear as the role-name in a
261: * security-role-ref within the servlet element.
262: */
263: List securityRoles = webContainerDeploymentDesc
264: .getSecurityRoleList();
265: SecurityRoleDesc securityRoleDesc = null;
266: String securityRoleName = null;
267:
268: for (Iterator itServlet = servlets.iterator(); itServlet
269: .hasNext();) {
270: servletDesc = (ServletDesc) itServlet.next();
271: servletName = servletDesc.getServletName();
272:
273: for (Iterator itSecurityRoles = securityRoles.iterator(); itSecurityRoles
274: .hasNext();) {
275: securityRoleDesc = (SecurityRoleDesc) itSecurityRoles
276: .next();
277: securityRoleName = securityRoleDesc.getRoleName();
278: // if role does not appear as the role-name in a
279: // security-role-ref
280: // need to create permission
281: if (!rolesAppearedInSecurityRoleRef
282: .contains(securityRoleName)) {
283:
284: /*
285: * The name of each such WebRoleRefPermission must be the
286: * servlet-name of the corresponding servlet element. The
287: * actions (that is, reference) of each such
288: * WebRoleRefPermission must be the corresponding
289: * (non-appearing) role-name. The resulting permissions must
290: * be added to the corresponding roles by calling the
291: * addToRole method on the PolicyConfiguration object.
292: */
293: Permission webRoleRefPermission = new WebRoleRefPermission(
294: servletName, securityRoleName);
295: try {
296: getPolicyConfiguration().addToRole(
297: securityRoleName, webRoleRefPermission);
298: } catch (PolicyContextException pce) {
299: throw new PermissionManagerException(
300: "Can not add add permission '"
301: + webRoleRefPermission
302: + "' to policy", pce);
303: }
304: }
305: }
306: }
307:
308: /**
309: * For resolution B19 added for maintenance review, WebRoleRefPermission
310: * must be added with empty strings for every security role
311: */
312: securityRoles = webContainerDeploymentDesc
313: .getSecurityRoleList();
314: for (Iterator itSecurityRoles = securityRoles.iterator(); itSecurityRoles
315: .hasNext();) {
316: securityRoleDesc = (SecurityRoleDesc) itSecurityRoles
317: .next();
318: securityRoleName = securityRoleDesc.getRoleName();
319: /**
320: * Add permission with empty name
321: * B19 resolution
322: */
323: Permission webRoleRefPermission = new WebRoleRefPermission(
324: "", securityRoleName);
325: try {
326: getPolicyConfiguration().addToRole(securityRoleName,
327: webRoleRefPermission);
328: } catch (PolicyContextException pce) {
329: throw new PermissionManagerException(
330: "Can not add add permission '"
331: + webRoleRefPermission + "' to policy",
332: pce);
333: }
334: }
335: }
336:
337: /**
338: * Check the security for a given HttpServletReauest
339: * @param request the http servlet request
340: * @param principalName name of the principal
341: * @param roles array of roles for this permission
342: * @return true if the permission is granted, else false
343: */
344: public boolean checkWebUserDataPermission(
345: HttpServletRequest request, String principalName,
346: String[] roles) {
347:
348: try {
349: ProtectionDomain protectionDomain = initPolicyContext(
350: request, principalName, roles);
351:
352: //TODO : cache request to avoid creation of a new
353: // WebUserDatapermission each time
354: // See JACC 4.12
355: WebUserDataPermission webUserDataPermission = new WebUserDataPermission(
356: request);
357: boolean accessOK = getPolicy().implies(protectionDomain,
358: webUserDataPermission);
359:
360: if (logger.isLoggable(BasicLevel.DEBUG)) {
361: logger.log(BasicLevel.DEBUG, "Policy.implies result = "
362: + accessOK);
363: }
364: return accessOK;
365:
366: } catch (Exception e) {
367: logger.log(BasicLevel.ERROR,
368: "Can't check web user data permission :"
369: + e.getMessage());
370: return false;
371: }
372:
373: }
374:
375: /**
376: * Check the security for a given HttpServletReauest
377: * @param request the http servlet request
378: * @param principalName name of the principal
379: * @param roles array of roles for this permission
380: * @return true if the permission is granted, else false
381: */
382: public boolean checkWebResourcePermission(
383: HttpServletRequest request, String principalName,
384: String[] roles) {
385: try {
386: ProtectionDomain protectionDomain = initPolicyContext(
387: request, principalName, roles);
388:
389: //TODO : cache request to avoid creation of a new
390: // WebResourcePermission each time
391: // See JACC 4.12
392: WebResourcePermission webResourcePermission = new WebResourcePermission(
393: request);
394: boolean accessOK = getPolicy().implies(protectionDomain,
395: webResourcePermission);
396: if (logger.isLoggable(BasicLevel.DEBUG)) {
397: logger.log(BasicLevel.DEBUG, "Policy.implies result = "
398: + accessOK);
399: }
400: return accessOK;
401:
402: } catch (Exception e) {
403: logger.log(BasicLevel.ERROR,
404: "Can't check web resource permission :"
405: + e.getMessage());
406: return false;
407: }
408:
409: }
410:
411: /**
412: * Check the security for a given HttpServletReauest
413: * @param request the http servlet request
414: * @param servletName Name of the servlet
415: * @param principalName name of the principal
416: * @param roles array of roles for this permission
417: * @param roleName name of the role
418: * @return true if the permission is granted, else false
419: */
420: public boolean checkWebRoleRefPermission(
421: HttpServletRequest request, String servletName,
422: String principalName, String[] roles, String roleName) {
423: try {
424:
425: ProtectionDomain protectionDomain = initPolicyContext(
426: request, principalName, roles);
427:
428: //TODO : cache request to avoid creation of a new
429: // WebRoleRefPermission each time
430: // See JACC 4.12
431: WebRoleRefPermission webRoleRefPermission = new WebRoleRefPermission(
432: servletName, roleName);
433: boolean accessOK = getPolicy().implies(protectionDomain,
434: webRoleRefPermission);
435: if (logger.isLoggable(BasicLevel.DEBUG)) {
436: logger.log(BasicLevel.DEBUG, "Policy.implies result = "
437: + accessOK);
438: }
439: return accessOK;
440:
441: } catch (Exception e) {
442: logger.log(BasicLevel.ERROR,
443: "Can't check web role ref permission :"
444: + e.getMessage());
445: return false;
446: }
447:
448: }
449:
450: /**
451: * Init the PolicyContext and return a protectionDomain
452: * @param request the http servlet request
453: * @param principalName name of the principal
454: * @param roles array of roles for this permission
455: * @return the protection domain built with given arguments
456: * @throws URISyntaxException if the URI can't be built
457: * @throws MalformedURLException if the URL of the codesource can't be built
458: */
459: private synchronized ProtectionDomain initPolicyContext(
460: HttpServletRequest request, String principalName,
461: String[] roles) throws URISyntaxException,
462: MalformedURLException {
463:
464: // Set the policy context
465: PolicyContext.setContextID(getContextId());
466:
467: // Configure ContextHandler
468: JPolicyContextHandlerData jPolicyContextHandlerData = JPolicyContextHandlerCurrent
469: .getCurrent().getJPolicyContextHandlerData();
470: if (jPolicyContextHandlerData == null) {
471: logger.log(BasicLevel.ERROR,
472: "The Handler data retrieved is null !");
473: return null;
474: }
475: jPolicyContextHandlerData.setHttpServletRequest(request);
476: PolicyContext.setHandlerData(jPolicyContextHandlerData);
477:
478: // Build Protection Domain with a codesource and array of principal
479: URI uri = new URI("file://" + getContextId());
480: CodeSource codesource = new CodeSource(new URL(uri.toString()),
481: (Certificate[]) null);
482:
483: // Existing mapping ?
484: String[] overridedRoles = JPolicyUserRoleMapping
485: .getMappingForPrincipal(getContextId(), principalName);
486: if (overridedRoles != null) {
487: roles = overridedRoles;
488: }
489:
490: Principal[] principals = null;
491: if (roles != null) {
492: principals = new Principal[roles.length];
493: for (int k = 0; k < roles.length; k++) {
494: principals[k] = new org.objectweb.jonas.security.auth.JPrincipal(
495: roles[k]);
496: }
497: }
498:
499: return new ProtectionDomain(codesource, null, null, principals);
500: }
501:
502: /**
503: * Reset Deployment Descriptor
504: */
505: protected void resetDeploymentDesc() {
506: webContainerDeploymentDesc = null;
507: }
508:
509: }
|