HHH-14844 - Drop JACC integration

This commit is contained in:
Steve Ebersole 2021-09-27 13:19:54 -05:00
parent 986d65a288
commit 8a8a92ca5e
28 changed files with 31 additions and 1401 deletions

View File

@ -1,296 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.userguide.events;
import java.io.Serializable;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.Map;
import jakarta.persistence.Entity;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.PostLoad;
import jakarta.persistence.PrePersist;
import jakarta.persistence.PreUpdate;
import jakarta.persistence.Transient;
import org.hibernate.HibernateException;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.engine.config.spi.ConfigurationService;
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.event.spi.LoadEvent;
import org.hibernate.event.spi.LoadEventListener;
import org.hibernate.integrator.spi.ServiceContributingIntegrator;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
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.secure.spi.GrantedPermission;
import org.hibernate.secure.spi.IntegrationException;
import org.hibernate.secure.spi.JaccPermissionDeclarations;
import org.hibernate.secure.spi.JaccService;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
import org.junit.Test;
import org.jboss.logging.Logger;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertTrue;
/**
* @author Vlad Mihalcea
*/
public class ListenerTest extends BaseEntityManagerFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Person.class,
Customer.class
};
}
@Test(expected = SecurityException.class)
public void testLoadListener() {
Serializable customerId = 1L;
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::events-interceptors-load-listener-example[]
EntityManagerFactory entityManagerFactory = entityManagerFactory();
SessionFactoryImplementor sessionFactory = entityManagerFactory.unwrap( SessionFactoryImplementor.class );
sessionFactory
.getServiceRegistry()
.getService( EventListenerRegistry.class )
.prependListeners( EventType.LOAD, new SecuredLoadEntityListener() );
Customer customer = entityManager.find( Customer.class, customerId );
//end::events-interceptors-load-listener-example[]
} );
}
@Test
public void testJPACallback() {
Long personId = 1L;
doInJPA( this::entityManagerFactory, entityManager -> {
Person person = new Person();
person.id = personId;
person.name = "John Doe";
person.dateOfBirth = Timestamp.valueOf(LocalDateTime.of( 2000, 1, 1, 0, 0, 0 ));
entityManager.persist( person );
} );
doInJPA( this::entityManagerFactory, entityManager -> {
Person person = entityManager.find( Person.class, personId );
assertTrue(person.age > 0);
} );
}
@Entity(name = "Customer")
public static class Customer {
@Id
@GeneratedValue
private Long id;
private String name;
public Customer() {
}
public Customer(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//tag::events-jpa-callbacks-example[]
@Entity(name = "Person")
@EntityListeners( LastUpdateListener.class )
public static class Person {
@Id
private Long id;
private String name;
private Date dateOfBirth;
@Transient
private long age;
private Date lastUpdate;
public void setLastUpdate(Date lastUpdate) {
this.lastUpdate = lastUpdate;
}
/**
* Set the transient property at load time based on a calculation.
* Note that a native Hibernate formula mapping is better for this purpose.
*/
@PostLoad
public void calculateAge() {
age = ChronoUnit.YEARS.between( LocalDateTime.ofInstant(
Instant.ofEpochMilli( dateOfBirth.getTime()), ZoneOffset.UTC),
LocalDateTime.now()
);
}
}
public static class LastUpdateListener {
@PreUpdate
@PrePersist
public void setLastUpdate( Person p ) {
p.setLastUpdate( new Date() );
}
}
//end::events-jpa-callbacks-example[]
//tag::events-interceptors-example[]
public static class SecuredLoadEntityListener implements LoadEventListener {
// this is the single method defined by the LoadEventListener interface
public void onLoad(LoadEvent event, LoadType loadType)
throws HibernateException {
if ( !Principal.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) {
throw new SecurityException( "Unauthorized access" );
}
}
}
//end::events-Principal-example[]
public static class Principal {
public static boolean isAuthorized(String clazz, Object id) {
return false;
}
}
//tag::events-declarative-security-jacc-example[]
public static 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(
Metadata metadata,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
doIntegration(
serviceRegistry
.getService( ConfigurationService.class ).getSettings(),
// pass no permissions here, because atm actually injecting the
// permissions into the JaccService is handled on SessionFactoryImpl via
// the org.hibernate.boot.cfgxml.spi.CfgXmlAccessService
null,
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 disintegrate(SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
// nothing to do
}
}
//end::events-declarative-security-jacc-example[]
}

View File

@ -24,8 +24,6 @@ import org.hibernate.boot.jaxb.cfg.spi.JaxbCfgEventListenerType;
import org.hibernate.boot.jaxb.cfg.spi.JaxbCfgHibernateConfiguration; import org.hibernate.boot.jaxb.cfg.spi.JaxbCfgHibernateConfiguration;
import org.hibernate.boot.jaxb.cfg.spi.JaxbCfgMappingReferenceType; import org.hibernate.boot.jaxb.cfg.spi.JaxbCfgMappingReferenceType;
import org.hibernate.event.spi.EventType; import org.hibernate.event.spi.EventType;
import org.hibernate.secure.spi.GrantedPermission;
import org.hibernate.secure.spi.JaccPermissionDeclarations;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
@ -42,7 +40,6 @@ public class LoadedConfig {
private final Map configurationValues = new ConcurrentHashMap( 16, 0.75f, 1 ); private final Map configurationValues = new ConcurrentHashMap( 16, 0.75f, 1 );
private Map<String,JaccPermissionDeclarations> jaccPermissionsByContextId;
private List<CacheRegionDefinition> cacheRegionDefinitions; private List<CacheRegionDefinition> cacheRegionDefinitions;
private List<MappingReference> mappingReferences; private List<MappingReference> mappingReferences;
private Map<EventType,Set<String>> eventListenerMap; private Map<EventType,Set<String>> eventListenerMap;
@ -59,14 +56,6 @@ public class LoadedConfig {
return configurationValues; return configurationValues;
} }
public Map<String, JaccPermissionDeclarations> getJaccPermissionsByContextId() {
return jaccPermissionsByContextId;
}
public JaccPermissionDeclarations getJaccPermissions(String jaccContextId) {
return jaccPermissionsByContextId.get( jaccContextId );
}
public List<CacheRegionDefinition> getCacheRegionDefinitions() { public List<CacheRegionDefinition> getCacheRegionDefinitions() {
return cacheRegionDefinitions == null ? Collections.emptyList() : cacheRegionDefinitions; return cacheRegionDefinitions == null ? Collections.emptyList() : cacheRegionDefinitions;
} }
@ -102,22 +91,6 @@ public class LoadedConfig {
cfg.addCacheRegionDefinition( parseCacheRegionDefinition( cacheDeclaration ) ); cfg.addCacheRegionDefinition( parseCacheRegionDefinition( cacheDeclaration ) );
} }
if ( jaxbCfg.getSecurity() != null ) {
for ( JaxbCfgHibernateConfiguration.JaxbCfgSecurity.JaxbCfgGrant grant : jaxbCfg.getSecurity().getGrant() ) {
final JaccPermissionDeclarations jaccPermissions = cfg.getOrCreateJaccPermissions(
jaxbCfg.getSecurity()
.getContext()
);
jaccPermissions.addPermissionDeclaration(
new GrantedPermission(
grant.getRole(),
grant.getEntityName(),
grant.getActions()
)
);
}
}
if ( !jaxbCfg.getSessionFactory().getListener().isEmpty() ) { if ( !jaxbCfg.getSessionFactory().getListener().isEmpty() ) {
for ( JaxbCfgEventListenerType listener : jaxbCfg.getSessionFactory().getListener() ) { for ( JaxbCfgEventListenerType listener : jaxbCfg.getSessionFactory().getListener() ) {
final EventType eventType = EventType.resolveEventTypeByName( listener.getType().value() ); final EventType eventType = EventType.resolveEventTypeByName( listener.getType().value() );
@ -216,20 +189,6 @@ public class LoadedConfig {
listenerClasses.add( listenerClass ); listenerClasses.add( listenerClass );
} }
public JaccPermissionDeclarations getOrCreateJaccPermissions(String contextId) {
if ( jaccPermissionsByContextId == null ) {
jaccPermissionsByContextId = new HashMap<>();
}
JaccPermissionDeclarations jaccPermission = jaccPermissionsByContextId.get( contextId );
if ( jaccPermission == null ) {
jaccPermission = new JaccPermissionDeclarations( contextId );
}
jaccPermissionsByContextId.put( contextId, jaccPermission );
return jaccPermission;
}
/** /**
* Merge information from loaded a {@code cfg.xml} represented by the incoming parameter * Merge information from loaded a {@code cfg.xml} represented by the incoming parameter
* into this LoadedConfig representation * into this LoadedConfig representation
@ -254,7 +213,6 @@ public class LoadedConfig {
addConfigurationValues( incoming.getConfigurationValues() ); addConfigurationValues( incoming.getConfigurationValues() );
addMappingReferences( incoming.getMappingReferences() ); addMappingReferences( incoming.getMappingReferences() );
addCacheRegionDefinitions( incoming.getCacheRegionDefinitions() ); addCacheRegionDefinitions( incoming.getCacheRegionDefinitions() );
addJaccPermissions( incoming.getJaccPermissionsByContextId() );
addEventListeners( incoming.getEventListenerMap() ); addEventListeners( incoming.getEventListenerMap() );
} }
@ -289,26 +247,6 @@ public class LoadedConfig {
this.cacheRegionDefinitions.addAll( cacheRegionDefinitions ); this.cacheRegionDefinitions.addAll( cacheRegionDefinitions );
} }
private void addJaccPermissions(Map<String, JaccPermissionDeclarations> jaccPermissionsByContextId) {
if ( jaccPermissionsByContextId == null ) {
return;
}
if ( this.jaccPermissionsByContextId == null ) {
this.jaccPermissionsByContextId = new HashMap<>();
}
for ( Map.Entry<String, JaccPermissionDeclarations> incomingEntry : jaccPermissionsByContextId.entrySet() ) {
JaccPermissionDeclarations permissions = jaccPermissionsByContextId.get( incomingEntry.getKey() );
if ( permissions == null ) {
permissions = new JaccPermissionDeclarations( incomingEntry.getKey() );
this.jaccPermissionsByContextId.put( incomingEntry.getKey(), permissions );
}
permissions.addPermissionDeclarations( incomingEntry.getValue().getPermissionDeclarations() );
}
}
private void addEventListeners(Map<EventType, Set<String>> eventListenerMap) { private void addEventListeners(Map<EventType, Set<String>> eventListenerMap) {
if ( eventListenerMap == null ) { if ( eventListenerMap == null ) {
return; return;

View File

@ -1997,10 +1997,6 @@ public interface AvailableSettings {
*/ */
String JTA_TRACK_BY_THREAD = "hibernate.jta.track_by_thread"; String JTA_TRACK_BY_THREAD = "hibernate.jta.track_by_thread";
String JACC_CONTEXT_ID = "hibernate.jacc_context_id";
String JACC_PREFIX = "hibernate.jacc";
String JACC_ENABLED = "hibernate.jacc.enabled";
/** /**
* If enabled, allows schema update and validation to support synonyms. Due * If enabled, allows schema update and validation to support synonyms. Due
* to the possibility that this would return duplicate tables (especially in * to the possibility that this would return duplicate tables (especially in

View File

@ -17,7 +17,6 @@ import jakarta.validation.Validation;
import jakarta.validation.Validator; import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory; import jakarta.validation.ValidatorFactory;
import org.hibernate.EntityMode;
import org.hibernate.boot.internal.ClassLoaderAccessImpl; import org.hibernate.boot.internal.ClassLoaderAccessImpl;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
@ -29,6 +28,7 @@ import org.hibernate.event.spi.PreUpdateEvent;
import org.hibernate.event.spi.PreUpdateEventListener; import org.hibernate.event.spi.PreUpdateEventListener;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.RepresentationMode;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
@ -78,31 +78,40 @@ public class BeanValidationEventListener
public boolean onPreInsert(PreInsertEvent event) { public boolean onPreInsert(PreInsertEvent event) {
validate( validate(
event.getEntity(), event.getPersister().getEntityMode(), event.getPersister(), event.getEntity(),
event.getSession().getFactory(), GroupsPerOperation.Operation.INSERT event.getPersister().getRepresentationStrategy().getMode(),
event.getPersister(),
event.getSession().getFactory(),
GroupsPerOperation.Operation.INSERT
); );
return false; return false;
} }
public boolean onPreUpdate(PreUpdateEvent event) { public boolean onPreUpdate(PreUpdateEvent event) {
validate( validate(
event.getEntity(), event.getPersister().getEntityMode(), event.getPersister(), event.getEntity(),
event.getSession().getFactory(), GroupsPerOperation.Operation.UPDATE event.getPersister().getRepresentationStrategy().getMode(),
event.getPersister(),
event.getSession().getFactory(),
GroupsPerOperation.Operation.UPDATE
); );
return false; return false;
} }
public boolean onPreDelete(PreDeleteEvent event) { public boolean onPreDelete(PreDeleteEvent event) {
validate( validate(
event.getEntity(), event.getPersister().getEntityMode(), event.getPersister(), event.getEntity(),
event.getSession().getFactory(), GroupsPerOperation.Operation.DELETE event.getPersister().getRepresentationStrategy().getMode(),
event.getPersister(),
event.getSession().getFactory(),
GroupsPerOperation.Operation.DELETE
); );
return false; return false;
} }
private <T> void validate(T object, EntityMode mode, EntityPersister persister, private <T> void validate(T object, RepresentationMode mode, EntityPersister persister,
SessionFactoryImplementor sessionFactory, GroupsPerOperation.Operation operation) { SessionFactoryImplementor sessionFactory, GroupsPerOperation.Operation operation) {
if ( object == null || mode != EntityMode.POJO ) { if ( object == null || mode != RepresentationMode.POJO ) {
return; return;
} }
TraversableResolver tr = new HibernateTraversableResolver( TraversableResolver tr = new HibernateTraversableResolver(

View File

@ -7,16 +7,13 @@
package org.hibernate.event.spi; package org.hibernate.event.spi;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.secure.spi.PermissionCheckEntityInformation;
/** /**
* Represents an operation we are about to perform against the database. * Represents an operation we are about to perform against the database.
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public abstract class AbstractPreDatabaseOperationEvent public abstract class AbstractPreDatabaseOperationEvent extends AbstractEvent {
extends AbstractEvent
implements PermissionCheckEntityInformation {
private final Object entity; private final Object entity;
private final Object id; private final Object id;
@ -46,7 +43,6 @@ public abstract class AbstractPreDatabaseOperationEvent
* *
* @return The entity. * @return The entity.
*/ */
@Override
public Object getEntity() { public Object getEntity() {
return entity; return entity;
} }
@ -61,7 +57,7 @@ public abstract class AbstractPreDatabaseOperationEvent
} }
/** /**
* The persister for the {@link #getEntity entity}. * The persister for the entity.
* *
* @return The entity persister. * @return The entity persister.
*/ */
@ -85,14 +81,4 @@ public abstract class AbstractPreDatabaseOperationEvent
public EventSource getSource() { public EventSource getSource() {
return getSession(); return getSession();
} }
@Override
public String getEntityName() {
return persister.getEntityName();
}
@Override
public Object getIdentifier() {
return id;
}
} }

View File

@ -7,7 +7,6 @@
package org.hibernate.event.spi; package org.hibernate.event.spi;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.secure.spi.PermissionCheckEntityInformation;
/** /**
@ -17,9 +16,7 @@ import org.hibernate.secure.spi.PermissionCheckEntityInformation;
* @author Gavin King * @author Gavin King
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class PreDeleteEvent public class PreDeleteEvent extends AbstractPreDatabaseOperationEvent {
extends AbstractPreDatabaseOperationEvent
implements PermissionCheckEntityInformation {
private Object[] deletedState; private Object[] deletedState;

View File

@ -7,14 +7,13 @@
package org.hibernate.event.spi; package org.hibernate.event.spi;
import org.hibernate.persister.entity.EntityPersister; 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 * @author Gavin King
*/ */
public class PreLoadEvent extends AbstractEvent implements PermissionCheckEntityInformation { public class PreLoadEvent extends AbstractEvent {
private Object entity; private Object entity;
private Object[] state; private Object[] state;
private Object id; private Object id;
@ -31,11 +30,10 @@ public class PreLoadEvent extends AbstractEvent implements PermissionCheckEntity
persister = null; persister = null;
} }
@Override
public Object getEntity() { public Object getEntity() {
return entity; return entity;
} }
public Object getId() { public Object getId() {
return id; return id;
} }
@ -57,7 +55,7 @@ public class PreLoadEvent extends AbstractEvent implements PermissionCheckEntity
this.id = id; this.id = id;
return this; return this;
} }
public PreLoadEvent setPersister(EntityPersister persister) { public PreLoadEvent setPersister(EntityPersister persister) {
this.persister = persister; this.persister = persister;
return this; return this;
@ -67,14 +65,4 @@ public class PreLoadEvent extends AbstractEvent implements PermissionCheckEntity
this.state = state; this.state = state;
return this; return this;
} }
@Override
public String getEntityName() {
return persister.getEntityName();
}
@Override
public Object getIdentifier() {
return id;
}
} }

View File

@ -13,7 +13,6 @@ import org.hibernate.cache.internal.CollectionCacheInvalidator;
import org.hibernate.cfg.beanvalidation.BeanValidationIntegrator; import org.hibernate.cfg.beanvalidation.BeanValidationIntegrator;
import org.hibernate.integrator.spi.Integrator; import org.hibernate.integrator.spi.Integrator;
import org.hibernate.integrator.spi.IntegratorService; import org.hibernate.integrator.spi.IntegratorService;
import org.hibernate.secure.spi.JaccIntegrator;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
@ -29,7 +28,6 @@ public class IntegratorServiceImpl implements IntegratorService {
// register standard integrators. Envers and JPA, for example, need to be handled by discovery because in // register standard integrators. Envers and JPA, for example, need to be handled by discovery because in
// separate project/jars. // separate project/jars.
addIntegrator( new BeanValidationIntegrator() ); addIntegrator( new BeanValidationIntegrator() );
addIntegrator( new JaccIntegrator() );
addIntegrator( new CollectionCacheInvalidator() ); addIntegrator( new CollectionCacheInvalidator() );
// register provided integrators // register provided integrators

View File

@ -47,7 +47,6 @@ import org.hibernate.SessionFactoryObserver;
import org.hibernate.StatelessSession; import org.hibernate.StatelessSession;
import org.hibernate.StatelessSessionBuilder; import org.hibernate.StatelessSessionBuilder;
import org.hibernate.boot.cfgxml.spi.CfgXmlAccessService; import org.hibernate.boot.cfgxml.spi.CfgXmlAccessService;
import org.hibernate.boot.cfgxml.spi.LoadedConfig;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.boot.spi.BootstrapContext;
import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.MetadataBuildingContext;
@ -80,16 +79,12 @@ import org.hibernate.engine.spi.SessionBuilderImplementor;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionOwner; import org.hibernate.engine.spi.SessionOwner;
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventEngine; import org.hibernate.event.spi.EventEngine;
import org.hibernate.event.spi.EventType;
import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.factory.IdentifierGeneratorFactory; import org.hibernate.id.factory.IdentifierGeneratorFactory;
import org.hibernate.integrator.spi.Integrator; import org.hibernate.integrator.spi.Integrator;
import org.hibernate.integrator.spi.IntegratorService; import org.hibernate.integrator.spi.IntegratorService;
import org.hibernate.internal.util.config.ConfigurationException;
import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.jpa.internal.AfterCompletionActionLegacyJpaImpl; import org.hibernate.jpa.internal.AfterCompletionActionLegacyJpaImpl;
import org.hibernate.jpa.internal.ExceptionMapperLegacyJpaImpl; import org.hibernate.jpa.internal.ExceptionMapperLegacyJpaImpl;
@ -124,9 +119,6 @@ import org.hibernate.resource.transaction.backend.jta.internal.synchronization.A
import org.hibernate.resource.transaction.backend.jta.internal.synchronization.ExceptionMapper; import org.hibernate.resource.transaction.backend.jta.internal.synchronization.ExceptionMapper;
import org.hibernate.resource.transaction.backend.jta.internal.synchronization.ManagedFlushChecker; import org.hibernate.resource.transaction.backend.jta.internal.synchronization.ManagedFlushChecker;
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder; import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
import org.hibernate.secure.spi.GrantedPermission;
import org.hibernate.secure.spi.JaccPermissionDeclarations;
import org.hibernate.secure.spi.JaccService;
import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.service.spi.SessionFactoryServiceRegistry; import org.hibernate.service.spi.SessionFactoryServiceRegistry;
import org.hibernate.service.spi.SessionFactoryServiceRegistryFactory; import org.hibernate.service.spi.SessionFactoryServiceRegistryFactory;
@ -226,7 +218,6 @@ public class SessionFactoryImpl implements SessionFactoryImplementor {
if ( sfName == null ) { if ( sfName == null ) {
sfName = cfgXmlAccessService.getAggregatedConfig().getSessionFactoryName(); sfName = cfgXmlAccessService.getAggregatedConfig().getSessionFactoryName();
} }
applyCfgXmlValues( cfgXmlAccessService.getAggregatedConfig(), serviceRegistry );
} }
this.name = sfName; this.name = sfName;
@ -494,34 +485,6 @@ public class SessionFactoryImpl implements SessionFactoryImplementor {
} }
} }
private void applyCfgXmlValues(LoadedConfig aggregatedConfig, SessionFactoryServiceRegistry serviceRegistry) {
final JaccService jaccService = serviceRegistry.getService( JaccService.class );
if ( jaccService.getContextId() != null ) {
final JaccPermissionDeclarations permissions = aggregatedConfig.getJaccPermissions( jaccService.getContextId() );
if ( permissions != null ) {
for ( GrantedPermission grantedPermission : permissions.getPermissionDeclarations() ) {
jaccService.addPermission( grantedPermission );
}
}
}
if ( aggregatedConfig.getEventListenerMap() != null ) {
final ClassLoaderService cls = serviceRegistry.getService( ClassLoaderService.class );
final EventListenerRegistry eventListenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );
for ( Map.Entry<EventType, Set<String>> entry : aggregatedConfig.getEventListenerMap().entrySet() ) {
final EventListenerGroup group = eventListenerRegistry.getEventListenerGroup( entry.getKey() );
for ( String listenerClassName : entry.getValue() ) {
try {
group.appendListener( cls.classForName( listenerClassName ).newInstance() );
}
catch (Exception e) {
throw new ConfigurationException( "Unable to instantiate event listener class : " + listenerClassName, e );
}
}
}
}
}
private JdbcConnectionAccess buildLocalConnectionAccess() { private JdbcConnectionAccess buildLocalConnectionAccess() {
if ( settings.getMultiTenancyStrategy().requiresMultiTenantConnectionProvider() ) { if ( settings.getMultiTenancyStrategy().requiresMultiTenantConnectionProvider() ) {
final MultiTenantConnectionProvider mTenantConnectionProvider = serviceRegistry.getService( MultiTenantConnectionProvider.class ); final MultiTenantConnectionProvider mTenantConnectionProvider = serviceRegistry.getService( MultiTenantConnectionProvider.class );

View File

@ -73,8 +73,6 @@ import org.hibernate.proxy.EntityNotFoundDelegate;
import org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorBuilderImpl; import org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorBuilderImpl;
import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorBuilderImpl; import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorBuilderImpl;
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder; import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
import org.hibernate.secure.spi.GrantedPermission;
import org.hibernate.secure.spi.JaccPermissionDeclarations;
import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.spi.ServiceBinding; import org.hibernate.service.spi.ServiceBinding;
import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.service.spi.ServiceRegistryImplementor;
@ -98,9 +96,6 @@ import static org.hibernate.cfg.AvailableSettings.CLASS_CACHE_PREFIX;
import static org.hibernate.cfg.AvailableSettings.COLLECTION_CACHE_PREFIX; import static org.hibernate.cfg.AvailableSettings.COLLECTION_CACHE_PREFIX;
import static org.hibernate.cfg.AvailableSettings.DATASOURCE; import static org.hibernate.cfg.AvailableSettings.DATASOURCE;
import static org.hibernate.cfg.AvailableSettings.DRIVER; import static org.hibernate.cfg.AvailableSettings.DRIVER;
import static org.hibernate.cfg.AvailableSettings.JACC_CONTEXT_ID;
import static org.hibernate.cfg.AvailableSettings.JACC_ENABLED;
import static org.hibernate.cfg.AvailableSettings.JACC_PREFIX;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_JDBC_DRIVER; import static org.hibernate.cfg.AvailableSettings.JAKARTA_JDBC_DRIVER;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_JDBC_PASSWORD; import static org.hibernate.cfg.AvailableSettings.JAKARTA_JDBC_PASSWORD;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_JDBC_URL; import static org.hibernate.cfg.AvailableSettings.JAKARTA_JDBC_URL;
@ -550,8 +545,6 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
normalizeSettings( persistenceUnit, integrationSettings, mergedSettings ); normalizeSettings( persistenceUnit, integrationSettings, mergedSettings );
final String jaccContextId = (String) mergedSettings.configurationValues.get( JACC_CONTEXT_ID );
// here we are going to iterate the merged config settings looking for: // here we are going to iterate the merged config settings looking for:
// 1) additional JACC permissions // 1) additional JACC permissions
// 2) additional cache region declarations // 2) additional cache region declarations
@ -570,22 +563,7 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
final String keyString = (String) entry.getKey(); final String keyString = (String) entry.getKey();
final String valueString = (String) entry.getValue(); final String valueString = (String) entry.getValue();
if ( keyString.startsWith( JACC_PREFIX ) ) { if ( keyString.startsWith( CLASS_CACHE_PREFIX ) ) {
if( !JACC_CONTEXT_ID.equals( keyString ) && !JACC_ENABLED.equals( keyString )) {
if ( jaccContextId == null ) {
LOG.debugf(
"Found JACC permission grant [%s] in properties, but no JACC context id was specified; ignoring",
keyString
);
}
else {
mergedSettings.getJaccPermissions( jaccContextId ).addPermissionDeclaration(
parseJaccConfigEntry( keyString, valueString )
);
}
}
}
else if ( keyString.startsWith( CLASS_CACHE_PREFIX ) ) {
mergedSettings.addCacheRegionDefinition( mergedSettings.addCacheRegionDefinition(
parseCacheRegionDefinitionEntry( parseCacheRegionDefinitionEntry(
keyString.substring( CLASS_CACHE_PREFIX.length() + 1 ), keyString.substring( CLASS_CACHE_PREFIX.length() + 1 ),
@ -1204,19 +1182,6 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
ssrBuilder.getAggregatedCfgXml().merge( loadedConfig ); ssrBuilder.getAggregatedCfgXml().merge( loadedConfig );
} }
private GrantedPermission parseJaccConfigEntry(String keyString, String valueString) {
try {
final int roleStart = JACC_PREFIX.length() + 1;
final String role = keyString.substring( roleStart, keyString.indexOf( '.', roleStart ) );
final int classStart = roleStart + role.length() + 1;
final String clazz = keyString.substring( classStart );
return new GrantedPermission( role, clazz, valueString );
}
catch ( IndexOutOfBoundsException e ) {
throw persistenceException( "Illegal usage of " + JACC_PREFIX + ": " + keyString );
}
}
private CacheRegionDefinition parseCacheRegionDefinitionEntry(String role, String value, CacheRegionDefinition.CacheRegionType cacheType) { private CacheRegionDefinition parseCacheRegionDefinitionEntry(String role, String value, CacheRegionDefinition.CacheRegionType cacheType) {
final StringTokenizer params = new StringTokenizer( value, ";, " ); final StringTokenizer params = new StringTokenizer( value, ";, " );
if ( !params.hasMoreTokens() ) { if ( !params.hasMoreTokens() ) {
@ -1591,7 +1556,6 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
public static class MergedSettings { public static class MergedSettings {
private final Map configurationValues = new ConcurrentHashMap( 16, 0.75f, 1 ); private final Map configurationValues = new ConcurrentHashMap( 16, 0.75f, 1 );
private Map<String, JaccPermissionDeclarations> jaccPermissionsByContextId;
private List<CacheRegionDefinition> cacheRegionDefinitions; private List<CacheRegionDefinition> cacheRegionDefinitions;
/** /**
@ -1630,19 +1594,6 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
return configurationValues; return configurationValues;
} }
private JaccPermissionDeclarations getJaccPermissions(String jaccContextId) {
if ( jaccPermissionsByContextId == null ) {
jaccPermissionsByContextId = new HashMap<>();
}
JaccPermissionDeclarations jaccPermissions = jaccPermissionsByContextId.get( jaccContextId );
if ( jaccPermissions == null ) {
jaccPermissions = new JaccPermissionDeclarations( jaccContextId );
jaccPermissionsByContextId.put( jaccContextId, jaccPermissions );
}
return jaccPermissions;
}
private void addCacheRegionDefinition(CacheRegionDefinition cacheRegionDefinition) { private void addCacheRegionDefinition(CacheRegionDefinition cacheRegionDefinition) {
if ( this.cacheRegionDefinitions == null ) { if ( this.cacheRegionDefinitions == null ) {
this.cacheRegionDefinitions = new ArrayList<>(); this.cacheRegionDefinitions = new ArrayList<>();

View File

@ -1,36 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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 );
}
}

View File

@ -1,36 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.secure.internal;
import org.hibernate.secure.spi.GrantedPermission;
import org.hibernate.secure.spi.JaccService;
import org.hibernate.secure.spi.PermissibleAction;
import org.hibernate.secure.spi.PermissionCheckEntityInformation;
import org.jboss.logging.Logger;
/**
* @author Steve Ebersole
*/
public class DisabledJaccServiceImpl implements JaccService {
private static final Logger log = Logger.getLogger( DisabledJaccServiceImpl.class );
@Override
public String getContextId() {
return null;
}
@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" );
}
}

View File

@ -1,28 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.secure.internal;
import org.hibernate.event.spi.PreDeleteEvent;
import org.hibernate.event.spi.PreDeleteEventListener;
import org.hibernate.secure.spi.PermissibleAction;
/**
* Check security before any deletion
*
* @author <a href="mailto:kabir.khan@jboss.org">Kabir Khan</a>
* @author Steve Ebersole
*/
public class JaccPreDeleteEventListener extends AbstractJaccSecurableEventListener implements PreDeleteEventListener {
public JaccPreDeleteEventListener() {
}
public boolean onPreDelete(PreDeleteEvent event) {
performSecurityCheck( event, PermissibleAction.DELETE );
return false;
}
}

View File

@ -1,27 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.secure.internal;
import org.hibernate.event.spi.PreInsertEvent;
import org.hibernate.event.spi.PreInsertEventListener;
import org.hibernate.secure.spi.PermissibleAction;
/**
* Check security before an insertion
*
* @author <a href="mailto:kabir.khan@jboss.org">Kabir Khan</a>
* @author Steve Ebersole
*/
public class JaccPreInsertEventListener extends AbstractJaccSecurableEventListener implements PreInsertEventListener {
public JaccPreInsertEventListener() {
}
public boolean onPreInsert(PreInsertEvent event) {
performSecurityCheck( event, PermissibleAction.INSERT );
return false;
}
}

View File

@ -1,26 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.secure.internal;
import org.hibernate.event.spi.PreLoadEvent;
import org.hibernate.event.spi.PreLoadEventListener;
import org.hibernate.secure.spi.PermissibleAction;
/**
* Check security before any load
*
* @author <a href="mailto:kabir.khan@jboss.org">Kabir Khan</a>
* @author Steve Ebersole
*/
public class JaccPreLoadEventListener extends AbstractJaccSecurableEventListener implements PreLoadEventListener {
public JaccPreLoadEventListener() {
}
public void onPreLoad(PreLoadEvent event) {
performSecurityCheck( event.getSession(), event, PermissibleAction.READ );
}
}

View File

@ -1,27 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.secure.internal;
import org.hibernate.event.spi.PreUpdateEvent;
import org.hibernate.event.spi.PreUpdateEventListener;
import org.hibernate.secure.spi.PermissibleAction;
/**
* Check security before any update
*
* @author <a href="mailto:kabir.khan@jboss.org">Kabir Khan</a>
* @author Steve Ebersole
*/
public class JaccPreUpdateEventListener extends AbstractJaccSecurableEventListener implements PreUpdateEventListener {
public JaccPreUpdateEventListener() {
}
public boolean onPreUpdate(PreUpdateEvent event) {
performSecurityCheck( event, PermissibleAction.UPDATE );
return false;
}
}

View File

@ -1,16 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.secure.internal;
/**
* Marker interface for JACC event listeners. Used in event listener duplication strategy checks; see
* {@link org.hibernate.secure.spi.JaccIntegrator} for details.
*
* @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
*/
public interface JaccSecurityListener {
}

View File

@ -1,209 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.secure.internal;
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 javax.security.auth.Subject;
import jakarta.security.jacc.EJBMethodPermission;
import jakarta.security.jacc.PolicyConfiguration;
import jakarta.security.jacc.PolicyConfigurationFactory;
import jakarta.security.jacc.PolicyContext;
import jakarta.security.jacc.PolicyContextException;
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;
import org.jboss.logging.Logger;
/**
* @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 String getContextId() {
return contextId;
}
@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<String> {
private final String contextId;
private ContextIdSetAction(String contextId) {
this.contextId = contextId;
}
@Override
public String run() {
String previousID = PolicyContext.getContextID();
PolicyContext.setContextID( contextId );
return previousID;
}
}
private void doPermissionCheckInContext(PermissionCheckEntityInformation entityInformation, PermissibleAction action) {
final Policy policy = Policy.getPolicy();
final Principal[] principals = getCallerPrincipals();
final CodeSource codeSource = entityInformation.getEntity().getClass().getProtectionDomain().getCodeSource();
final ProtectionDomain pd = new ProtectionDomain( codeSource, null, null, principals );
// the action is known as 'method name' in JACC
final EJBMethodPermission jaccPermission = new EJBMethodPermission(
entityInformation.getEntityName(),
action.getImpliedActions()[0],
null,
null
);
if ( ! policy.implies( pd, jaccPermission) ) {
throw new SecurityException(
String.format(
"JACC denied permission to [%s.%s] for [%s]",
entityInformation.getEntityName(),
action.getImpliedActions()[0],
join( principals )
)
);
}
}
private String join(Principal[] principals) {
String separator = "";
final StringBuilder buffer = new StringBuilder();
for ( Principal principal : principals ) {
buffer.append( separator ).append( principal.getName() );
separator = ", ";
}
return buffer.toString();
}
protected Principal[] getCallerPrincipals() {
final Subject caller = getContextSubjectAccess().getContextSubject();
if ( caller == null ) {
return new Principal[0];
}
final Set<Principal> principalsSet = caller.getPrincipals();
return principalsSet.toArray( new Principal[ principalsSet.size()] );
}
private ContextSubjectAccess getContextSubjectAccess() {
return ( System.getSecurityManager() == null )
? NonPrivilegedContextSubjectAccess.INSTANCE
: PrivilegedContextSubjectAccess.INSTANCE;
}
protected static interface ContextSubjectAccess {
public static final String SUBJECT_CONTEXT_KEY = "javax.security.auth.Subject.container";
public Subject getContextSubject();
}
protected static class PrivilegedContextSubjectAccess implements ContextSubjectAccess {
public static final PrivilegedContextSubjectAccess INSTANCE = new PrivilegedContextSubjectAccess();
private final PrivilegedAction<Subject> privilegedAction = new PrivilegedAction<Subject>() {
public Subject run() {
return NonPrivilegedContextSubjectAccess.INSTANCE.getContextSubject();
}
};
@Override
public Subject getContextSubject() {
return AccessController.doPrivileged( privilegedAction );
}
}
protected static class NonPrivilegedContextSubjectAccess implements ContextSubjectAccess {
public static final NonPrivilegedContextSubjectAccess INSTANCE = new NonPrivilegedContextSubjectAccess();
@Override
public Subject getContextSubject() {
try {
return (Subject) PolicyContext.getContext( SUBJECT_CONTEXT_KEY );
}
catch (PolicyContextException e) {
throw new HibernateException( "Unable to access JACC PolicyContext in order to locate calling Subject", e );
}
}
}
}

View File

@ -1,11 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.secure;
/**
* Package defining support for declarative security of CRUD operations via JACC.
*/

View File

@ -1,36 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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;
}
}

View File

@ -1,22 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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 );
}
}

View File

@ -1,113 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.secure.spi;
import java.util.Map;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.engine.config.spi.ConfigurationService;
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.ServiceContributingIntegrator;
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;
import org.jboss.logging.Logger;
/**
* 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(
Metadata metadata,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
doIntegration(
serviceRegistry.getService( ConfigurationService.class ).getSettings(),
// pass no permissions here, because atm actually injecting the
// permissions into the JaccService is handled on SessionFactoryImpl via
// the org.hibernate.boot.cfgxml.spi.CfgXmlAccessService
null,
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 disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
// nothing to do
}
}

View File

@ -1,45 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.secure.spi;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* @author Steve Ebersole
*/
public class JaccPermissionDeclarations {
private final String contextId;
private List<GrantedPermission> permissionDeclarations;
public JaccPermissionDeclarations(String contextId) {
this.contextId = contextId;
}
public String getContextId() {
return contextId;
}
public void addPermissionDeclaration(GrantedPermission permissionDeclaration) {
if ( permissionDeclarations == null ) {
permissionDeclarations = new ArrayList<>();
}
permissionDeclarations.add( permissionDeclaration );
}
public void addPermissionDeclarations(Collection<GrantedPermission> permissionDeclarations) {
if ( this.permissionDeclarations == null ) {
this.permissionDeclarations = new ArrayList<>();
}
this.permissionDeclarations.addAll( permissionDeclarations );
}
public Collection<GrantedPermission> getPermissionDeclarations() {
return permissionDeclarations;
}
}

View File

@ -1,27 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.secure.spi;
import org.hibernate.service.Service;
/**
* Service describing Hibernate integration with JACC for security service.
*
* @author Steve Ebersole
*/
public interface JaccService extends Service {
/**
* Obtain the JACC context-id in effect for this service. {@code null} indicates no
* context is in effect (service is disabled).
*
* @return The effective JACC context-id
*/
public String getContextId();
public void addPermission(GrantedPermission permissionDeclaration);
public void checkPermission(PermissionCheckEntityInformation entityInformation, PermissibleAction action);
}

View File

@ -1,63 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.secure.spi;
/**
* @author Steve Ebersole
*/
public enum PermissibleAction {
INSERT( "insert" ),
UPDATE( "update" ),
DELETE( "delete" ),
READ( "read" ),
ANY( "*" ) {
@Override
public String[] getImpliedActions() {
return new String[] { INSERT.externalName, UPDATE.externalName, DELETE.externalName, READ.externalName };
}
};
private final String externalName;
private final String[] impliedActions;
private PermissibleAction(String externalName) {
this.externalName = externalName;
this.impliedActions = buildImpliedActions( externalName );
}
private String[] buildImpliedActions(String externalName) {
return new String[] { externalName };
}
public String getExternalName() {
return externalName;
}
public String[] getImpliedActions() {
return impliedActions;
}
public static PermissibleAction interpret(String action) {
if ( INSERT.externalName.equals( action ) ) {
return INSERT;
}
else if ( UPDATE.externalName.equals( action ) ) {
return UPDATE;
}
else if ( DELETE.externalName.equals( action ) ) {
return DELETE;
}
else if ( READ.externalName.equals( action ) ) {
return READ;
}
else if ( ANY.externalName.equals( action ) ) {
return ANY;
}
throw new IllegalArgumentException( "Unrecognized action : " + action );
}
}

View File

@ -1,16 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.secure.spi;
/**
* @author Steve Ebersole
*/
public interface PermissionCheckEntityInformation {
public Object getEntity();
public String getEntityName();
public Object getIdentifier();
}

View File

@ -1,167 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.orm.test.secure;
import java.security.CodeSource;
import java.security.Permission;
import java.security.PermissionCollection;
import java.security.Policy;
import java.security.ProtectionDomain;
import java.security.Provider;
import java.util.Collections;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import javax.security.auth.Subject;
import jakarta.security.jacc.PolicyContext;
import jakarta.security.jacc.PolicyContextException;
import jakarta.security.jacc.PolicyContextHandler;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
import org.hibernate.testing.orm.junit.Jpa;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* @author Vlad Mihalcea
*/
@Jpa(annotatedClasses = {
JaccIntegratorTest.Person.class
}, properties = {
@Setting( name = AvailableSettings.JACC_ENABLED, value = "true"),
@Setting( name = AvailableSettings.JACC_CONTEXT_ID, value = "JACC_CONTEXT_ID"),
@Setting( name = "hibernate.jacc.allowed.org.hibernate.secure.Customer", value = "insert")
})
@TestForIssue( jiraKey = "HHH-11805" )
public class JaccIntegratorTest {
@BeforeEach
protected void afterEntityManagerFactoryBuilt(EntityManagerFactoryScope scope) {
scope.getEntityManagerFactory();
PolicyContextHandler policyContextHandler = new PolicyContextHandler() {
@Override
public Object getContext(String key, Object data) throws PolicyContextException {
Subject subject = new Subject( true, Collections.singleton(new java.security.Principal() {
@Override
public String getName() {
return "org.hibernate.secure.JaccIntegratorTest$Person";
}
@Override
public boolean implies(Subject subject) {
return true;
}
}), Collections.emptySet(), Collections.emptySet());
return subject;
}
@Override
public String[] getKeys() throws PolicyContextException {
return new String[0];
}
@Override
public boolean supports(String key) throws PolicyContextException {
return true;
}
};
try {
PolicyContext.registerHandler( "javax.security.auth.Subject.container", policyContextHandler, true);
}
catch (PolicyContextException e) {
fail(e.getMessage());
}
}
protected void setPolicy(boolean allow) {
Policy.setPolicy( new Policy() {
@Override
public Provider getProvider() {
return super.getProvider();
}
@Override
public String getType() {
return super.getType();
}
@Override
public Parameters getParameters() {
return super.getParameters();
}
@Override
public PermissionCollection getPermissions(CodeSource codesource) {
return super.getPermissions( codesource );
}
@Override
public PermissionCollection getPermissions(ProtectionDomain domain) {
return super.getPermissions( domain );
}
@Override
public boolean implies(ProtectionDomain domain, Permission permission) {
return allow;
}
@Override
public void refresh() {
super.refresh();
}
} );
}
@Test
public void testAllow(EntityManagerFactoryScope scope) {
setPolicy( true );
scope.inTransaction( entityManager -> {
Person person = new Person();
person.id = 1L;
person.name = "John Doe";
entityManager.persist( person );
} );
}
@Test
public void testDisallow(EntityManagerFactoryScope scope) {
setPolicy( false );
try {
scope.inTransaction( entityManager -> {
Person person = new Person();
person.id = 1L;
person.name = "John Doe";
entityManager.persist( person );
} );
fail("Should have thrown SecurityException");
}
catch (Exception e) {
assertTrue( e.getCause() instanceof SecurityException );
}
}
@Entity(name = "Person")
public static class Person {
@Id
private Long id;
private String name;
}
}

View File

@ -57,3 +57,8 @@ Multiple component mappings for the same java class with different property mapp
* Functions * Functions
* Multi-table bulk manipulation HQL/Criteria query handling * Multi-table bulk manipulation HQL/Criteria query handling
=== Removal
* JMX integration
* JACC integration