/*
* Javolution - Java(TM) Solution for Real-Time and Embedded Systems
* Copyright (C) 2007 - Javolution (http://javolution.org/)
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software is
* freely granted, provided that this notice is preserved.
*/
package javolution.context;
import javolution.osgi.internal.OSGiServices;
/**
* <p> A high-level security context integrated with OSGi.</p>
*
* <p> When granting/revoking permission the order is important.
* For example, the following code revokes all configurable permissions
* except for setting the concurrency level.
* [code]
* SecurityContext ctx = SecurityContext.enter();
* try {
* ctx.revoke(Configurable.RECONFIGURE_PERMISSION);
* ctx.grant(ConcurrentContext.CONCURRENCY.getReconfigurePermission());
* ...
* ConcurrentContext.CONCURRENCY.reconfigure(0); // Ok (permission specifically granted).
* ...
* } finally {
* ctx.exit(); // Back to previous security settings.
* }[/code]</p>
*
* @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
* @version 6.0, July 21, 2013
*/
public abstract class SecurityContext extends AbstractContext {
/**
* A permission associated to a specific class/action/instance.
* There are three levels of permission possible, at
* the class/category level, at the action level and at the instance level.
* Any permission granted/revoked at the higher level is explicitly
* granted/revoked at the lower level. The order in which the permission
* are granted/revoked is important. For example, it is possible to grant
* a permission at the class level, then to revoke it at the action or
* instance level. In which case, for that class the permission is granted
* for all actions/instances except for those actions/instances for which the
* permission has been explicitly revoked.
*/
public static class Permission<T> {
/**
* Holds the global permission for anything.
*/
public static final Permission<Object> ALL = new Permission<Object>(
null);
private final Class<? super T> category;
private final String action;
private final T instance;
/**
* Creates a security permission for all actions of the specified category.
*/
public Permission(Class<? super T> category) {
this(category, null, null);
}
/**
* Creates a security permission for the specified action of the
* specified category.
*/
public Permission(Class<? super T> category, String action) {
this(category, action, null);
}
/**
* Creates a security permission for the specified instance and the
* specified action of the specified category.
*/
public Permission(Class<? super T> category, String action, T instance) {
this.category = category;
this.action = action;
this.instance = instance;
}
/**
* Returns the permission category or <code>null</code> for all categories.
*/
public Class<? super T> getCategory() {
return category;
}
/**
* Returns the permission action or <code>null</code> for all actions.
*/
public String getAction() {
return action;
}
/**
* Returns the permission instance or <code>null</code> for all instances.
*/
public T getInstance() {
return instance;
}
/**
* Checks if the specified permission is automatically granted/revoked
* by 'this' permission being granted/revoked.
*
* @param that the permission to check.
* @return <code>true</code> if this permission being granted/revoked
* implies that the specified permission is granted/revoked;
* <code>false</code> otherwise.
*/
public boolean implies(Permission<?> that) {
if (category == null)
return true;
if (!category.isAssignableFrom(that.category))
return false;
if (action == null)
return true;
if (!action.equals(that.action))
return false;
if (instance == null)
return true;
if (!instance.equals(that.instance))
return false;
return true;
}
@Override
public String toString() {
if (category == null)
return "All permissions";
if (action == null)
return "Permission for any action on " + category.getName();
if (instance == null)
return "Permission for " + action + " on " + category.getName();
return "Permission for " + action + " on instance " + instance
+ " of " + category.getName();
}
@Override
public boolean equals(Object obj) {
if (obj == this)
return true;
if (!(obj instanceof Permission))
return false;
Permission<?> that = (Permission<?>) obj;
if ((category == null) && (that.category != null))
return false;
if ((category != null) && (!category.equals(that.category)))
return false;
if ((action == null) && (that.action != null))
return false;
if ((action != null) && (!action.equals(that.action)))
return false;
if ((instance == null) && (that.instance != null))
return false;
if ((instance != null) && (!instance.equals(that.instance)))
return false;
return false;
}
@Override
public int hashCode() {
return (category != null ? category.hashCode() : 0)
+ (action != null ? action.hashCode() : 0)
+ (instance != null ? instance.hashCode() : 0);
}
}
/**
* Default constructor.
*/
protected SecurityContext() {}
/**
* Enters and returns a new security context instance.
*
* @return the new security context implementation entered.
*/
public static SecurityContext enter() {
return (SecurityContext) currentSecurityContext().enterInner();
}
/**
* Checks if the specified permission is granted.
*
* @param permission the permission to check.
* @throws SecurityException if the specified permission is not granted.
*/
public static void check(Permission<?> permission) {
if (!currentSecurityContext().isGranted(permission))
throw new SecurityException(permission + " is not granted.");
}
/**
* Indicates if the specified permission is granted.
*
* @param permission the permission to check.
*/
public abstract boolean isGranted(Permission<?> permission);
/**
* Grants the specified permission.
*
* @param permission the permission to grant.
* @param certificate the certificate used to grant that permission or
* <code>null</code> if none.
* @throws SecurityException if the specified permission cannot be granted.
*/
public abstract void grant(Permission<?> permission, Object certificate);
/**
* Revokes the specified permission.
*
* @param permission the permission to grant.
* @param certificate the certificate used to grant that permission or
* <code>null</code> if none.
* @throws SecurityException if the specified permission cannot be revoked.
*/
public abstract void revoke(Permission<?> permission, Object certificate);
/**
* Grants the specified permission (convenience method).
*
* @param permission the permission to grant.
* @throws SecurityException if the specified permission cannot be granted.
*/
public final void grant(Permission<?> permission) {
grant(permission, null);
}
/**
* Revokes the specified permission (convenience method).
*
* @param permission the permission to grant.
* @throws SecurityException if the specified permission cannot be revoked.
*/
public final void revoke(Permission<?> permission) {
revoke(permission, null);
}
/**
* Returns the current security context.
*/
private static SecurityContext currentSecurityContext() {
SecurityContext ctx = current(SecurityContext.class);
if (ctx != null)
return ctx;
return OSGiServices.getSecurityContext();
}
}