001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.jetspeed.security.impl;
018:
019: import java.lang.reflect.Constructor;
020: import java.security.AccessController;
021: import java.security.Permission;
022: import java.security.Permissions;
023: import java.security.Principal;
024: import java.security.PrivilegedAction;
025: import java.sql.Timestamp;
026: import java.util.ArrayList;
027: import java.util.Collection;
028: import java.util.HashMap;
029: import java.util.HashSet;
030: import java.util.Iterator;
031: import java.util.LinkedList;
032:
033: import javax.security.auth.Subject;
034:
035: import org.apache.commons.logging.Log;
036: import org.apache.commons.logging.LogFactory;
037: import org.apache.jetspeed.i18n.KeyedMessage;
038: import org.apache.jetspeed.security.JSSubject;
039: import org.apache.jetspeed.security.PermissionManager;
040: import org.apache.jetspeed.security.RolePrincipal;
041: import org.apache.jetspeed.security.SecurityException;
042: import org.apache.jetspeed.security.SecurityHelper;
043: import org.apache.jetspeed.security.UserPrincipal;
044: import org.apache.jetspeed.security.om.InternalPermission;
045: import org.apache.jetspeed.security.om.InternalPrincipal;
046: import org.apache.jetspeed.security.om.impl.InternalPermissionImpl;
047: import org.apache.jetspeed.security.om.impl.InternalPrincipalImpl;
048: import org.apache.jetspeed.util.ArgUtil;
049: import org.apache.ojb.broker.query.Criteria;
050: import org.apache.ojb.broker.query.Query;
051: import org.apache.ojb.broker.query.QueryByCriteria;
052: import org.apache.ojb.broker.query.QueryFactory;
053: import org.springframework.orm.ojb.support.PersistenceBrokerDaoSupport;
054:
055: /**
056: * <p>
057: * Implementation for managing {@link Permission}and permission association to
058: * {@link Principal}. Permissions are used to manage Principals access
059: * entitlement on specified resources.
060: * </p>
061: * <p>
062: * For instance:
063: * </p>
064: *
065: * <pre><code>
066: *
067: *
068: * grant principal o.a.j.security.UserPrincipal "theUserPrincipal"
069: * {
070: * permission o.a.j.security.PortletPermission "myportlet", "view,edit,minimize,maximize";
071: * };
072: *
073: *
074: * </code>
075: *
076: * <pre>
077: * @author <a href="mailto:dlestrat@apache.org">David Le Strat</a>
078: *
079: *
080: */
081: public class PermissionManagerImpl extends PersistenceBrokerDaoSupport
082: implements PermissionManager {
083: private static final Log log = LogFactory
084: .getLog(PermissionManagerImpl.class);
085: private static ThreadLocal permissionsCache = new ThreadLocal();
086:
087: /**
088: * @see org.apache.jetspeed.security.PermissionManager#getPermissions(java.security.Principal)
089: */
090: public Permissions getPermissions(Principal principal) {
091: String fullPath = SecurityHelper
092: .getPreferencesFullPath(principal);
093: ArgUtil.notNull(new Object[] { fullPath },
094: new String[] { "fullPath" },
095: "removePermission(java.security.Principal)");
096:
097: HashMap permissionsMap = (HashMap) permissionsCache.get();
098: if (permissionsMap == null) {
099: permissionsMap = new HashMap();
100: permissionsCache.set(permissionsMap);
101: }
102: HashSet principalPermissions = (HashSet) permissionsMap
103: .get(fullPath);
104: if (principalPermissions == null) {
105: InternalPrincipal internalPrincipal = getInternalPrincipal(fullPath);
106: if (null != internalPrincipal) {
107: principalPermissions = getSecurityPermissions(internalPrincipal
108: .getPermissions());
109: }
110: if (principalPermissions == null) {
111: principalPermissions = new HashSet();
112: }
113: permissionsMap.put(fullPath, principalPermissions);
114: }
115:
116: Permissions permissions = new Permissions();
117: Iterator iter = principalPermissions.iterator();
118: while (iter.hasNext()) {
119: permissions.add((Permission) iter.next());
120: }
121:
122: return permissions;
123: }
124:
125: /**
126: * @see org.apache.jetspeed.security.PermissionManager#getPermissions(java.util.Collection)
127: */
128: public Permissions getPermissions(Collection principals) {
129: ArgUtil.notNull(new Object[] { principals },
130: new String[] { "principals" },
131: "getPermissions(java.util.Collection)");
132:
133: Permissions permissions = new Permissions();
134: Collection principalsFullPath = getPrincipalsFullPath(principals);
135: if ((null != principalsFullPath)
136: && principalsFullPath.size() > 0) {
137: HashSet permissionsSet = new HashSet();
138: HashMap permissionsMap = (HashMap) permissionsCache.get();
139: if (permissionsMap == null) {
140: permissionsMap = new HashMap();
141: permissionsCache.set(permissionsMap);
142: }
143:
144: Iterator iter = principalsFullPath.iterator();
145: HashSet principalPermissions;
146: while (iter.hasNext()) {
147: principalPermissions = (HashSet) permissionsMap
148: .get(iter.next());
149: if (principalPermissions != null) {
150: iter.remove();
151: permissionsSet.addAll(principalPermissions);
152: }
153: }
154: if (principalsFullPath.size() > 0) {
155: Criteria filter = new Criteria();
156: filter.addIn("fullPath", principalsFullPath);
157: Query query = QueryFactory.newQuery(
158: InternalPrincipalImpl.class, filter);
159: Collection internalPrincipals = getPersistenceBrokerTemplate()
160: .getCollectionByQuery(query);
161: Iterator internalPrincipalsIter = internalPrincipals
162: .iterator();
163: while (internalPrincipalsIter.hasNext()) {
164: InternalPrincipal internalPrincipal = (InternalPrincipal) internalPrincipalsIter
165: .next();
166: Collection internalPermissions = internalPrincipal
167: .getPermissions();
168: if (null != internalPermissions) {
169: principalPermissions = getSecurityPermissions(internalPermissions);
170: permissionsSet.addAll(principalPermissions);
171: } else {
172: principalPermissions = new HashSet();
173: }
174: permissionsMap.put(internalPrincipal.getFullPath(),
175: principalPermissions);
176: }
177: }
178: iter = permissionsSet.iterator();
179: while (iter.hasNext()) {
180: permissions.add((Permission) iter.next());
181: }
182: }
183: return permissions;
184: }
185:
186: /**
187: * <p>
188: * Get the full path for the {@link Principal}in the collection.
189: * </p>
190: *
191: * @param principals The collection of principals.
192: * @return The collection of principals names.
193: */
194: private Collection getPrincipalsFullPath(Collection principals) {
195: Collection principalsFullPath = new ArrayList();
196: Iterator principalsIterator = principals.iterator();
197: while (principalsIterator.hasNext()) {
198: Principal principal = (Principal) principalsIterator.next();
199: String fullPath = SecurityHelper
200: .getPreferencesFullPath(principal);
201: if (null != fullPath) {
202: principalsFullPath.add(fullPath);
203: }
204: }
205: return principalsFullPath;
206: }
207:
208: /**
209: * <p>
210: * Iterate through a collection of {@link InternalPermission}and build a
211: * unique collection of {@link java.security.Permission}.
212: * </p>
213: *
214: * @param omPermissions The collection of {@link InternalPermission}.
215: */
216: private HashSet getSecurityPermissions(Collection omPermissions) {
217: HashSet permissions = new HashSet();
218: Iterator internalPermissionsIter = omPermissions.iterator();
219: while (internalPermissionsIter.hasNext()) {
220: InternalPermission internalPermission = (InternalPermission) internalPermissionsIter
221: .next();
222: Permission permission = null;
223: try {
224: Class permissionClass = Class
225: .forName(internalPermission.getClassname());
226: Class[] parameterTypes = { String.class, String.class };
227: Constructor permissionConstructor = permissionClass
228: .getConstructor(parameterTypes);
229: Object[] initArgs = { internalPermission.getName(),
230: internalPermission.getActions() };
231: permission = (Permission) permissionConstructor
232: .newInstance(initArgs);
233: if (permissions.add(permission)) {
234: if (log.isDebugEnabled()) {
235: log.debug("Added permimssion: [class, "
236: + permission.getClass().getName()
237: + "], " + "[name, "
238: + permission.getName() + "], "
239: + "[actions, "
240: + permission.getActions() + "]");
241: }
242: }
243: } catch (Exception e) {
244: log.error("Internal error", e);
245: }
246: }
247: return permissions;
248: }
249:
250: /**
251: * @see org.apache.jetspeed.security.PermissionManager#addPermission(java.security.Permission)
252: */
253: public void addPermission(Permission permission)
254: throws SecurityException {
255: ArgUtil.notNull(new Object[] { permission },
256: new String[] { "permission" },
257: "addPermission(java.security.Permission)");
258:
259: InternalPermission internalPermission = new InternalPermissionImpl(
260: permission.getClass().getName(), permission.getName(),
261: permission.getActions());
262: try {
263: getPersistenceBrokerTemplate().store(internalPermission);
264: } catch (Exception e) {
265: KeyedMessage msg = SecurityException.UNEXPECTED.create(
266: "PermissionManager.addPermission", "store", e
267: .getMessage());
268: logger.error(msg, e);
269: throw new SecurityException(msg, e);
270: }
271: }
272:
273: /**
274: * @see org.apache.jetspeed.security.PermissionManager#removePermission(java.security.Permission)
275: */
276: public void removePermission(Permission permission)
277: throws SecurityException {
278: ArgUtil.notNull(new Object[] { permission },
279: new String[] { "permission" },
280: "removePermission(java.security.Permission)");
281:
282: InternalPermission internalPermission = getInternalPermission(permission);
283: if (null != internalPermission) {
284: // clear the whole ThreadLocal permissions cache
285: permissionsCache.set(null);
286: try {
287: // Remove permission.
288: getPersistenceBrokerTemplate().delete(
289: internalPermission);
290: } catch (Exception e) {
291: KeyedMessage msg = SecurityException.UNEXPECTED.create(
292: "PermissionManager.removePermission", "delete",
293: e.getMessage());
294: logger.error(msg, e);
295: throw new SecurityException(msg, e);
296: }
297: }
298: }
299:
300: /**
301: * @see org.apache.jetspeed.security.PermissionManager#removePermissions(java.security.Principal)
302: */
303: public void removePermissions(Principal principal)
304: throws SecurityException {
305: String fullPath = SecurityHelper
306: .getPreferencesFullPath(principal);
307: ArgUtil.notNull(new Object[] { fullPath },
308: new String[] { "fullPath" },
309: "removePermission(java.security.Principal)");
310:
311: // Remove permissions on principal.
312: InternalPrincipal internalPrincipal = getInternalPrincipal(fullPath);
313: if (null != internalPrincipal) {
314: Collection internalPermissions = internalPrincipal
315: .getPermissions();
316: if (null != internalPermissions) {
317: internalPermissions.clear();
318: }
319: // clear the whole ThreadLocal permissions cache
320: permissionsCache.set(null);
321: try {
322: internalPrincipal.setModifiedDate(new Timestamp(System
323: .currentTimeMillis()));
324: internalPrincipal.setPermissions(internalPermissions);
325:
326: getPersistenceBrokerTemplate().store(internalPrincipal);
327: } catch (Exception e) {
328: KeyedMessage msg = SecurityException.UNEXPECTED.create(
329: "PermissionManager.removePermissions", "store",
330: e.getMessage());
331: logger.error(msg, e);
332: throw new SecurityException(msg, e);
333: }
334: }
335: }
336:
337: /**
338: * @see org.apache.jetspeed.security.PermissionManager#grantPermission(java.security.Principal,
339: * java.security.Permission)
340: */
341: public void grantPermission(Principal principal,
342: Permission permission) throws SecurityException {
343: String fullPath = SecurityHelper
344: .getPreferencesFullPath(principal);
345: ArgUtil
346: .notNull(new Object[] { fullPath, permission },
347: new String[] { "fullPath", "permission" },
348: "grantPermission(java.security.Principal, java.security.Permission)");
349:
350: Collection internalPermissions = new ArrayList();
351:
352: InternalPrincipal internalPrincipal = getInternalPrincipal(fullPath);
353: if (null == internalPrincipal) {
354: if (principal instanceof UserPrincipal) {
355: throw new SecurityException(
356: SecurityException.USER_DOES_NOT_EXIST
357: .create(principal.getName()));
358: } else if (principal instanceof RolePrincipal) {
359: throw new SecurityException(
360: SecurityException.ROLE_DOES_NOT_EXIST
361: .create(principal.getName()));
362: }
363: // must/should be GroupPrincipal
364: throw new SecurityException(
365: SecurityException.GROUP_DOES_NOT_EXIST
366: .create(principal.getName()));
367: }
368: InternalPermission internalPermission = getInternalPermission(permission);
369: if (null == internalPermission) {
370: throw new SecurityException(
371: SecurityException.PERMISSION_DOES_NOT_EXIST
372: .create(permission.getName()));
373: }
374:
375: if (null != internalPrincipal.getPermissions()) {
376: internalPermissions.addAll(internalPrincipal
377: .getPermissions());
378: }
379: if (!internalPermissions.contains(internalPermission)) {
380: internalPermissions.add(internalPermission);
381: }
382: // clear the whole ThreadLocal permissions cache
383: permissionsCache.set(null);
384: try {
385: internalPrincipal.setModifiedDate(new Timestamp(System
386: .currentTimeMillis()));
387: internalPrincipal.setPermissions(internalPermissions);
388:
389: getPersistenceBrokerTemplate().store(internalPrincipal);
390: } catch (Exception e) {
391: KeyedMessage msg = SecurityException.UNEXPECTED.create(
392: "PermissionManager.grantPermission", "store", e
393: .getMessage());
394: logger.error(msg, e);
395: throw new SecurityException(msg, e);
396: }
397: }
398:
399: /**
400: * @see org.apache.jetspeed.security.PermissionManager#permissionExists(java.security.Permission)
401: */
402: public boolean permissionExists(Permission permission) {
403: boolean permissionExists = true;
404: InternalPermission internalPermission = getInternalPermission(permission);
405: if (null == internalPermission) {
406: permissionExists = false;
407: }
408: return permissionExists;
409: }
410:
411: /**
412: * @see org.apache.jetspeed.security.PermissionManager#revokePermission(java.security.Principal,
413: * java.security.Permission)
414: */
415: public void revokePermission(Principal principal,
416: Permission permission) throws SecurityException {
417: String fullPath = SecurityHelper
418: .getPreferencesFullPath(principal);
419: ArgUtil
420: .notNull(new Object[] { fullPath, permission },
421: new String[] { "fullPath", "permission" },
422: "revokePermission(java.security.Principal, java.security.Permission)");
423:
424: // Remove permissions on principal.
425: InternalPrincipal internalPrincipal = getInternalPrincipal(fullPath);
426: if (null != internalPrincipal) {
427: Collection internalPermissions = internalPrincipal
428: .getPermissions();
429: if (null != internalPermissions) {
430: boolean revokePermission = false;
431: ArrayList newInternalPermissions = new ArrayList();
432: Iterator internalPermissionsIter = internalPermissions
433: .iterator();
434: while (internalPermissionsIter.hasNext()) {
435: InternalPermission internalPermission = (InternalPermission) internalPermissionsIter
436: .next();
437: if (!((internalPermission.getClassname()
438: .equals(permission.getClass().getName()))
439: && (internalPermission.getName()
440: .equals(permission.getName())) && (internalPermission
441: .getActions().equals(permission
442: .getActions())))) {
443: newInternalPermissions.add(internalPermission);
444: } else {
445: revokePermission = true;
446: }
447: }
448: if (revokePermission) {
449: // clear the whole ThreadLocal permissions cache
450: permissionsCache.set(null);
451: try {
452: internalPrincipal
453: .setModifiedDate(new Timestamp(System
454: .currentTimeMillis()));
455: internalPrincipal
456: .setPermissions(newInternalPermissions);
457:
458: getPersistenceBrokerTemplate().store(
459: internalPrincipal);
460: } catch (Exception e) {
461: KeyedMessage msg = SecurityException.UNEXPECTED
462: .create(
463: "PermissionManager.revokePermission",
464: "store", e.getMessage());
465: logger.error(msg, e);
466: throw new SecurityException(msg, e);
467: }
468: }
469: }
470: }
471: }
472:
473: /**
474: * <p>
475: * Returns the {@link InternalPrincipal}from the full path.
476: * </p>
477: *
478: * @param fullPath The full path.
479: * @return The {@link InternalPrincipal}.
480: */
481: InternalPrincipal getInternalPrincipal(String fullPath) {
482: Criteria filter = new Criteria();
483: filter.addEqualTo("fullPath", fullPath);
484: Query query = QueryFactory.newQuery(
485: InternalPrincipalImpl.class, filter);
486: InternalPrincipal internalPrincipal = (InternalPrincipal) getPersistenceBrokerTemplate()
487: .getObjectByQuery(query);
488: return internalPrincipal;
489: }
490:
491: /**
492: * <p>
493: * Returns the {@link InternalPermission} from a Permission.
494: * </p>
495: *
496: * @param permission The permission.
497: * @return The {@link InternalPermission}.
498: */
499: InternalPermission getInternalPermission(Permission permission) {
500: Criteria filter = new Criteria();
501: filter.addEqualTo("classname", permission.getClass().getName());
502: filter.addEqualTo("name", permission.getName());
503: filter.addEqualTo("actions", permission.getActions());
504: Query query = QueryFactory.newQuery(
505: InternalPermissionImpl.class, filter);
506: InternalPermission internalPermission = (InternalPermission) getPersistenceBrokerTemplate()
507: .getObjectByQuery(query);
508: return internalPermission;
509: }
510:
511: public boolean checkPermission(Subject subject,
512: final Permission permission) {
513: try {
514: //JSSubject.doAs(subject, new PrivilegedAction()
515: JSSubject.doAsPrivileged(subject, new PrivilegedAction() {
516: public Object run() {
517: AccessController.checkPermission(permission);
518: return null;
519: }
520: }, null);
521: } catch (Exception e) {
522: return false;
523: }
524: return true;
525: }
526:
527: public Collection getPermissions() {
528: QueryByCriteria query = QueryFactory.newQuery(
529: InternalPermissionImpl.class, new Criteria());
530: query.addOrderByAscending("classname");
531: query.addOrderByAscending("name");
532: Collection internalPermissions = getPersistenceBrokerTemplate()
533: .getCollectionByQuery(query);
534: return internalPermissions;
535: }
536:
537: public Permissions getPermissions(String classname, String resource) {
538: Criteria filter = new Criteria();
539: filter.addEqualTo("classname", classname);
540: filter.addEqualTo("name", resource);
541: Query query = QueryFactory.newQuery(
542: InternalPermissionImpl.class, filter);
543: Collection internalPermissions = getPersistenceBrokerTemplate()
544: .getCollectionByQuery(query);
545: Permissions permissions = new Permissions();
546: Iterator iter = internalPermissions.iterator();
547: try {
548: while (iter.hasNext()) {
549: InternalPermission internalPermission = (InternalPermission) iter
550: .next();
551: Class permissionClass = Class
552: .forName(internalPermission.getClassname());
553: Class[] parameterTypes = { String.class, String.class };
554: Constructor permissionConstructor = permissionClass
555: .getConstructor(parameterTypes);
556: Object[] initArgs = { internalPermission.getName(),
557: internalPermission.getActions() };
558: Permission permission = (Permission) permissionConstructor
559: .newInstance(initArgs);
560: permissions.add(permission);
561: }
562: } catch (Exception e) {
563: logger.error("Failed to retrieve permissions", e);
564: }
565: return permissions;
566: }
567:
568: public int updatePermission(Permission permission,
569: Collection principals) throws SecurityException {
570: int count = 0;
571: InternalPermission internal = getInternalPermission(permission);
572: Iterator iter = principals.iterator();
573: Collection newPrincipals = new LinkedList();
574: while (iter.hasNext()) {
575: Principal principal = (Principal) iter.next();
576: String fullPath = SecurityHelper
577: .getPreferencesFullPath(principal);
578: InternalPrincipal internalPrincipal = getInternalPrincipal(fullPath);
579: newPrincipals.add(internalPrincipal);
580: }
581: internal.setPrincipals(newPrincipals);
582: internal.setModifiedDate(new Timestamp(System
583: .currentTimeMillis()));
584: try {
585: getPersistenceBrokerTemplate().store(internal);
586: } catch (Exception e) {
587: KeyedMessage msg = SecurityException.UNEXPECTED.create(
588: "PermissionManager.updatePermission", "store", e
589: .getMessage());
590: logger.error(msg, e);
591: throw new SecurityException(msg, e);
592: }
593:
594: return count;
595: }
596:
597: public Collection getPrincipals(Permission permission) {
598: Collection result = new LinkedList();
599: InternalPermission internalPermission = this
600: .getInternalPermission(permission);
601: if (internalPermission == null) {
602: return result;
603: }
604: Iterator principals = internalPermission.getPrincipals()
605: .iterator();
606: while (principals.hasNext()) {
607: InternalPrincipal internalPrincipal = (InternalPrincipal) principals
608: .next();
609: Principal principal = SecurityHelper
610: .createPrincipalFromFullPath(internalPrincipal
611: .getFullPath());
612: result.add(principal);
613: }
614: return result;
615: }
616:
617: }
|