Kundera / HBase / Spring: Timeout trying to initialize / update the schema - spring

I am using Spring boot to create a web service and want to persist my data model in HBase. I want to use Kundera for this task. However, I cannot get it to work. When spinning up the application, it starts up, freezes for about a minute and runs into a timeout. Here are some snippets of my configuration:
My persistence.xml:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="hbase_pu">
<provider>com.impetus.kundera.KunderaPersistence</provider>
<properties>
<property name="kundera.nodes" value="my-hbase-server.example.com"/>
<property name="kundera.port" value="2181"/>
<property name="kundera.keyspace" value="mykeyspace"/>
<property name="kundera.dialect" value="hbase"/>
<property name="kundera.client.lookup.class" value="com.impetus.client.hbase.HBaseClientFactory" />
<property name="kundera.ddl.auto.prepare" value="update"/>
</properties>
</persistence-unit>
</persistence>
My configuration for the entity manager:
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
final LocalContainerEntityManagerFactoryBean bean = new LocalContainerEntityManagerFactoryBean();
return bean;
}
When trying to run this, it seems to spin up okay:
... many info outputs ...
2014-12-10 09:07:05.682 INFO 5194 --- [ost-startStop-1] org.apache.zookeeper.ZooKeeper : Initiating client connection, connectString=my-hbase-server.example.com:2181 sessionTimeout=90000 watcher=hconnection-0x556effa0, quorum=my-hbase-server.example.com:2181, baseZNode=/hbase
2014-12-10 09:07:05.694 INFO 5194 --- [ne002.int:2181)] org.apache.zookeeper.ClientCnxn : Opening socket connection to server my-hbase-server.example.com/x.x.x.x:2181. Will not attempt to authenticate using SASL (unknown error)
2014-12-10 09:07:05.698 INFO 5194 --- [ne002.int:2181)] org.apache.zookeeper.ClientCnxn : Socket connection established to my-hbase-server.example.com/x.x.x.x:2181, initiating session
2014-12-10 09:07:05.780 INFO 5194 --- [ne002.int:2181)] org.apache.zookeeper.ClientCnxn : Session establishment complete on server my-hbase-server.example.com/x.x.x.x:2181, sessionid = 0x14a2e04a4ca001f, negotiated timeout = 40000
2014-12-10 09:07:05.820 INFO 5194 --- [ost-startStop-1] o.a.h.hbase.client.ZooKeeperRegistry : ClusterId read in ZooKeeper is null
Then, it freezes for about a minute, after that, it crashes:
2014-12-10 09:08:05.703 ERROR 5194 --- [ost-startStop-1] c.i.c.h.s.HBaseSchemaManager : Either check for network connection or table isn't in enabled state, Caused by:
... large stack trace, interesting section: ...
Caused by: org.apache.hadoop.hbase.client.RetriesExhaustedException: Can't get the locations
at org.apache.hadoop.hbase.client.RpcRetryingCallerWithReadReplicas.getRegionLocations(RpcRetryingCallerWithReadReplicas.java:301)
at org.apache.hadoop.hbase.client.ScannerCallableWithReplicas.call(ScannerCallableWithReplicas.java:131)
at org.apache.hadoop.hbase.client.ScannerCallableWithReplicas.call(ScannerCallableWithReplicas.java:56)
at org.apache.hadoop.hbase.client.RpcRetryingCaller.callWithoutRetries(RpcRetryingCaller.java:179)
at org.apache.hadoop.hbase.client.ClientScanner.call(ClientScanner.java:287)
at org.apache.hadoop.hbase.client.ClientScanner.nextScanner(ClientScanner.java:267)
at org.apache.hadoop.hbase.client.ClientScanner.initializeScannerInConstruction(ClientScanner.java:139)
at org.apache.hadoop.hbase.client.ClientScanner.<init>(ClientScanner.java:134)
at org.apache.hadoop.hbase.client.HTable.getScanner(HTable.java:763)
at org.apache.hadoop.hbase.client.MetaScanner.metaScan(MetaScanner.java:185)
at org.apache.hadoop.hbase.client.MetaScanner.metaScan(MetaScanner.java:86)
at org.apache.hadoop.hbase.client.ConnectionManager$HConnectionImplementation.isTableAvailable(ConnectionManager.java:919)
at org.apache.hadoop.hbase.client.HBaseAdmin.isTableAvailable(HBaseAdmin.java:1127)
at org.apache.hadoop.hbase.client.HBaseAdmin.isTableAvailable(HBaseAdmin.java:1135)
at com.impetus.client.hbase.schemamanager.HBaseSchemaManager.update(HBaseSchemaManager.java:100)
... 165 more
What is going wrong here? Did I miss anything, and if yes, what?

Turns out it has to do with Zookeeper. The entry point for hbase is hard-coded to /hbase, and the entry point of my server was different. But alas, Kundera seems to be incomplete, KunderaCriteriaQuery has many // TODO Auto-generated method stub and return null so unfortunately it is unusable for my task.

Related

Starting a simple WebSocket Server with Spring integration

I am trying to start a simple websocket server in a spring integration application.
I build my application thanks to the following dependancies :
dependencies {
compile("org.springframework.boot:spring-boot-starter-integration")
compile("org.springframework:spring-websocket")
compile("org.springframework.integration:spring-integration-ip")
compile("org.springframework.integration:spring-integration-websocket")
compile('com.fasterxml.jackson.core:jackson-databind')
compile("org.springframework.integration:spring-integration-feed")
}
I launch my application thanks to the following Java file :
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
org.springframework.integration.annotation.IntegrationComponentScan;
#Configuration
#EnableAutoConfiguration
#IntegrationComponentScan
public class Application {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext ctx = new SpringApplication("/integration.xml").run(args);
System.out.println("Hit Enter to terminate");
System.in.read();
ctx.close();
}
}
Here is my "integartion.xml" :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:file="http://www.springframework.org/schema/integration/file"
xmlns:feed="http://www.springframework.org/schema/integration/feed"
xmlns:int-ip="http://www.springframework.org/schema/integration/ip"
xmlns:ws="http://www.springframework.org/schema/integration/websocket"
xsi:schemaLocation="http://www.springframework.org/schema/integration/feed http://www.springframework.org/schema/integration/feed/spring-integration-feed.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/file http://www.springframework.org/schema/integration/file/spring-integration-file.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/ip http://www.springframework.org/schema/integration/ip/spring-integration-ip.xsd
http://www.springframework.org/schema/integration/websocket http://www.springframework.org/schema/integration/websocket/spring-integration-websocket.xsd">
<int-ip:udp-inbound-channel-adapter id="udpReceiver"
channel="udpOutChannel"
port="11111"
receive-buffer-size="500"
multicast="true"
multicast-address="225.6.7.8"/>
<int:object-to-string-transformer input-channel="udpOutChannel" output-channel="stringified"/>
<bean id="nmeaParser" class="transformers.NMEAParser"/>
<int:transformer input-channel="stringified" ref="nmeaParser" output-channel="parsedData"/>
<int:channel id="jsondata"/>
<int:object-to-json-transformer input-channel="parsedData" output-channel="jsondata"/>
<ws:server-container id="server" path="/position"/>
<ws:outbound-channel-adapter container="server" channel="jsondata"/>
</beans>
As you can see, I create an UDP inbound channel. This channels works like a charm. I am able to see that data are sucessfully passed to my "NMEAParser" bean.
I think that my Websocket server doesn't work because :
I can't connect to it with wscat... When I try to do :
wscat -c ws://127.0.0.1:8080/position
I receive a "CONNECTION REFUSED", the same message I receive when nothing is launched.
In the Spring log's I can read this :
Starting beans in phase 0
Adding {object-to-string-transformer} as a subscriber to the 'udpOutChannel' channel
Channel 'application:8080.udpOutChannel' has 1 subscriber(s).
started org.springframework.integration.config.ConsumerEndpointFactoryBean#0
Adding {transformer} as a subscriber to the 'stringified' channel
Channel 'application:8080.stringified' has 1 subscriber(s).
started org.springframework.integration.config.ConsumerEndpointFactoryBean#1
Adding {object-to-json-transformer} as a subscriber to the 'parsedData' channel
Channel 'application:8080.parsedData' has 1 subscriber(s).
started org.springframework.integration.config.ConsumerEndpointFactoryBean#2
Adding {websocket:outbound-channel-adapter} as a subscriber to the 'jsondata' channel
Channel 'application:8080.jsondata' has 1 subscriber(s).
started org.springframework.integration.config.ConsumerEndpointFactoryBean#3
Adding {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel
Channel 'application:8080.errorChannel' has 1 subscriber(s).
started _org.springframework.integration.errorLogger
Starting beans in phase 1073741823
started udpReceiver
Started Application in 0.792 seconds (JVM running for 1.121)
We can see here that all my beans are launched, except the bean "server" which is my server container. There is no trace of this bean in this log message.
To write my application I read carrefully this sampe and this doc.
What am I doing wrong, or what I forgot ?
As discussed in the chat after our lengthy comment back and forth, you need org.springframework.boot:spring-boot-starter-websocket in your dependencies, this will bring in spring-boot-starter-web and org.springframework.boot:spring-boot-starter-tomcat transitively, giving you a websocket runtime.

trap Spring context close error

I have a spring Integration project using spring-hadoop.
I have an Hbase template as follows,
<beans:bean id="fsh" class="org.springframework.data.hadoop.fs.FsShell">
</beans:bean>
<beans:bean id="hbaseTemplate"
class="org.springframework.data.hadoop.hbase.HbaseTemplate">
<beans:property name="configuration" ref="hdpConfiguration" />
</beans:bean>
Now, when I shutdown the app and the context at the end, it throws a strange error,
o.a.h.hbase.client.HConnectionManager : Connection not found in the list, can't delete it (connection key=HConnectionKey{properties={hbase.zookeeper.quorum=xxx.com,xxx.com, hbase.rpc.timeout=60000, hbase.client.prefetch.limit=10, hbase.zookeeper.property.clientPort=2181, zookeeper.znode.parent=/hbase-secure, hbase.client.retries.number=35, hbase.client.pause=100}, username='xyz#PQR.COM'}). May be the key was modified?
As I understand, this was an innocuous error and was thrown even in Hadoop 1.x
I have migrated to Hadoop 2.x and Spring-Hadoop-2.0.4
But now, spring throws an Exception which earlier was not thrown,
java.lang.Exception: null
at org.apache.hadoop.hbase.client.HConnectionManager.deleteConnection(HConnectionManager.java:488)
at org.apache.hadoop.hbase.client.HConnectionManager.deleteConnection(HConnectionManager.java:424)
at org.springframework.data.hadoop.hbase.HbaseConfigurationFactoryBean.destroy(HbaseConfigurationFactoryBean.java:80)
at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:258)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:578)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:554)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingleton(DefaultListableBeanFactory.java:907)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:523)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingletons(DefaultListableBeanFactory.java:914)
at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:908)
at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:884)
at org.springframework.context.support.AbstractApplicationContext$1.run(AbstractApplicationContext.java:804)
2015-01-22 14:58:20.168 INFO --- [ Thread-11] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService
2015-01-22 14:58:20.170 INFO --- [ Thread-11] o.s.s.c.ThreadPoolTaskScheduler : Shutting down ExecutorService 'taskScheduler'
2015-01-22 14:58:20.175 INFO --- [ Thread-2] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
Question, how can I trap this error so that it's not shown to the user...
Thanks for any insight.
I was able to resolve the error, simply by setting delete-connection to false, (default is 'true')
<hbase-configuration configration-ref="hdpConfiguration" delete-connection="false"/>

FailoverTransport instantiated multiple times

I'm using spring-jms version 3.0.5 and activeMQ version 4.5.2. When deployed to Tomcat, everything seems to work properly. When deployed to WebSphere, it appears that four separate failover transports are being insantiated, and my MessageListener implementation receives the same message four times for every message that gets published to my topic.
Here's my config:
<bean id="activeMQConnectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="failover://(tcp://server.com:12345,tcp://server2.com:12345)?randomize=false/>
</bean>
<bean id="topic" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg value="TOPIC.ONE" />
</bean>
<bean id="jmsTemplate" class="org.sprinframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory" />
<property name="defaultDestination" ref="topic" />
</bean>
<bean name="topicListener" class="com.foo.TopicListener" />
<jms:listener-container connection-factory="connectionFactory" cache="auto" destination-type="topic">
<jms:listener destination="topic" ref="topicListener" />
</jms:listener-container>
Here's my message listener:
import javax.jms.MessageListener;
import org.springframework.stereotype.Component;
#Component
public class TopicListener implements MessageListener {
public void onMessage(Message msg) {
log(msg);
}
}
And here's what I see in my logs (only on WebSphere)
11:59:59,764 () INFO (Thread-50) (DefaultLifecycleProcessor) Starting beans in phase 214783647
12:00:00,140 () INFO (ActiveMQ Task) (FailoverTransport) Successfully connected to tcp://server.com:12345
12:00:00,253 () INFO (ActiveMQ Task) (FailoverTransport) Successfully connected to tcp://server.com:12345
12:00:00,342 () INFO (ActiveMQ Task) (FailoverTransport) Successfully connected to tcp://server.com:12345
12:00:00,423 () INFO (ActiveMQ Task) (FailoverTransport) Successfully connected to tcp://server.com:12345
12:00:00,492 () INFO (Thread-50) (ContextLoader) Root WebApplicationContext: initialization completed in 100239 ms
And then once I publish to the topic, I see:
12:01:00,250 () INFO (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) (TopicListener) logging message
12:01:00,251 () INFO (org.springframework.jms.listener.DefaultMessageListenerContainer#3-1) (TopicListener) logging message
12:01:00,251 () INFO (org.springframework.jms.listener.DefaultMessageListenerContainer#2-1) (TopicListener) logging message
12:01:00,275 () INFO (org.springframework.jms.listener.DefaultMessageListenerContainer#1-1) (TopicListener) logging message
I've seen some indication that this sort of behavior might be expected if I'd set concurrentConsumers > 1, but as far as I can tell, I haven't. How can I make sure I'm only receiving these messages once?
UPDATE:
With debug logging on, I also see:
2012-10-28 12:00:00,000 () DEBUG (Thread-50) (DefaultLifecycleProcessor) Starting bean 'org.springframework.jms.listener.DefaultMessageListenerContainer#0' of type [class org.springframework.jms.listener.DefaultMessageListenerContainer]
2012-10-28 12:00:00,011 () DEBUG (Thread-50) (DefaultLifecycleProcessor) Starting bean 'org.springframework.jms.listener.DefaultMessageListenerContainer#1' of type [class org.springframework.jms.listener.DefaultMessageListenerContainer]
2012-10-28 12:00:00,021 () DEBUG (Thread-50) (DefaultLifecycleProcessor) Starting bean 'org.springframework.jms.listener.DefaultMessageListenerContainer#2' of type [class org.springframework.jms.listener.DefaultMessageListenerContainer]
2012-10-28 12:00:00,029 () DEBUG (Thread-50) (DefaultLifecycleProcessor) Starting bean 'org.springframework.jms.listener.DefaultMessageListenerContainer#3' of type [class org.springframework.jms.listener.DefaultMessageListenerContainer]
Why would Spring create four of these beans?

Persistence unit not finding managed entity

#PersistenceContext entity manager cannot find an/any entity class which it appeared to have processed during container launch.
During persistence unit setup, it appears that the container finds and registers the entity:
2012-05-17 15:28:21,978 INFO [org.hibernate.cfg.annotations.Version] (main) Hibernate Annotations 3.4.0.GA
2012-05-17 15:28:21,997 INFO [org.hibernate.annotations.common.Version] (main) Hibernate Commons Annotations 3.1.0.GA
2012-05-17 15:28:22,004 INFO [org.hibernate.ejb.Version] (main) Hibernate EntityManager 3.4.0.GA
2012-05-17 15:28:22,039 INFO [org.hibernate.ejb.Ejb3Configuration] (main) Processing
PersistenceUnitInfo [
name: dashboardPu
...]
2012-05-17 15:28:22,069 WARN [org.hibernate.ejb.Ejb3Configuration] (main) Persistence provider caller does not implement the EJB3 spec correctly. PersistenceUnitInfo.getNewTempClassLoader() is null.
2012-05-17 15:28:22,146 INFO [org.hibernate.cfg.AnnotationBinder] (main) Binding entity from annotated class: scholastic.dashboard.dto.ReportRequest
2012-05-17 15:28:22,161 INFO [org.hibernate.cfg.annotations.QueryBinder] (main) Binding Named query: ReportRequest.getReportsByUser => from ReportRequest where userId = :userId
However, the later attempt to use that entity fails. I've verified that the entitymanager is indeed using dashboardPu (there are 3 persistence units in this ear) by dropping into the debugger and looking through the entitymanager>factory>persistenceUnit.
2012-05-17 15:28:54,730 DEBUG [org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter] (http-127.0.0.1-8080-2) Opening JPA EntityManager in OpenEntityManagerInViewFilter
2012-05-17 15:28:54,731 DEBUG [org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter] (http-127.0.0.1-8080-1) Using EntityManagerFactory 'dashboardEntityManagerFactory' for OpenEntityManagerInViewFilter
2012-05-17 15:28:54,731 DEBUG [org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter] (http-127.0.0.1-8080-1) Opening JPA EntityManager in OpenEntityManagerInViewFilter
2012-05-17 15:28:54,775 DEBUG [scholastic.dashboard.dao.ReportRequestDao] (http-127.0.0.1-8080-2) Get reports for secretuserid
2012-05-17 15:28:54,797 WARN [org.hibernate.hql.QuerySplitter] (http-127.0.0.1-8080-2) no persistent classes found for query class: from scholastic.dashboard.dto.ReportRequest where user_id = secretuserid
I got here by first having it fail to find the "ReportRequest.getReportsByUser" query using em.createNamedQuery(), then trying a query w/o using the full path name to the entity class from ReportRequest where userId = :userId, and then the query in the last code block line above.
Using JBoss 5.1, JPA 2, Hibernate 3.3 or 3.6, Spring 3.0.5.
Code snippets:
#Entity
#Table(name="td_report_request")
#NamedQueries({
#NamedQuery(name=ReportRequestDao.GET_REPORTS_BY_USER,
query="from ReportRequest where userId = :userId"),
})
public class ReportRequest extends SlmsGuidAbstract {...}
...
#Repository
public class ReportRequestDao {
#PersistenceContext
private EntityManager em;
public List<ReportRequest> getReportRequests(String userId) {
// TODO uncomment this line and remove the one after when we go to JBoss >= 6
// TypedQuery<ReportRequest> query = em.createNamedQuery(GET_REPORTS_BY_USER, ReportRequest.class);
// Query query = em.createNamedQuery(GET_REPORTS_BY_USER);
Query query = em.createQuery("from scholastic.dashboard.dto.ReportRequest where user_id = " + userId);
...
<bean id="dashboardEntityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="lycea.ds.jndi-MySqlDS" />
<property name="persistenceUnitName" value="dashboardPu"/>
</bean>
...
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="dashboardPu" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/MySqlDS</jta-data-source>
<properties>
<property name="jboss.entity.manager.factory.jndi.name" value="java:/dashboardPu"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="hibernate.query.factory_class" value="org.hibernate.hql.ast.ASTQueryTranslatorFactory"/>
<property name="hibernate.connection.release_mode" value="auto"/>
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup" />
<property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>
</persistence>
Try adding annotated jpa class in persistance.xml inside tag <class/>

PreAuthorize doesn't work

I'm writing a socket server (no web-application !) application and want to use method-based security to handle my ACL needs. i followed a small tutorial i found spring security by example
so far i configured:
<security:global-method-security pre-post-annotations="enabled">
<security:expression-handler ref="expressionHandler" />
</security:global-method-security>
<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<property name="permissionEvaluator">
<bean id="permissionEvaluator" class="myPermissionEvaluator" />
</property>
</bean>
<security:authentication-manager id="authenticationmanager">
<security:authentication-provider ref="authenticationprovider" />
</security:authentication-manager>
<bean id="authenticationprovider" class="myAuthenticationProvider" />
With a service bean:
#Named
public class ChannelService {
#PreAuthorize("isAuthenticated() and hasPermission(#channel, 'CHANNEL_WRITE')")
public void writeMessage(Channel channel, String message) { ... }
}
Everything compiles and the application starts and works fine, but without access control. My debug log shows that my Evaluator is never called.
When i tried something similar with a #Secured annotation the annotation was evaluated and access was denied. but simple role based security isn't enough for my requirements.
EDIT
did some more tests: when i configure only secured-annotations="enabled" the role based security works. when configure pre-post-annotations="enabled" in ADDITION neither secured nor preauthorize works. when i configure only pre-post-annotations it still doesn't work.
EDIT2
some more tests:
with only secured_annotations="enabled" the call to my channelservice goes through the Cglib2AopProxy
as soon as i activate pre-post-annotations the call lands directly in the channelservice. no interceptor, no proxy, nothing.
I'm getting kind of desperate...
EDIT3
I debug-logged my testruns here is the part for spring-security
with only secured-annotations="enabled"
2012-04-12 13:36:46,171 INFO [main] o.s.s.c.SpringSecurityCoreVersion - You are running with Spring Security Core 3.1.0.RELEASE
2012-04-12 13:36:46,174 INFO [main] o.s.s.c.SecurityNamespaceHandler - Spring Security 'config' module version is 3.1.0.RELEASE
2012-04-12 13:36:49,042 DEBUG [main] o.s.s.a.m.DelegatingMethodSecurityMetadataSource - Caching method [CacheKey[mystuff.UserService; public void mystuff.UserService.serverBan(java.lang.String,mystuff.models.User,org.joda.time.DateTime)]] with attributes [user]
2012-04-12 13:36:49,138 DEBUG [main] o.s.s.a.i.a.MethodSecurityInterceptor - Validated configuration attributes
2012-04-12 13:36:49,221 DEBUG [main] o.s.s.a.m.DelegatingMethodSecurityMetadataSource - Caching method [CacheKey[mystuff.ChannelService; public void mystuff.ChannelService.writeMessage(mystuff.models.Channel,java.lang.String)]] with attributes [blubb]
2012-04-12 13:36:51,159 DEBUG [main] o.s.s.a.ProviderManager - Authentication attempt using mystuff.GlobalchatAuthenticationProvider
2012-04-12 13:36:56,166 DEBUG [Timer-1] o.s.s.a.ProviderManager - Authentication attempt using mystuff.GlobalchatAuthenticationProvider
2012-04-12 13:36:56,183 DEBUG [Timer-1] o.s.s.a.i.a.MethodSecurityInterceptor - Secure object: ReflectiveMethodInvocation: public void mystuff.ChannelService.writeMessage(mystuff.models.Channel,java.lang.String); target is of class [mystuff.ChannelService]; Attributes: [blubb]
2012-04-12 13:36:56,184 DEBUG [Timer-1] o.s.s.a.i.a.MethodSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken#312e8aef: Principal: mystuff.UserId#ced1752b; Credentials: [PROTECTED]; Authenticated: true; Details: null; Not granted any authorities
Exception in thread "Timer-1" org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AbstractAccessDecisionManager.checkAllowIfAllAbstainDecisions(AbstractAccessDecisionManager.java:70)
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:88)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:205)
at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:59)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)
at mystuff.ChannelService$$EnhancerByCGLIB$$3ad5e57f.writeMessage(<generated>)
at mystuff.run(DataGenerator.java:109)
at java.util.TimerThread.mainLoop(Timer.java:512)
at java.util.TimerThread.run(Timer.java:462)
2012-04-12 13:36:56,185 DEBUG [Timer-1] o.s.s.access.vote.AffirmativeBased - Voter: org.springframework.security.access.vote.RoleVoter#1cfe174, returned: 0
2012-04-12 13:36:56,185 DEBUG [Timer-1] o.s.s.access.vote.AffirmativeBased - Voter: org.springframework.security.access.vote.AuthenticatedVoter#da89a7, returned: 0
with pre-post-annotations="enabled"
2012-04-12 13:39:54,926 INFO [main] o.s.s.c.SpringSecurityCoreVersion - You are running with Spring Security Core 3.1.0.RELEASE
2012-04-12 13:39:54,929 INFO [main] o.s.s.c.SecurityNamespaceHandler - Spring Security 'config' module version is 3.1.0.RELEASE
2012-04-12 13:39:54,989 INFO [main] o.s.s.c.m.GlobalMethodSecurityBeanDefinitionParser - Using bean 'expressionHandler' as method ExpressionHandler implementation
2012-04-12 13:39:59,812 DEBUG [main] o.s.s.a.ProviderManager - Authentication attempt mystuff.GlobalchatAuthenticationProvider
2012-04-12 13:39:59,850 DEBUG [main] o.s.s.a.i.a.MethodSecurityInterceptor - Validated configuration attributes
As far as i understand this log output spring doesn't realize my beans need to be proxied, so they aren't and so i don't get security.
EDIT4
I debug-logged the complete sprint startup... (thats one big log) and there i find:
2012-04-12 14:40:41,385 INFO [main] o.s.c.s.ClassPathXmlApplicationContext - Bean 'channelService' of type [class mystuff.ChannelService] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
is there a way to figure out why? because as far as i understand it. because of #preauthorize the bean should be eligible. with only secured-annotations="enabled" i get a post processing log.
This configuration worked just as expected for me:
<bean id="securityExpressionHandler"
class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler" />
<bean id="preInvocationAdvice"
class="org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice"
p:expressionHandler-ref="securityExpressionHandler" />
<util:list id="decisionVoters">
<bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
<bean class="org.springframework.security.access.vote.RoleVoter" />
<bean class="org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter"
c:pre-ref="preInvocationAdvice" />
</util:list>
<bean id="accessDecisionManager"
class="org.springframework.security.access.vote.UnanimousBased"
c:decisionVoters-ref="decisionVoters" />
<sec:global-method-security
authentication-manager-ref="authenticationManager"
access-decision-manager-ref="accessDecisionManager"
pre-post-annotations="enabled" />
I got the log message:
WARN org.springframework.security.access.expression.DenyAllPermissionEvaluator -
Denying user jack permission 'CHANNEL_WRITE' on object Channel[ name=null ]
And an exception:
org.springframework.security.access.AccessDeniedException: Access is denied
From a simple test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:META-INF/spring/application-context.xml")
public class SpringSecurityPrePostTest {
#Autowired
ChannelService channelService;
#Test
public void shouldSecureService() throws Exception {
Authentication authentication = new UsernamePasswordAuthenticationToken("jack", "sparrow");
SecurityContext securityContext = SecurityContextHolder.getContext();
securityContext.setAuthentication(authentication);
channelService.writeMessage(new Channel(), "test");
}
}
One thing I did diffrent was to use interface on a service and JDK proxies instead of cglib:
public interface ChannelService {
void writeMessage(Channel channel, String message);
}
and:
#Component
public class ChannelServiceImpl implements ChannelService {
private static final Logger LOG = LoggerFactory.getLogger(ChannelServiceImpl.class);
#Override
#PreAuthorize("isAuthenticated() and hasPermission(#channel, 'CHANNEL_WRITE')")
public void writeMessage(Channel channel, String message) {
LOG.info("Writing message {} to: {}" , message, channel);
}
}
UPDATE1:
With this simplified config I get the same result:
<bean id="securityExpressionHandler"
class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler" />
<sec:global-method-security
authentication-manager-ref="authenticationManager"
pre-post-annotations="enabled">
<sec:expression-handler ref="securityExpressionHandler" />
</sec:global-method-security>
UPDATE2:
The debug message from Edit4 indicates that channelService may not have bean proxied at all as it got classified as not eligible for auto-proxying. This qiestion answers similar problem - try not to use #Autowired or any other mechanism based on BeanPostProcessors to set up the beans involved in security checks (i.e. myPermissionEvaluator).
UPDATE3:
You cannot use secured resources (i.e. services) within beans responsible for security checks! This creates a dependency loop and is a error in Your configuration. You must use lover level access (i.e. DAO) to check permissions, anything that is not secured! Implementing security checks using secured resources is not what You want to do.
If despite using not secured resources with #Autowired things don't work as expected, try using old-school XML confiuration style for all beans involved in security checks. Also remember that <context:component-scan /> is in fact a BeanDefinitionRegistryPostProcessor and introduces the scanned beans into the BeanFactory after all the ones declared in XML are already there.
it works,
make sure that you have <sec:global-method-security pre-post-annotations="enabled"/> in your spring servlet (ie where you may have your <mvc:annotation-driven/>)
"sec" is from xmlns:sec="http://www.springframework.org/schema/security"

Resources