true
(enabled).
*/
public static final String JTA_TRACK_BY_THREAD = "hibernate.jta.track_by_thread";
+
+ public static final String JACC_CONTEXT_ID = "hibernate.jacc_context_id";
+ public static final String JACC_PREFIX = "hibernate.jacc";
+ public static final String JACC_ENABLED = "hibernate.jacc.enabled";
}
diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java b/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java
index 701d769946..c62ef69eff 100644
--- a/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java
+++ b/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java
@@ -134,7 +134,8 @@ import org.hibernate.mapping.Table;
import org.hibernate.mapping.TypeDef;
import org.hibernate.mapping.UniqueKey;
import org.hibernate.proxy.EntityNotFoundDelegate;
-import org.hibernate.secure.internal.JACCConfiguration;
+import org.hibernate.secure.spi.GrantedPermission;
+import org.hibernate.secure.spi.JaccPermissionDeclarations;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.tool.hbm2ddl.DatabaseMetadata;
import org.hibernate.tool.hbm2ddl.IndexMetadata;
@@ -2198,23 +2199,42 @@ public class Configuration implements Serializable {
}
}
+ private JaccPermissionDeclarations jaccPermissionDeclarations;
+
private void parseSecurity(Element secNode) {
- String contextId = secNode.attributeValue( "context" );
- setProperty( Environment.JACC_CONTEXTID, contextId );
- LOG.jaccContextId( contextId );
- JACCConfiguration jcfg = new JACCConfiguration( contextId );
- Iterator grantElements = secNode.elementIterator();
- while ( grantElements.hasNext() ) {
- Element grantElement = (Element) grantElements.next();
- String elementName = grantElement.getName();
- if ( "grant".equals( elementName ) ) {
- jcfg.addPermission(
- grantElement.attributeValue( "role" ),
- grantElement.attributeValue( "entity-name" ),
- grantElement.attributeValue( "actions" )
- );
+ final String nodeContextId = secNode.attributeValue( "context" );
+
+ final String explicitContextId = getProperty( AvailableSettings.JACC_CONTEXT_ID );
+ if ( explicitContextId == null ) {
+ setProperty( AvailableSettings.JACC_CONTEXT_ID, nodeContextId );
+ LOG.jaccContextId( nodeContextId );
+ }
+ else {
+ // if they dont match, throw an error
+ if ( ! nodeContextId.equals( explicitContextId ) ) {
+ throw new HibernateException( "Non-matching JACC context ids" );
}
}
+ jaccPermissionDeclarations = new JaccPermissionDeclarations( nodeContextId );
+
+ Iterator grantElements = secNode.elementIterator();
+ while ( grantElements.hasNext() ) {
+ final Element grantElement = (Element) grantElements.next();
+ final String elementName = grantElement.getName();
+ if ( "grant".equals( elementName ) ) {
+ jaccPermissionDeclarations.addPermissionDeclaration(
+ new GrantedPermission(
+ grantElement.attributeValue( "role" ),
+ grantElement.attributeValue( "entity-name" ),
+ grantElement.attributeValue( "actions" )
+ )
+ );
+ }
+ }
+ }
+
+ public JaccPermissionDeclarations getJaccPermissionDeclarations() {
+ return jaccPermissionDeclarations;
}
RootClass getRootClassMapping(String clazz) throws MappingException {
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractPreDatabaseOperationEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractPreDatabaseOperationEvent.java
index c39afd5dde..685e72c13b 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractPreDatabaseOperationEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractPreDatabaseOperationEvent.java
@@ -26,13 +26,17 @@ package org.hibernate.event.spi;
import java.io.Serializable;
import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.secure.spi.PermissionCheckEntityInformation;
/**
* Represents an operation we are about to perform against the database.
*
* @author Steve Ebersole
*/
-public abstract class AbstractPreDatabaseOperationEvent extends AbstractEvent {
+public abstract class AbstractPreDatabaseOperationEvent
+ extends AbstractEvent
+ implements PermissionCheckEntityInformation {
+
private final Object entity;
private final Serializable id;
private final EntityPersister persister;
@@ -61,6 +65,7 @@ public abstract class AbstractPreDatabaseOperationEvent extends AbstractEvent {
*
* @return The entity.
*/
+ @Override
public Object getEntity() {
return entity;
}
@@ -97,4 +102,14 @@ public abstract class AbstractPreDatabaseOperationEvent extends AbstractEvent {
public EventSource getSource() {
return getSession();
}
+
+ @Override
+ public String getEntityName() {
+ return persister.getEntityName();
+ }
+
+ @Override
+ public Serializable getIdentifier() {
+ return id;
+ }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/PreDeleteEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/PreDeleteEvent.java
index 9d4ded751a..7fae5576b9 100755
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/PreDeleteEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/PreDeleteEvent.java
@@ -26,6 +26,8 @@ package org.hibernate.event.spi;
import java.io.Serializable;
import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.secure.spi.PermissionCheckEntityInformation;
+
/**
* Represents a pre-delete event, which occurs just prior to
@@ -34,7 +36,10 @@ import org.hibernate.persister.entity.EntityPersister;
* @author Gavin King
* @author Steve Ebersole
*/
-public class PreDeleteEvent extends AbstractPreDatabaseOperationEvent {
+public class PreDeleteEvent
+ extends AbstractPreDatabaseOperationEvent
+ implements PermissionCheckEntityInformation{
+
private Object[] deletedState;
/**
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/PreLoadEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/PreLoadEvent.java
index 7d825fee87..e7b2a2e283 100755
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/PreLoadEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/PreLoadEvent.java
@@ -26,14 +26,14 @@ package org.hibernate.event.spi;
import java.io.Serializable;
import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.secure.spi.PermissionCheckEntityInformation;
/**
- * Called before injecting property values into a newly
- * loaded entity instance.
+ * Called before injecting property values into a newly loaded entity instance.
*
* @author Gavin King
*/
-public class PreLoadEvent extends AbstractEvent {
+public class PreLoadEvent extends AbstractEvent implements PermissionCheckEntityInformation {
private Object entity;
private Object[] state;
private Serializable id;
@@ -43,6 +43,7 @@ public class PreLoadEvent extends AbstractEvent {
super(session);
}
+ @Override
public Object getEntity() {
return entity;
}
@@ -78,5 +79,14 @@ public class PreLoadEvent extends AbstractEvent {
this.state = state;
return this;
}
-
+
+ @Override
+ public String getEntityName() {
+ return persister.getEntityName();
+ }
+
+ @Override
+ public Serializable getIdentifier() {
+ return id;
+ }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/integrator/internal/IntegratorServiceImpl.java b/hibernate-core/src/main/java/org/hibernate/integrator/internal/IntegratorServiceImpl.java
index b4cd7872d7..f8829a04e6 100644
--- a/hibernate-core/src/main/java/org/hibernate/integrator/internal/IntegratorServiceImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/integrator/internal/IntegratorServiceImpl.java
@@ -31,6 +31,7 @@ import org.hibernate.cfg.beanvalidation.BeanValidationIntegrator;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.integrator.spi.IntegratorService;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
+import org.hibernate.secure.spi.JaccIntegrator;
/**
* @author Steve Ebersole
@@ -44,6 +45,7 @@ public class IntegratorServiceImpl implements IntegratorService {
// register standard integrators. Envers and JPA, for example, need to be handled by discovery because in
// separate project/jars.
addIntegrator( new BeanValidationIntegrator() );
+ addIntegrator( new JaccIntegrator() );
// register provided integrators
for ( Integrator integrator : providedIntegrators ) {
diff --git a/hibernate-core/src/main/java/org/hibernate/secure/internal/AbstractJaccSecurableEventListener.java b/hibernate-core/src/main/java/org/hibernate/secure/internal/AbstractJaccSecurableEventListener.java
new file mode 100644
index 0000000000..38173b73c3
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/secure/internal/AbstractJaccSecurableEventListener.java
@@ -0,0 +1,53 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.secure.internal;
+
+import org.hibernate.engine.spi.SessionImplementor;
+import org.hibernate.event.spi.AbstractPreDatabaseOperationEvent;
+import org.hibernate.secure.spi.JaccService;
+import org.hibernate.secure.spi.PermissibleAction;
+import org.hibernate.secure.spi.PermissionCheckEntityInformation;
+
+/**
+ * Base class for JACC-securable event listeners
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractJaccSecurableEventListener implements JaccSecurityListener {
+ private JaccService jaccService;
+
+ protected void performSecurityCheck(AbstractPreDatabaseOperationEvent event, PermissibleAction action) {
+ performSecurityCheck( event.getSession(), event, action );
+ }
+
+ protected void performSecurityCheck(
+ SessionImplementor session,
+ PermissionCheckEntityInformation entityInformation,
+ PermissibleAction action) {
+ if ( jaccService == null ) {
+ jaccService = session.getFactory().getServiceRegistry().getService( JaccService.class );
+ }
+ jaccService.checkPermission( entityInformation, action );
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/secure/internal/DisabledJaccServiceImpl.java b/hibernate-core/src/main/java/org/hibernate/secure/internal/DisabledJaccServiceImpl.java
new file mode 100644
index 0000000000..29aaf8b61d
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/secure/internal/DisabledJaccServiceImpl.java
@@ -0,0 +1,48 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.secure.internal;
+
+import org.jboss.logging.Logger;
+
+import org.hibernate.secure.spi.GrantedPermission;
+import org.hibernate.secure.spi.JaccService;
+import org.hibernate.secure.spi.PermissibleAction;
+import org.hibernate.secure.spi.PermissionCheckEntityInformation;
+
+/**
+ * @author Steve Ebersole
+ */
+public class DisabledJaccServiceImpl implements JaccService {
+ private static final Logger log = Logger.getLogger( DisabledJaccServiceImpl.class );
+
+ @Override
+ public void addPermission(GrantedPermission permissionDeclaration) {
+ log.debug( "Ignoring call to addPermission on disabled JACC service" );
+ }
+
+ @Override
+ public void checkPermission(PermissionCheckEntityInformation entityInformation, PermissibleAction action) {
+ log.debug( "Ignoring call to checkPermission on disabled JACC service" );
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/secure/internal/HibernatePermission.java b/hibernate-core/src/main/java/org/hibernate/secure/internal/HibernatePermission.java
deleted file mode 100755
index 071754d679..0000000000
--- a/hibernate-core/src/main/java/org/hibernate/secure/internal/HibernatePermission.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Hibernate, Relational Persistence for Idiomatic Java
- *
- * Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
- * indicated by the @author tags or express copyright attribution
- * statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Inc.
- *
- * This copyrighted material is made available to anyone wishing to use, modify,
- * copy, or redistribute it subject to the terms and conditions of the GNU
- * Lesser General Public License, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this distribution; if not, write to:
- * Free Software Foundation, Inc.
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02110-1301 USA
- */
-package org.hibernate.secure.internal;
-
-import java.security.Permission;
-
-/**
- * @author Gavin King
- */
-public class HibernatePermission extends Permission {
- public static final String INSERT = "insert";
- public static final String UPDATE = "update";
- public static final String DELETE = "delete";
- public static final String READ = "read";
- public static final String ANY = "*";
-
- private final String actions;
-
- public HibernatePermission(String entityName, String actions) {
- super(entityName);
- this.actions = actions;
- }
-
- public boolean implies(Permission permission) {
- //TODO!
- return ( "*".equals( getName() ) || getName().equals( permission.getName() ) ) &&
- ( "*".equals(actions) || actions.indexOf( permission.getActions() ) >= 0 );
- }
-
- public boolean equals(Object obj) {
- if ( !(obj instanceof HibernatePermission) ) return false;
- HibernatePermission permission = (HibernatePermission) obj;
- return permission.getName().equals( getName() ) &&
- permission.getActions().equals(actions);
- }
-
- public int hashCode() {
- return getName().hashCode() * 37 + actions.hashCode();
- }
-
- public String getActions() {
- return actions;
- }
-
- public String toString() {
- return "HibernatePermission(" + getName() + ':' + actions + ')';
- }
-
-}
diff --git a/hibernate-core/src/main/java/org/hibernate/secure/internal/JACCConfiguration.java b/hibernate-core/src/main/java/org/hibernate/secure/internal/JACCConfiguration.java
deleted file mode 100755
index a6e2a31a83..0000000000
--- a/hibernate-core/src/main/java/org/hibernate/secure/internal/JACCConfiguration.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Hibernate, Relational Persistence for Idiomatic Java
- *
- * Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
- * indicated by the @author tags or express copyright attribution
- * statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Inc.
- *
- * This copyrighted material is made available to anyone wishing to use, modify,
- * copy, or redistribute it subject to the terms and conditions of the GNU
- * Lesser General Public License, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this distribution; if not, write to:
- * Free Software Foundation, Inc.
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02110-1301 USA
- */
-package org.hibernate.secure.internal;
-
-import java.util.StringTokenizer;
-import javax.security.jacc.EJBMethodPermission;
-import javax.security.jacc.PolicyConfiguration;
-import javax.security.jacc.PolicyConfigurationFactory;
-import javax.security.jacc.PolicyContextException;
-
-import org.jboss.logging.Logger;
-
-import org.hibernate.HibernateException;
-import org.hibernate.internal.CoreMessageLogger;
-
-/**
- * Adds Hibernate permissions to roles via JACC
- *
- * @author Gavin King
- */
-public class JACCConfiguration {
-
- private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, JACCConfiguration.class.getName());
-
- private final PolicyConfiguration policyConfiguration;
-
- public JACCConfiguration(String contextId) throws HibernateException {
- try {
- policyConfiguration = PolicyConfigurationFactory
- .getPolicyConfigurationFactory()
- .getPolicyConfiguration( contextId, false );
- }
- catch (ClassNotFoundException cnfe) {
- throw new HibernateException( "JACC provider class not found", cnfe );
- }
- catch (PolicyContextException pce) {
- throw new HibernateException( "policy context exception occurred", pce );
- }
- }
-
- public void addPermission(String role, String entityName, String action) {
-
- if ( action.equals( "*" ) ) {
- action = "insert,read,update,delete";
- }
-
- StringTokenizer tok = new StringTokenizer( action, "," );
-
- while ( tok.hasMoreTokens() ) {
- String methodName = tok.nextToken().trim();
- EJBMethodPermission permission = new EJBMethodPermission(
- entityName,
- methodName,
- null, // interfaces
- null // arguments
- );
-
- LOG.debugf("Adding permission to role %s: %s", role, permission);
- try {
- policyConfiguration.addToRole( role, permission );
- }
- catch (PolicyContextException pce) {
- throw new HibernateException( "policy context exception occurred", pce );
- }
- }
- }
-}
diff --git a/hibernate-core/src/main/java/org/hibernate/secure/internal/JACCPermissions.java b/hibernate-core/src/main/java/org/hibernate/secure/internal/JACCPermissions.java
deleted file mode 100644
index 31eb980f47..0000000000
--- a/hibernate-core/src/main/java/org/hibernate/secure/internal/JACCPermissions.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Hibernate, Relational Persistence for Idiomatic Java
- *
- * Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
- * indicated by the @author tags or express copyright attribution
- * statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Inc.
- *
- * This copyrighted material is made available to anyone wishing to use, modify,
- * copy, or redistribute it subject to the terms and conditions of the GNU
- * Lesser General Public License, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this distribution; if not, write to:
- * Free Software Foundation, Inc.
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02110-1301 USA
- */
-package org.hibernate.secure.internal;
-
-import java.lang.reflect.UndeclaredThrowableException;
-import java.security.AccessController;
-import java.security.CodeSource;
-import java.security.Policy;
-import java.security.Principal;
-import java.security.PrivilegedAction;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
-import java.security.ProtectionDomain;
-import java.util.Set;
-import javax.security.auth.Subject;
-import javax.security.jacc.EJBMethodPermission;
-import javax.security.jacc.PolicyContext;
-import javax.security.jacc.PolicyContextException;
-
-/**
- * Copied from JBoss org.jboss.ejb3.security.JaccHelper and org.jboss.ejb3.security.SecurityActions
- *
- * @author Kabir Khan
- */
-public class JACCPermissions {
-
- public static void checkPermission(Class clazz, String contextID, EJBMethodPermission methodPerm)
- throws SecurityException {
- CodeSource ejbCS = clazz.getProtectionDomain().getCodeSource();
-
- try {
- setContextID( contextID );
-
- Policy policy = Policy.getPolicy();
- // Get the caller
- Subject caller = getContextSubject();
-
- Principal[] principals = null;
- if ( caller != null ) {
- // Get the caller principals
- Set principalsSet = caller.getPrincipals();
- principals = new Principal[ principalsSet.size() ];
- principalsSet.toArray( principals );
- }
-
- ProtectionDomain pd = new ProtectionDomain( ejbCS, null, null, principals );
- if ( policy.implies( pd, methodPerm ) == false ) {
- String msg = "Denied: " + methodPerm + ", caller=" + caller;
- SecurityException e = new SecurityException( msg );
- throw e;
- }
- }
- catch (PolicyContextException e) {
- throw new RuntimeException( e );
- }
- }
-
- interface PolicyContextActions {
- /**
- * The JACC PolicyContext key for the current Subject
- */
- static final String SUBJECT_CONTEXT_KEY = "javax.security.auth.Subject.container";
- PolicyContextActions PRIVILEGED = new PolicyContextActions() {
- private final PrivilegedExceptionAction exAction = new PrivilegedExceptionAction() {
- public Object run() throws Exception {
- return PolicyContext.getContext( SUBJECT_CONTEXT_KEY );
- }
- };
-
- public Subject getContextSubject() throws PolicyContextException {
- try {
- return (Subject) AccessController.doPrivileged( exAction );
- }
- catch (PrivilegedActionException e) {
- Exception ex = e.getException();
- if ( ex instanceof PolicyContextException ) {
- throw (PolicyContextException) ex;
- }
- else {
- throw new UndeclaredThrowableException( ex );
- }
- }
- }
- };
-
- PolicyContextActions NON_PRIVILEGED = new PolicyContextActions() {
- public Subject getContextSubject() throws PolicyContextException {
- return (Subject) PolicyContext.getContext( SUBJECT_CONTEXT_KEY );
- }
- };
-
- Subject getContextSubject() throws PolicyContextException;
- }
-
- static Subject getContextSubject() throws PolicyContextException {
- if ( System.getSecurityManager() == null ) {
- return PolicyContextActions.NON_PRIVILEGED.getContextSubject();
- }
- else {
- return PolicyContextActions.PRIVILEGED.getContextSubject();
- }
- }
-
- private static class SetContextID implements PrivilegedAction {
- String contextID;
-
- SetContextID(String contextID) {
- this.contextID = contextID;
- }
-
- public Object run() {
- String previousID = PolicyContext.getContextID();
- PolicyContext.setContextID( contextID );
- return previousID;
- }
- }
-
- static String setContextID(String contextID) {
- PrivilegedAction action = new SetContextID( contextID );
- String previousID = (String) AccessController.doPrivileged( action );
- return previousID;
- }
-}
diff --git a/hibernate-core/src/main/java/org/hibernate/secure/internal/JACCPreDeleteEventListener.java b/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreDeleteEventListener.java
similarity index 72%
rename from hibernate-core/src/main/java/org/hibernate/secure/internal/JACCPreDeleteEventListener.java
rename to hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreDeleteEventListener.java
index 955842f8d9..5ad75293cd 100755
--- a/hibernate-core/src/main/java/org/hibernate/secure/internal/JACCPreDeleteEventListener.java
+++ b/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreDeleteEventListener.java
@@ -23,31 +23,22 @@
*/
package org.hibernate.secure.internal;
-import javax.security.jacc.EJBMethodPermission;
-
import org.hibernate.event.spi.PreDeleteEvent;
import org.hibernate.event.spi.PreDeleteEventListener;
+import org.hibernate.secure.spi.PermissibleAction;
/**
* Check security before any deletion
*
* @author Kabir Khan
+ * @author Steve Ebersole
*/
-public class JACCPreDeleteEventListener implements PreDeleteEventListener, JACCSecurityListener {
- private final String contextId;
-
- public JACCPreDeleteEventListener(String contextId) {
- this.contextId = contextId;
+public class JaccPreDeleteEventListener extends AbstractJaccSecurableEventListener implements PreDeleteEventListener {
+ public JaccPreDeleteEventListener() {
}
public boolean onPreDelete(PreDeleteEvent event) {
- final EJBMethodPermission deletePermission = new EJBMethodPermission(
- event.getPersister().getEntityName(),
- HibernatePermission.DELETE,
- null,
- null
- );
- JACCPermissions.checkPermission( event.getEntity().getClass(), contextId, deletePermission );
+ performSecurityCheck( event, PermissibleAction.DELETE );
return false;
}
diff --git a/hibernate-core/src/main/java/org/hibernate/secure/internal/JACCPreInsertEventListener.java b/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreInsertEventListener.java
similarity index 72%
rename from hibernate-core/src/main/java/org/hibernate/secure/internal/JACCPreInsertEventListener.java
rename to hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreInsertEventListener.java
index b05a73cfd7..6dd0babb2f 100755
--- a/hibernate-core/src/main/java/org/hibernate/secure/internal/JACCPreInsertEventListener.java
+++ b/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreInsertEventListener.java
@@ -23,31 +23,22 @@
*/
package org.hibernate.secure.internal;
-import javax.security.jacc.EJBMethodPermission;
-
import org.hibernate.event.spi.PreInsertEvent;
import org.hibernate.event.spi.PreInsertEventListener;
+import org.hibernate.secure.spi.PermissibleAction;
/**
* Check security before an insertion
*
* @author Kabir Khan
+ * @author Steve Ebersole
*/
-public class JACCPreInsertEventListener implements PreInsertEventListener, JACCSecurityListener {
- private final String contextId;
-
- public JACCPreInsertEventListener(String contextId) {
- this.contextId = contextId;
+public class JaccPreInsertEventListener extends AbstractJaccSecurableEventListener implements PreInsertEventListener {
+ public JaccPreInsertEventListener() {
}
public boolean onPreInsert(PreInsertEvent event) {
- final EJBMethodPermission insertPermission = new EJBMethodPermission(
- event.getPersister().getEntityName(),
- HibernatePermission.INSERT,
- null,
- null
- );
- JACCPermissions.checkPermission( event.getEntity().getClass(), contextId, insertPermission );
+ performSecurityCheck( event, PermissibleAction.INSERT );
return false;
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/secure/internal/JACCPreLoadEventListener.java b/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreLoadEventListener.java
similarity index 72%
rename from hibernate-core/src/main/java/org/hibernate/secure/internal/JACCPreLoadEventListener.java
rename to hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreLoadEventListener.java
index 51423314a6..492ce52680 100755
--- a/hibernate-core/src/main/java/org/hibernate/secure/internal/JACCPreLoadEventListener.java
+++ b/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreLoadEventListener.java
@@ -23,30 +23,21 @@
*/
package org.hibernate.secure.internal;
-import javax.security.jacc.EJBMethodPermission;
-
import org.hibernate.event.spi.PreLoadEvent;
import org.hibernate.event.spi.PreLoadEventListener;
+import org.hibernate.secure.spi.PermissibleAction;
/**
* Check security before any load
*
* @author Kabir Khan
+ * @author Steve Ebersole
*/
-public class JACCPreLoadEventListener implements PreLoadEventListener, JACCSecurityListener {
- private final String contextId;
-
- public JACCPreLoadEventListener(String contextId) {
- this.contextId = contextId;
+public class JaccPreLoadEventListener extends AbstractJaccSecurableEventListener implements PreLoadEventListener {
+ public JaccPreLoadEventListener() {
}
public void onPreLoad(PreLoadEvent event) {
- final EJBMethodPermission loadPermission = new EJBMethodPermission(
- event.getPersister().getEntityName(),
- HibernatePermission.READ,
- null,
- null
- );
- JACCPermissions.checkPermission( event.getEntity().getClass(), contextId, loadPermission );
+ performSecurityCheck( event.getSession(), event, PermissibleAction.READ );
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/secure/internal/JACCPreUpdateEventListener.java b/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreUpdateEventListener.java
similarity index 72%
rename from hibernate-core/src/main/java/org/hibernate/secure/internal/JACCPreUpdateEventListener.java
rename to hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreUpdateEventListener.java
index f7e9d73303..4f481266ed 100755
--- a/hibernate-core/src/main/java/org/hibernate/secure/internal/JACCPreUpdateEventListener.java
+++ b/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreUpdateEventListener.java
@@ -23,31 +23,22 @@
*/
package org.hibernate.secure.internal;
-import javax.security.jacc.EJBMethodPermission;
-
import org.hibernate.event.spi.PreUpdateEvent;
import org.hibernate.event.spi.PreUpdateEventListener;
+import org.hibernate.secure.spi.PermissibleAction;
/**
* Check security before any update
*
* @author Kabir Khan
+ * @author Steve Ebersole
*/
-public class JACCPreUpdateEventListener implements PreUpdateEventListener, JACCSecurityListener {
- private final String contextId;
-
- public JACCPreUpdateEventListener(String contextId) {
- this.contextId = contextId;
+public class JaccPreUpdateEventListener extends AbstractJaccSecurableEventListener implements PreUpdateEventListener {
+ public JaccPreUpdateEventListener() {
}
public boolean onPreUpdate(PreUpdateEvent event) {
- final EJBMethodPermission updatePermission = new EJBMethodPermission(
- event.getPersister().getEntityName(),
- HibernatePermission.UPDATE,
- null,
- null
- );
- JACCPermissions.checkPermission( event.getEntity().getClass(), contextId, updatePermission );
+ performSecurityCheck( event, PermissibleAction.UPDATE );
return false;
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/secure/internal/JACCSecurityListener.java b/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccSecurityListener.java
similarity index 84%
rename from hibernate-core/src/main/java/org/hibernate/secure/internal/JACCSecurityListener.java
rename to hibernate-core/src/main/java/org/hibernate/secure/internal/JaccSecurityListener.java
index 90b9871790..2dfe030f12 100644
--- a/hibernate-core/src/main/java/org/hibernate/secure/internal/JACCSecurityListener.java
+++ b/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccSecurityListener.java
@@ -24,9 +24,10 @@
package org.hibernate.secure.internal;
/**
- * Marker interface for JACC event listeners
+ * Marker interface for JACC event listeners. Used in event listener duplication strategy checks; see
+ * {@link org.hibernate.secure.spi.JaccIntegrator} for details.
*
* @author Kabir Khan
*/
-public interface JACCSecurityListener {
+public interface JaccSecurityListener {
}
diff --git a/hibernate-core/src/main/java/org/hibernate/secure/internal/StandardJaccServiceImpl.java b/hibernate-core/src/main/java/org/hibernate/secure/internal/StandardJaccServiceImpl.java
new file mode 100644
index 0000000000..25e173d581
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/secure/internal/StandardJaccServiceImpl.java
@@ -0,0 +1,221 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.secure.internal;
+
+import javax.security.auth.Subject;
+import javax.security.jacc.EJBMethodPermission;
+import javax.security.jacc.PolicyConfiguration;
+import javax.security.jacc.PolicyConfigurationFactory;
+import javax.security.jacc.PolicyContext;
+import javax.security.jacc.PolicyContextException;
+import java.security.AccessController;
+import java.security.CodeSource;
+import java.security.Policy;
+import java.security.Principal;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+import java.util.Map;
+import java.util.Set;
+
+import org.jboss.logging.Logger;
+
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.AvailableSettings;
+import org.hibernate.secure.spi.GrantedPermission;
+import org.hibernate.secure.spi.IntegrationException;
+import org.hibernate.secure.spi.JaccService;
+import org.hibernate.secure.spi.PermissibleAction;
+import org.hibernate.secure.spi.PermissionCheckEntityInformation;
+import org.hibernate.service.spi.Configurable;
+
+/**
+ * @author Steve Ebersole
+ */
+public class StandardJaccServiceImpl implements JaccService, Configurable {
+ private static final Logger log = Logger.getLogger( StandardJaccServiceImpl.class );
+
+ private String contextId;
+ private PolicyConfiguration policyConfiguration;
+
+ @Override
+ public void configure(Map configurationValues) {
+ this.contextId = (String) configurationValues.get( AvailableSettings.JACC_CONTEXT_ID );
+ }
+
+ @Override
+ public void addPermission(GrantedPermission permissionDeclaration) {
+ // todo : do we need to wrap these PolicyConfiguration calls in privileged actions like we do during permission checks?
+
+ if ( policyConfiguration == null ) {
+ policyConfiguration = locatePolicyConfiguration( contextId );
+ }
+
+ for ( String grantedAction : permissionDeclaration.getPermissibleAction().getImpliedActions() ) {
+ final EJBMethodPermission permission = new EJBMethodPermission(
+ permissionDeclaration.getEntityName(),
+ grantedAction,
+ null, // interfaces
+ null // arguments
+ );
+
+ log.debugf( "Adding permission [%s] to role [%s]", grantedAction, permissionDeclaration.getRole() );
+ try {
+ policyConfiguration.addToRole( permissionDeclaration.getRole(), permission );
+ }
+ catch (PolicyContextException pce) {
+ throw new HibernateException( "policy context exception occurred", pce );
+ }
+ }
+ }
+
+ private PolicyConfiguration locatePolicyConfiguration(String contextId) {
+ try {
+ return PolicyConfigurationFactory
+ .getPolicyConfigurationFactory()
+ .getPolicyConfiguration( contextId, false );
+ }
+ catch (Exception e) {
+ throw new IntegrationException( "Unable to access JACC PolicyConfiguration" );
+ }
+ }
+
+ @Override
+ public void checkPermission(PermissionCheckEntityInformation entityInformation, PermissibleAction action) {
+ if ( action == PermissibleAction.ANY ) {
+ throw new HibernateException( "ANY action (*) is not legal for permission check, only for configuration" );
+ }
+
+ final String originalContextId = AccessController.doPrivileged( new ContextIdSetAction( contextId ) );
+ try {
+ doPermissionCheckInContext( entityInformation, action );
+ }
+ finally {
+ AccessController.doPrivileged( new ContextIdSetAction( originalContextId ) );
+ }
+ }
+
+ private static class ContextIdSetAction implements PrivilegedAction- Declarative security for CRUD operations on entities. -
- - diff --git a/hibernate-core/src/main/java/org/hibernate/secure/spi/GrantedPermission.java b/hibernate-core/src/main/java/org/hibernate/secure/spi/GrantedPermission.java new file mode 100644 index 0000000000..6d4ca397cc --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/secure/spi/GrantedPermission.java @@ -0,0 +1,53 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2013, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.secure.spi; + +/** + * Describes a Hibernate (persistence) permission. + * + * @author Steve Ebersole + */ +public class GrantedPermission { + private final String role; + private final String entityName; + private final PermissibleAction action; + + public GrantedPermission(String role, String entityName, String action) { + this.role = role; + this.entityName = entityName; + this.action = PermissibleAction.interpret( action ); + } + + public String getRole() { + return role; + } + + public String getEntityName() { + return entityName; + } + + public PermissibleAction getPermissibleAction() { + return action; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/secure/spi/IntegrationException.java b/hibernate-core/src/main/java/org/hibernate/secure/spi/IntegrationException.java new file mode 100644 index 0000000000..78762bc960 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/secure/spi/IntegrationException.java @@ -0,0 +1,39 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2013, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.secure.spi; + +import org.hibernate.HibernateException; + +/** + * @author Steve Ebersole + */ +public class IntegrationException extends HibernateException { + public IntegrationException(String message) { + super( message ); + } + + public IntegrationException(String message, Throwable root) { + super( message, root ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/secure/spi/JaccIntegrator.java b/hibernate-core/src/main/java/org/hibernate/secure/spi/JaccIntegrator.java new file mode 100644 index 0000000000..44095920d4 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/secure/spi/JaccIntegrator.java @@ -0,0 +1,132 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2013, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.secure.spi; + +import java.util.Map; + +import org.jboss.logging.Logger; + +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Configuration; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.event.service.spi.DuplicationStrategy; +import org.hibernate.event.service.spi.EventListenerRegistry; +import org.hibernate.event.spi.EventType; +import org.hibernate.integrator.spi.Integrator; +import org.hibernate.integrator.spi.ServiceContributingIntegrator; +import org.hibernate.metamodel.source.MetadataImplementor; +import org.hibernate.secure.internal.DisabledJaccServiceImpl; +import org.hibernate.secure.internal.JaccPreDeleteEventListener; +import org.hibernate.secure.internal.JaccPreInsertEventListener; +import org.hibernate.secure.internal.JaccPreLoadEventListener; +import org.hibernate.secure.internal.JaccPreUpdateEventListener; +import org.hibernate.secure.internal.JaccSecurityListener; +import org.hibernate.secure.internal.StandardJaccServiceImpl; +import org.hibernate.service.spi.SessionFactoryServiceRegistry; + +/** + * Integrator for setting up JACC integration + * + * @author Steve Ebersole + */ +public class JaccIntegrator implements ServiceContributingIntegrator { + private static final Logger log = Logger.getLogger( JaccIntegrator.class ); + + private static final DuplicationStrategy DUPLICATION_STRATEGY = new DuplicationStrategy() { + @Override + public boolean areMatch(Object listener, Object original) { + return listener.getClass().equals( original.getClass() ) && + JaccSecurityListener.class.isInstance( original ); + } + + @Override + public Action getAction() { + return Action.KEEP_ORIGINAL; + } + }; + + @Override + public void prepareServices(StandardServiceRegistryBuilder serviceRegistryBuilder) { + boolean isSecurityEnabled = serviceRegistryBuilder.getSettings().containsKey( AvailableSettings.JACC_ENABLED ); + final JaccService jaccService = isSecurityEnabled ? new StandardJaccServiceImpl() : new DisabledJaccServiceImpl(); + serviceRegistryBuilder.addService( JaccService.class, jaccService ); + } + + @Override + public void integrate( + Configuration configuration, + SessionFactoryImplementor sessionFactory, + SessionFactoryServiceRegistry serviceRegistry) { + doIntegration( configuration.getProperties(), configuration.getJaccPermissionDeclarations(), serviceRegistry ); + } + + private void doIntegration( + Map properties, + JaccPermissionDeclarations permissionDeclarations, + SessionFactoryServiceRegistry serviceRegistry) { + boolean isSecurityEnabled = properties.containsKey( AvailableSettings.JACC_ENABLED ); + if ( ! isSecurityEnabled ) { + log.debug( "Skipping JACC integration as it was not enabled" ); + return; + } + + final String contextId = (String) properties.get( AvailableSettings.JACC_CONTEXT_ID ); + if ( contextId == null ) { + throw new IntegrationException( "JACC context id must be specified" ); + } + + final JaccService jaccService = serviceRegistry.getService( JaccService.class ); + if ( jaccService == null ) { + throw new IntegrationException( "JaccService was not set up" ); + } + + if ( permissionDeclarations != null ) { + for ( GrantedPermission declaration : permissionDeclarations.getPermissionDeclarations() ) { + jaccService.addPermission( declaration ); + } + } + + final EventListenerRegistry eventListenerRegistry = serviceRegistry.getService( EventListenerRegistry.class ); + eventListenerRegistry.addDuplicationStrategy( DUPLICATION_STRATEGY ); + + eventListenerRegistry.prependListeners( EventType.PRE_DELETE, new JaccPreDeleteEventListener() ); + eventListenerRegistry.prependListeners( EventType.PRE_INSERT, new JaccPreInsertEventListener() ); + eventListenerRegistry.prependListeners( EventType.PRE_UPDATE, new JaccPreUpdateEventListener() ); + eventListenerRegistry.prependListeners( EventType.PRE_LOAD, new JaccPreLoadEventListener() ); + } + + @Override + public void integrate( + MetadataImplementor metadata, + SessionFactoryImplementor sessionFactory, + SessionFactoryServiceRegistry serviceRegistry) { + doIntegration( sessionFactory.getProperties(), null, serviceRegistry ); + } + + @Override + public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) { + // nothing to do + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/secure/spi/JaccPermissionDeclarations.java b/hibernate-core/src/main/java/org/hibernate/secure/spi/JaccPermissionDeclarations.java new file mode 100644 index 0000000000..571cba36a3 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/secure/spi/JaccPermissionDeclarations.java @@ -0,0 +1,50 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2013, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.secure.spi; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Steve Ebersole + */ +public class JaccPermissionDeclarations { + private final String contextId; + private List