Unable to inject Bean properties in Spring Bean BasicDataSource - apache-camel

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!

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.

Configuring 2 database in mybatis + springs

I have an existing setup of mybatis + springs for working with Oracle DB. I have a set of java mapper interfaces, a set of corresponding mapper xmls (each having reference to their corresponding java mapper). I need to setup support for MSSQL also, but finding it hard to do that. I have created a separate set of xmls (specific to queries of MSSQL) in com/mycomp/mob/db/mappers/mssql.
Below is the extract of my applicationConext.xml (Here DBDataSource is an internal class which reads a config files to get all DB details).
<bean name="dataSource" class="com.mycomp.mob.core.db.DBDataSource">
<constructor-arg index="0" name="dbAlias" value="mob" />
<constructor-arg index="1" name="cfgSection" value="primary" />
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.mycomp.mob.db.mappers.oracle" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="typeAliasesPackage" value="com.mycomp.mob.db.mappers.oracle" />
<property name="configLocation" value="classpath:mybatis-config.xml" />
</bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
</bean>
Below is part of mybatis-config.xml (here ${} params are replaced using the earlier DBDatasource)
<configuration>
<typeAliases>
<package name="com.mycomp.mob.db.model" />
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/mycomp/mob/db/mappers/oracle/tenant.xml" />
<mapper resource="com/mycomp/mob/db/mappers/oracle/functionenty.xml" />
</mappers>
</configuration>
com.mycomp.mob.db.model contains POJO for tenant and functionentry.
Usage is as below :
ITenantMapper mappper = sqlSessionFactory.openSession().getMapper(ItenantMapper.class)
Tenant t = mapper.getTenant();
Now at a time only one DB (which is configured as primary in DB config file) will be used. So how to make sure that XML corresponding to that particular DB is invoked by the java mapper interface.
Also need to know can I configure same java mapper class name inside the mapper xmls of mssql ?
Is the flow used correct or I need to change the flow for supporting multiple databases.
Create two datasources and two SessionFactories in spring one for Oracle another for MSSQL.

cxf-rs-ws authorization under karaf

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

Spring Security:password encoding in DB and in applicationContext

Have config (applicationContext-security.xml):
<authentication-manager alias="authenticationManager">
<authentication-provider>
<password-encoder hash="sha"/>
<jdbc-user-service data-source-ref="dataSource"/>
</authentication-provider>
</authentication-manager>
from other side have SQLs from my dataSource(it's JdbcDaoImpl):
...
public static final String DEF_USERS_BY_USERNAME_QUERY =
"select username,password,enabled " +
"from users " +
"where username = ?";
...
There is now word about sha in this code,so password selected from standard Spring Security users table not encoded.
Perhaps, I should provide some sha attribute for password column in my hibernate mapping config here:
<class name="model.UserDetails" table="users">
<id name="id">
<generator class="increment"/>
</id>
<property name="username" column="username"/>
<property name="password" column="password"/>
<property name="enabled" column="enabled"/>
<property name="mail" column="mail"/>
<property name="city" column="city"/>
<property name="confirmed" column="confirmed"/>
<property name="confirmationCode" column="confirmation_code"/>
<set name="authorities" cascade="all" inverse="true">
<key column="id" not-null="true"/>
<one-to-many class="model.Authority"/>
</set>
</class>
For now password saved to DB as is,but should be encoded.
How to friend applicationContext config and DB queries to be the same password encoding?
If you are choosing a hashing system yourself, rather than building an app using an existing database which already contains hashed passwords, then you should make sure your hashing algorithm also uses a salt. Don't just use a plain digest.
A good choice is bcrypt, which we now support directly in Spring Security 3.1 via the BCryptPasswordEncoder (implemented using jBCrypt). This automatically generates a salt and concatenates it with the hash value in a single String.
Some databases have built-in support for hashing (e.g. Postgres). Otherwise, you need to hash the password yourself before passing it to JDBC:
String password = "plaintextPassword";
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String hashedPassword = passwordEncoder.encode(password);
That's all you need to do to encode the passwords when you create a user.
For authentication, you would use something like:
<bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
<bean id="authProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="yourJdbcUserService" />
<property name="passwordEncoder" ref="encoder" />
</bean>
A little more explanation on the accepted answer. Hope it helps someone.
Hash the password yourself before putting it to database:
String password = "plaintextPassword";
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String hashedPassword = passwordEncoder.encode(password);
Add BCryptPasswordEncoder bean to your security-config.xml
Add passwordEncoder as a property to Authentication Provider class. Autowire it or provide setter and getter methods.
#AutoWired
private BCryptPasswordEncoder passwordEncoder;
Get the property while you authendicate user for login
<bean id="dbAuthenticationProvider" class="mypackage.auth.spring.DBAuthenticationProvider" >
<property name="dataSource" ref="routingDataSource"></property>
<property name="passwordEncoder" ref="encoder" />
<property name="passwordQuery"
value="select password as password from tbl where username=:username">
</property>
</bean>
And in the authenticating class match both passwords
new BCryptPasswordEncoder().matches(plainTextPasswdFromUserInput, hashedPasswdFromDb)
In a simple way can you do something like in applicationContext-security.xml
<authentication-manager alias="authenticationManager">
<authentication-provider>
<password-encoder ref="encoder"/>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="
select username,password, enabled
from principal where username=?"
authorities-by-username-query="
select p.username, a.authority from principal p, authority a
where p.id = a.principal_id and p.username=?"
/>
</authentication-provider>
</authentication-manager>
<beans:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
In Java
public static String encodePasswordWithBCrypt(String plainPassword){
return new BCryptPasswordEncoder().encode(plainPassword);
}
Then test it
System.out.println(encodePasswordWithBCrypt("fsdfd"));
Using Spring Security 3.1, try this:
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="service">
<password-encoder hash="sha"/>
<jdbc-user-service data-source-ref="dataSource"/>
</authentication-provider>
</authentication-manager>
<beans:bean id="dataSource" ...>
...
</beans:bean>
<beans:bean id="service" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<beans:property name="dataSource" ref="dataSource"/>
...
</beans:bean>
What's new: authentication-provider points to service and service points to datasource.
Edit: In Java you will have to encode the password with something like this:
DigestUtils.sha(request.getParameter("password"));
Warn: Be careful! Do not mix SHA with MD5!
If you set the password-encoder of the authentication-provider as SHA, you need to encode in Java the same way to keep consistent. But if you enconde in Java as MD5, as the sample you found, do not forget to set the hash to "md5". DigestUtils also provides md5 encoder:
DigestUtils.md5(request.getParameter("password"));
Just a tip for doing it with annotations
#Configuration
#EnableWebSecurity
#PropertySource("classpath://configs.properties")
public class SecurityContextConfig extends WebSecurityConfigurerAdapter {
#Autowired
#Qualifier("userDetailsService")
private UserDetailsService userDetailsService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(getPasswordEncoder());
}
#Bean(name = "passwordEncoder")
public PasswordEncoder getPasswordEncoder(){
return new BCryptPasswordEncoder();
}
}
The accepted answer is right.
I tested it with spring 3.1 and BCrypt encode algorithm.
When create a user.
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
userEntity.setPassword(passwordEncoder.encode(userEntity.getPassword()));
userDao.save(userEntity);
When the user login, Remember, use the plain password (not hashed). just like:
Authentication request = new UsernamePasswordAuthenticationToken(user.getUserName(), user.getPassword());
Authentication result = authenticationManager.authenticate(request);
SecurityContextHolder.getContext().setAuthentication(result);
Here is security-config:
<bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
<bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userService" />
<property name="hideUserNotFoundExceptions" value="false" />
<property name="passwordEncoder" ref="encoder" />
</bean>
Hope it will help somebody!
with 3.1.x this mapping doesnt work for auth.
Working way is:
<beans:bean id='bCryptPasswordEncoder' class='org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder'></beans:bean>
<authentication-manager>
<authentication-provider user-service-ref="userDetailsService">
<password-encoder ref="bCryptPasswordEncoder"/>
</authentication-provider>
</authentication-manager>

Resources