cxf-rs-ws authorization under karaf - cxf

I'm trying to configure a cxf soap webservice with authorization and authentication to be deployed on Servicemix.
I configured the LDAP authentication module as follows:
<!-- Bean to allow the $[karaf.base] property to be correctly resolved -->
<ext:property-placeholder placeholder-prefix="$[" placeholder-suffix="]"/>
<jaas:config name="myRealm">
<jaas:module className="org.apache.karaf.jaas.modules.ldap.LDAPLoginModule" flags="required">
connection.url = ldap://srv-ldap:389
user.base.dn = ou=people,dc=intranet,dc=company,dc=com
user.filter = (uid=%u)
user.search.subtree = false
role.base.dn = ou=groups,dc=intranet,dc=company,dc=com
role.filter = (member:=uid=%u,ou=people,dc=intranet,dc=company,dc=com)
role.name.attribute = cn
role.search.subtree = true
authentication = simple
</jaas:module>
</jaas:config>
<service interface="org.apache.karaf.jaas.modules.BackingEngineFactory">
<bean class="org.apache.karaf.jaas.modules.properties.PropertiesBackingEngineFactory"/>
</service>
And here is the beans.xml file
<jaxws:endpoint id="myService"
implementor="com.myorg.services.impl.MyServiceWSImpl"
address="/myService">
<jaxws:inInterceptors>
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<constructor-arg>
<map>
<entry key="action" value="UsernameToken" />
<entry key="passwordType" value="PasswordText" />
</map>
</constructor-arg>
</bean>
<ref bean="authenticationInterceptor" />
<ref bean="authorizationInterceptor" />
</jaxws:inInterceptors>
<jaxws:properties>
<entry key="ws-security.validate.token" value="false" />
</jaxws:properties>
</jaxws:endpoint>
<bean id="authenticationInterceptor"
class="org.apache.cxf.interceptor.security.JAASLoginInterceptor">
<property name="contextName" value="myRealm" />
</bean>
<bean id="authorizationInterceptor"
class="org.apache.cxf.interceptor.security.SecureAnnotationsInterceptor">
<property name="securedObject" ref="securedBean"/>
</bean>
Finally, in my WebService implementation I annotated a method with #RolesAllowed.
#RolesAllowed("Role1")
public Department get(String name) throws IdMException {
return service.get(name);
}
The authentication interceptor is retrieving the user, authenticating it and retrieving the groups as RolePrincipal instances.
Then, in the authorization interceptor (SecureAnnotationsInterceptor), the method configuration is read, the expectedRoles are "Role1", but the SimpleAuthorizingInterceptor.isUserInRole method returns false.
I haven't found any example trying to do more or less the same and the few information I found was from the CXF documentation page http://cxf.apache.org/docs/security.html#Security-Authorization
I have to be missing something important, hope somebody could help me.
Thanks in advance and kind regards.

Your problem is because of Karaf's RolePricipal do not implements Group as CXF expected. Instead of it, it implements Pricipal so CXF thinks that 1st role name is a username. That is why "SimpleAuthorizingInterceptor.isUserInRole method returns false".
A solution is to wait for fixed versions of CXF (2.7.11 and 3.0.0).
If not possible to update to newer version, then an odd and temporary solution (simply workaround) is to add more than one role to a user in LDAP and to method.
You can find more about that bug here: CXF-5603

Related

Hybris interceptor is not getting triggered

I create ValidateInterceptor in below path and created bean in custombackoffice-backoffice-spring.xml
C:\hybris\bin\custom\custombackoffice\backoffice\src\com\custom\backoffice\interceptor\CustomAppeasementUserValidateInterceptor.java
bean is as below
<bean id="customAppeasementUserValidateInterceptor" class="de.hybris.platform.servicelayer.interceptor.impl.InterceptorMapping">
<property name="interceptor" ref="customAppeasementUserValidateInterceptor" />
<property name="typeCode" value="Appeasement" />
</bean>
when I modify particular model in backoffice and click on the save button, debugger never goes to interceptor it directly saves the model.
NOTE :- I can't write this interceptor in customcore because we can not import below services in custom core
import com.hybris.cockpitng.core.user.AuthorityGroupService;
import com.hybris.cockpitng.core.user.impl.AuthorityGroup;
Why the interceptor is not getting triggered?
The bean-id and the mapper bean-id are the same. Change either one. Ideally, it should be like-
<bean id="customAppeasementUserValidateInterceptorMapping" class="de.hybris.platform.servicelayer.interceptor.impl.InterceptorMapping">
<property name="interceptor" ref="customAppeasementUserValidateInterceptor" />
<property name="typeCode" value="Appeasement" />
</bean>
Notice the new id for the mapping bean i.e. customAppeasementUserValidateInterceptorMapping.

QPID Connection factory properties

My system is based on camel and use Apache QPID 0.37.0 to consume messages from a remote AMQPS sever. Our system authenticates via a client certificate. Thus I have this piece of configuration:
<bean id="jmsConnectionFactory" class="org.apache.qpid.jms.JmsConnectionFactory">
<constructor-arg name="remoteURI" value="amqps://some-location:5671?transport.keyStoreLocation=/very/long/path/nnn-openssl.p12&transport.keyStorePassword=*******&transport.trustStoreLocation=/very/long/path/server.keystore&transport.trustStorePassword=*******"/>
</bean>
This is just working fine. However, configuring key/trust store this way (i.e. in the URI) has several drawbacks:
First, it is not easy to read and maintain.
Some components log the URI, so the paths (I can live with it) and the passwords (ouch...) get logged.
I know it's possible to configure via a system property (javax.net.ssl.keyStore, and son on), but it's not an option because different modules may use different key and trust store, and we want to keep them in separate files.
Is there a way to configure those transport properties of JmsConnectionFactory in a different way ?
Something like:
<bean id="jmsConnectionFactory" class="org.apache.qpid.jms.JmsConnectionFactory">
<constructor-arg name="remoteURI" value="amqps://some-location:5671"/>
<property name="transport.keyStoreLocation" value="/very/long/path/nnn-openssl.p12"/>
...
</bean>
Note that this factory is used in a JMSConfig, which in turn is used within an AMQPComponent:
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration" >
<property name="connectionFactory" ref="jmsConnectionFactory" />
...
</bean>
<bean id="amqp" class="org.apache.camel.component.amqp.AMQPComponent">
<property name="testConnectionOnStartup" value="true"/>
<property name="configuration" ref="jmsConfig" />
...
</bean>
The short answer is no, that's all that class supports. However you could write a configuration bean which has the properties you require, and have that create the bean. Off the top of my head, something like this:
#Configuration
public class QpidConfiguration {
// Add setters for these
private String host;
private int port = 5671;
private String keyStore;
private String keyStorePassword;
private String trustStoreLocation;
private String trustStorePassword;
#Bean
public JmsConnectionFactory createConnectionFactory() {
return new JmsConnectionFactory("amqps://" + host" + ":" + port + "?transport.keyStoreLocation=" + keyStoreLocation + "&transport.keyStorePassword=" + keyStorePassword + "&transport.trustStoreLocation=" + trustStoreLocation + "&transport.trustStorePassword=" + trustStorePassword);
}
}
You probably want to add some parameter validation in there to be safe.
You can then define the bean using more convenient properties.
<bean id="jmsConnectionFactory" class="com.example.QpidConfiguration">
<property name="host" value="some-location"/>
<property name="keyStoreLocation" value="/very/long/path/nnn-openssl.p12"/>
...
</bean>
You can also leverage encrypted property placeholders, if your heart so desires.

Unable to inject Bean properties in Spring Bean BasicDataSource

I'm trying to use in the BasicDataSource the username and password as derived from a Bean class:
<bean class="org.apache.commons.dbcp.BasicDataSource" id="myDataSource">
<property name="driverClassName" value="org.teiid.jdbc.TeiidDriver"/>
<property name="url" value="jdbc:myurl"/>
<property name="username" value="${bean:quickstartConfiguration?method=getQueueUsername}"/>
<property name="password" value="${bean:quickstartConfiguration?method=getQueuePassword}"/>
<property name="maxIdle" value="1"/>
</bean>
In my project I have a Bean class named QuickStartConfiguration with methods getQueueUser and getQueuePassword.
Unfortunately, when the route gets instantiated, it seems that the username and password is not parsed:
The username "quickstartConfiguration?method=getQueueUsername" and/or password and/or payload token could not be authenticated by security domain ldap-security.)
What is weird is that however using the log component, I'm able to retrieve the actual value from the Bean:
<log id="async-queue-cred-log" message="----> Using username '${bean:quickstartConfiguration?method=getQueueUsername}' for the async queue"/>
Is there any limitation in the BasicDataSource class which prevents from evaluate the Bean expression?
Thanks!

"org.hibernate.HibernateException: No Session found for current thread" even when method is wrapped in proxy

I'm getting following error:
org.hibernate.HibernateException: No Session found for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:106)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1014)
at com.test.serviceimpl.EbayCredentialImpl.getCredential(EbayCredentialImpl.java:22)
at com.test.serviceimpl.EbayCredentialImpl$$FastClassBySpringCGLIB$$3f81c256.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:708)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)
at com.test.serviceimpl.EbayCredentialImpl$$EnhancerBySpringCGLIB$$a9d77df8.getCredential(<generated>)
at com.test.jobs.EbayJob_FetchOrders.fetchAndUpdateOrders_Execute(EbayJob_FetchOrders.java:64)
at com.test.jobs.EbayJob_FetchOrders.execute(EbayJob_FetchOrders.java:48)
at org.quartz.core.JobRunShell.run(JobRunShell.java:213)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:557)
related spring configs:
<bean id="hibernateSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <!-- annotation.AnnotationSessionFactoryBean -->
<property name="dataSource" ref="mysqlDataSource" />
......
with NO hibernate.current_session_context_class.
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="hibernateSessionFactory"/>
</bean>
<tx:advice id="transactionInterceptor" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRES_NEW" rollback-for="Throwable"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:advisor pointcut="execution(* com.test.jobs.*.*Job*.*_Execute(..))" advice-ref="transactionInterceptor"/>
</aop:config>
As you can see, the method is wrapped in proxy, still no session found!
The method is run by a scheduler's job, not a controller method, it gets daos etc from spring context. the transaction etc is working good on controller methods, where i'm using #transactional.
Versions: hibernate-4.3.5, spring-4.0.4
Any clue is appreciated.
if you are going to configure your transaction manager as annotation-driven you dont need code below
<tx:advice id="transactionInterceptor" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRES_NEW" rollback-for="Throwable"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:advisor pointcut="execution(* com.test.jobs.*.*Job*.*_Execute(..))" advice-ref="transactionInterceptor"/>
</aop:config>
just #Transactional(propagation= Propagation.REQUIRES_NEW) will handle it with
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="hibernateSessionFactory"/>
</bean>
However i think you can set (propagation= Propagation.REQUIRES_NEW) only at function level as
#Service
public class SomeService{
#Autowired
private DataSource dataSource;
#Transactional(propagation=Propagation.REQUIRES_NEW)
public void useDataSource() {
//save record
}
}

How to make CXF SOAP Request to be printed under log file

#InInterceptors(interceptors = "org.apache.cxf.interceptor.LoggingInInterceptor" )
#OutInterceptors(interceptors = "org.apache.cxf.interceptor.LoggingOutInterceptor")
public class SKTWeb implements SKTWebService {
// method logic goes here
}
Hi , after adding these two lines inside the CXF Method Implementation .
I could get whip of SOAP Requestand Response under tomcat server console
see a instance of SOAP Request Printed under Tomcat console
INFO: Inbound Message
----------------------------
ID: 1
Address: /Sktweb-33.0/services/SKTWeb
Encoding: UTF-8
Content-Type: text/xml; charset=UTF-8
Headers: {cache-control=[no-cache], content-type=[text/xml; charset=UTF-8], connection=[keep-alive], host=[local
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns4:strategy xmlns:ns
Could anybody please tell me how can get this inside my Log file (Log4j)
Currently this is my log4j.properties file
log4j.rootCategory=INFO, A1
# A1 is a DailyRollingFileAppender
log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender
log4j.appender.A1.file=/Haieeee.log
log4j.appender.A1.datePattern='.'yyyy-MM-dd
log4j.appender.A1.append=true
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-22d{dd/MMM/yyyy HH:mm:ss} - %m%n
And also i have META-INF\cxf\org\apache\cxf\Logger Log4jLogger.class inside the Web Application .
And also i kept
<cxf:bus>
<cxf:features>
<cxf:logging/>
</cxf:features>
</cxf:bus>
Inside the endpoints.xml file
Any help please
A slight bit of confusion it seems. You need your assembled application to have a locatable file META-INF/cxf/org.apache.cxf.Logger (yes, those are dots! It's not a .java or .class file) and it should have the contents:
org.apache.cxf.common.logging.Log4jLogger
I use exactly the above in my code and it works like a charm. (I don't use it with the message logging feature though; too much traffic when deployed for my tasteā€¦)
Basically you want your properties file to be picked by CXF then it use this properties file instead of CXF's.
I am using spring configuration in my CXF application. If you are not using any Spring config then you create a new config and load it on start up using spring context listener, then you can add the below code in your XML file.
<bean id="log4jInitialization"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="org.springframework.util.Log4jConfigurer" />
<property name="targetMethod" value="initLogging" />
<property name="arguments">
<list>
<value>file:fullpath/filename.properties</value>
</list>
</property>
</bean>
You can also have classpath:filename.properties in the <list> </list>. The logging implemented in Spring framework will be used to log all the request and response. You can also use the same logging implementation to use in your application.
Always go with interceptors...Add slf4j-log4j12-1.6.1.jar,slf4j-api-1.6.1.jar and commons-logging-1.1.1.jar. Paste the following code in your cxf.xml...
<bean class="org.apache.cxf.interceptor.LoggingInInterceptor" id="loggingInInterceptor" />
<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" id="logOutInterceptor" />
<cxf:bus>
<cxf:inInterceptors>
<ref bean="loggingInInterceptor" />
</cxf:inInterceptors>
<cxf:outInterceptors>
<ref bean="logOutInterceptor" />
</cxf:outInterceptors>
</cxf:bus>

Resources