Spring Data mongodb: how to add credentials when running a replica set - mongodb

I'm running MongoDB 2.2. I can add credentials to access my single instance MongoDB like this:
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<property name="writeResultChecking" value="EXCEPTION"/>
<property name="writeConcern" value="FSYNC_SAFE"/>
<constructor-arg ref="myRs"/>
<constructor-arg name="databaseName" value="mydb"/>
<constructor-arg name="userCredentials" ref="userCredentials"/>
</bean>
<bean id="userCredentials" class="org.springframework.data.authentication.UserCredentials">
<constructor-arg name="username" value="username" />
<constructor-arg name="password" value="password" />
</bean>
but the docs say that only keyfile authentication is available for replica sets:
http://docs.mongodb.org/v2.2/administration/replica-sets/#replica-set-security
How can I use DB credentials preferrably (or even a keyfile) in the app context XML file so I can authenticate to the MongoDB replica set when using Spring Data MongoDB?
Thanks.

--keyfile option enables key based authentication between replicaset members. It has no effect the communication between your application and the replicaset.
You need to add a user to the database. Make sure you are connected to Primary.
$ mongo
PRIMARY> use the_database_i_want_to_be_authenticated
switched to db the_database_i_want_to_be_authenticated
PRIMARY> db.addUser("myusername","mypassword")
{
"user" : "myusername",
"readOnly" : false,
"pwd" : "a6de521abefc2fed4f5876855a3484f5",
"_id" : ObjectId("5194932444ef978a730c22d4")
}
After you created a user in the database, you will be able to connect it with the following
<bean id="userCredentials" class="org.springframework.data.authentication.UserCredentials">
<constructor-arg name="username" value="username" />
<constructor-arg name="password" value="password" />
</bean>

Related

spring-social Facebook login doesn't set Authentication object

I'm using Facebook login to authenticate in my application. I use the authentication filter.
The authentication goes OK, but when it redirects back to homepage the filter doesn't seem to set the Authentication object, so calling SecurityContextHolder.getContext().getAuthentication() returns null. This only happens the first time when the user authorizes our app. It doesn't happen after that.
Currently to get the Authentication object set, the user has to 'login with facebook' twice. The second time it doesn't actually do any logins, the filter looks like it's picking up the cookie and does the authentication and doesn't even need to go to Facebook anymore.
So my question is why do I need to go through the filter twice? Or how can I avoid that?
Configuration looks like this:
<bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<constructor-arg value="/login"/>
<property name="useForward" value="true"/>
</bean>
<bean class="com.gigi.web.SpringDataUserDetailsService" id="userService"/>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider user-service-ref="userService"/>
<security:authentication-provider ref="socialAuthenticationProvider" />
</security:authentication-manager>
<bean class="org.springframework.social.security.SocialAuthenticationFilter" id="socialAuthenticationFilter">
<constructor-arg ref="authenticationManager" />
<constructor-arg ref="userIdSource" />
<constructor-arg ref="usersConnectionRepository" />
<constructor-arg ref="connectionRegistry" />
<property name="postLoginUrl" value="/home" />
<property name="defaultFailureUrl" value="/login?error&social" />
<property name="signupUrl" value="/user/signup" />
</bean>
<bean class="org.springframework.social.connect.web.ProviderSignInUtils">
<constructor-arg ref="connectionRegistry"/>
<constructor-arg ref="usersConnectionRepository"/>
</bean>
<bean id="userIdSource" class="org.springframework.social.security.AuthenticationNameUserIdSource" />
<bean id="socialAuthenticationProvider"
class="org.springframework.social.security.SocialAuthenticationProvider">
<constructor-arg ref="usersConnectionRepository" />
<constructor-arg ref="userService" />
</bean>
<bean id="userSocialConnectionService" class="com.gigi.web.UserSocialConnectionController"></bean>
<bean id="usersConnectionRepository" class="com.gigi.social.SpringDataUsersConnectionRepository">
<constructor-arg ref="connectionRegistry" />
</bean>
<bean id="connectionRegistry"
class="org.springframework.social.security.SocialAuthenticationServiceRegistry">
<property name="authenticationServices">
<list>
<bean class="org.springframework.social.facebook.security.FacebookAuthenticationService">
<constructor-arg value="${facebook.app.id}" />
<constructor-arg value="${facebook.app.secret}" />
<constructor-arg value="${facebook.app.namespace}" />
</bean>
</list>
</property>
</bean>
It looks like spring doesn't handle that on it's own, which kinda makes sense though I feel like it should be possible for the config, rather than having to write code for it. Anyway, here's how we've done it:
#RequestMapping("/signup")
public String signUp(WebRequest request) {
Connection<?> connection = providerSignInUtils.getConnectionFromSession(request);
User user = usersConnectionRepository.createUser(connection);
getRepository().save(user);
providerSignInUtils.doPostSignUp(user.getId().toString(), request);
// the following will automatically log in the user after sign up
SecurityContextHolder.getContext().setAuthentication(new SocialAuthenticationToken(connection, user, null, user.getAuthorities()));
return "redirect:/home";
}

Error with Spring ldap pooling

i build async jersey web services, and now i need to make some operations with ldap.
I have configure Spring beam.xml in this mode:
<bean id="contextSourceTarget" class="org.springframework.ldap.core.support.LdapContextSource">
<property name="url" value="${ldap.url}" />
<property name="base" value="${ldap.base}" />
<property name="userDn" value="${ldap.userDn}" />
<property name="password" value="${ldap.password}" />
<property name="pooled" value="false" />
</bean>
<bean id="contextSource"
class="org.springframework.ldap.pool.factory.PoolingContextSource">
<property name="contextSource" ref="contextSourceTarget" />
</bean>
<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
<constructor-arg ref="contextSource" />
</bean>
<bean id="ldapTreeBuilder" class="com.me.ldap.LdapTreeBuilder">
<constructor-arg ref="ldapTemplate" />
</bean>
<bean id="personDao" class="com.me.ldap.PersonDaoImpl">
<property name="ldapTemplate" ref="ldapTemplate" />
</bean>
But when i try to use ldap i have this error:
Error creating bean with name 'contextSource' defined in class path resource [config/Beans.xml]: Instantiation of bean failed; nested exception is java.lang.NoClassDefFoundError: org/apache/commons/pool/KeyedPoolableObjectFactory
In my project i have commons-pool2-2.2.jar lib, but still i have this error..i try to add commons-pool2-2.2.jar in TOMCAT_PATH/lib but not works..
UPDATE:
If i put commons-pool-1.6.jar it works.. but if i want to use pool2 how i can do? only i must change class inn commons-pool2-2.2.jar?
Updated Answer:
Since at least Spring LDAP 2.3.2 you can now use commons-pool2. Spring LDAP now provides two classes:
For commons-pool 1.x:
org.springframework.ldap.pool.factory.PoolingContextSource
For commons-pool 2.x:
org.springframework.ldap.pool2.factory.PooledContextSource
Details can be found here:
https://github.com/spring-projects/spring-ldap/issues/351#issuecomment-586551591
Original Answer:
Unfortunately Spring-Ldap uses commons-pool and not commons-pool2. As you have found the class org.apache.commons.pool.KeyedPoolableObjectFactory does not exist in commons-pool2 (it has a different package structure), hence the error.
There is a Jira issue for the Spring-ldap project asking them to upgrade/support commons-pool2:
https://jira.spring.io/browse/LDAP-316
Until that has been completed you will have to use commons-pool 1.6.

Activiti BPM Platform - Select a specific schema for creating tables?

I've just started working with activity and integrated it in my project (postgres based) in an embedded way (sample spring configuration file snip)
(...)
<!-- Activiti components -->
<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
<property name="dataSource" ref="dataSource" />
<property name="transactionManager" ref="transactionManager" />
<property name="databaseSchemaUpdate" value="true" />
<property name="jobExecutorActivate" value="false" />
</bean>
<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
<property name="processEngineConfiguration" ref="processEngineConfiguration" />
</bean>
<bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" />
<bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService" />
<bean id="taskService" factory-bean="processEngine" factory-method="getTaskService" />
<bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService" />
<bean id="managementService" factory-bean="processEngine" factory-method="getManagementService" />
(...)
It works well and create a lot of tables on my application schema at startup.
My problem is : tables are created in the 'public' schema in my postgres database. I would have preferred to put those tables in a separate schema, say 'activity'.
Fact is that after browsing the documentation / the net for almost two hours, I didn't found any way to change the default schema target creation behavior.
Any help... greatly appreciated ! ;)
Since Postgres 9.4 JDBC driver you can specify the default schema in the JDBC url like this:
jdbc:postgresql://localhost:5432/mydatabase?currentSchema=myschema
With this URL, all Activiti tables are created in the myschema schema instead of the default one in the search path, usually public.
Sources: this response on Stack Overflow and the latest documentation.

Read operation exception MongoDB in EC2, but local is ok

My web app and mongo built in different ec2.
I run web app in localhost and connect mongo in ec2.
It's OK.
but I deploy web app in ec2.
It have exception
com.mongodb.MongoException$Network: Read operation to server /172.XX.XX.XX:27017 failed on database
com.mongodb.DBTCPConnector.innerCall(DBTCPConnector.java:253)
com.mongodb.DBTCPConnector.call(DBTCPConnector.java:216)
com.mongodb.DBApiLayer$MyCollection.__find(DBApiLayer.java:288)
com.mongodb.DBApiLayer$MyCollection.__find(DBApiLayer.java:273)
com.mongodb.DBCursor._check(DBCursor.java:368)
com.mongodb.DBCursor._hasNext(DBCursor.java:459)
com.mongodb.DBCursor.hasNext(DBCursor.java:484)
com.google.code.morphia.query.MorphiaIterator.hasNext(MorphiaIterator.java:43)
com.google.code.morphia.query.QueryImpl.asList(QueryImpl.java:286)
my monogo congig
<bean id="mongoOptions" class="com.mongodb.MongoOptions">
<property name="autoConnectRetry" value="false" />
<property name="maxAutoConnectRetryTime" value="0" />
<property name="connectionsPerHost" value="10" />
<property name="connectTimeout" value="10000" />
<property name="cursorFinalizerEnabled" value="true" />
<property name="maxWaitTime" value="120000" />
<property name="threadsAllowedToBlockForConnectionMultiplier" value="5" />
<property name="socketTimeout" value="0" />
<property name="socketKeepAlive" value="false" />
<property name="safe" value="true" />
<property name="w" value="0" />
<property name="wtimeout" value="0" />
<property name="fsync" value="false" />
<property name="j" value="false" />
</bean>
Set the network security in the EC2 configuration to allow MongoDb traffic through to your DB box, the default is 27017.
In case anyone comes by (because I did) I was stuck on this same problem of mongodb connecting on local but not on my ec2 server.. for hours.. here is the solution and it's very simple.
When you created the MongoDB cluster, you added your computer's IP address to the white list. You need to grab EC2 Instance's 'IPv4 Public IP' and add that to to the white list as well.

How to connect to MongoDB on CloudBees using Spring Data (XML config)?

To learn (spring/mongoBD/CLoudBees), I have created a mongoDB instance on CloudBees, and I am trying to connect my spring app using spring Data.
I get the following error:
Caused by: org.springframework.data.mongodb.CannotGetMongoDbConnectionException:
Failed to authenticate to database [appDB], username = [MY_DB_USERNAME], password = [b**********1]
at org.springframework.data.mongodb.core.MongoDbUtils.doGetDB(MongoDbUtils.java:114)
at org.springframework.data.mongodb.core.MongoDbUtils.getDB(MongoDbUtils.java:74)
at org.springframework.data.mongodb.core.SimpleMongoDbFactory.getDb(SimpleMongoDbFactory.java:118)
at org.springframework.data.mongodb.core.SimpleMongoDbFactory.getDb(SimpleMongoDbFactory.java:107)
at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator.ensureIndex(MongoPersistentEntityIndexCreator.java:213)
at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator$1.doWithPersistentProperty(MongoPersistentEntityIndexCreator.java:146)
at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator$1.doWithPersistentProperty(MongoPersistentEntityIndexCreator.java:120)
at org.springframework.data.mapping.model.BasicPersistentEntity.doWithProperties(BasicPersistentEntity.java:257)
at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator.checkForIndexes(MongoPersistentEntityIndexCreator.java:120)
at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator.onApplicationEvent(MongoPersistentEntityIndexCreator.java:92)
at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator.onApplicationEvent(MongoPersistentEntityIndexCreator.java:49)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:96)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:334)
at org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:268)
at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:168)
at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:137)
at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:63)
at org.springframework.data.mongodb.repository.support.MongoRepositoryFactory.getEntityInformation(MongoRepositoryFactory.java:141)
at org.springframework.data.mongodb.repository.support.MongoRepositoryFactory.getTargetRepository(MongoRepositoryFactory.java:83)
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:147)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:162)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:44)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:142)
... 46 more
My XML config for Spring Data:
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongo" ref="mongo"/>
<constructor-arg name="databaseName" value="appDB"/>
<constructor-arg name="userCredentials" ref="mongoCredentials"/>
</bean>
<bean id="mongoCredentials" class="org.springframework.data.authentication.UserCredentials">
<constructor-arg name="username" value="#{mongoUri.username}" />
<constructor-arg name="password" value="#{new java.lang.String(mongoUri.password)}" />
</bean>
<bean id="mongoUri" class="com.mongodb.MongoURI">
<constructor-arg value="mongodb://MY_DB_USERNAME:MY_DB_PASS#paulo.mongohq.com:10048/xxxxxxxxxxxxx"/>
</bean>
<bean class="com.mongodb.Mongo" id="mongo">
<constructor-arg ref="mongoUri" />
</bean>
When I test my URI mongodb://MY_DB_USERNAME:MY_DB_PASS#paulo.mongohq.com:10048/xxxxxxxxxxxxx using umongo, it connects correctly.
Maven dependencies:
spring data mongodb version: 1.3.1.RELEASE
mongodb driver version: 2.10.1
spring core version: 3.2.3.RELEASE
Any idea about what I am doing wrong ?
I solved the problem by replacing my DB name "appDB" by #{mongoUri.database} so the new Bean def for mongoTemplate is:
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongo" ref="mongo"/>
<constructor-arg name="databaseName" value="#{mongoUri.database}"/>
<constructor-arg name="userCredentials" ref="mongoCredentials"/>
</bean>
I don't understand why putting the DB name directly as String is wrong, but anyway for me it works with this XML config.