Java MongoDB Exception: can't authenticate twice on the same database - java

I've got a problem with MongoDB User Authentication using the Java driver 2.11.1. I added some admin-users (dbAdmins, userAdmins etc.) to the admin database.
As suggested by the MongoDB tutorial, I use only one instance of the MongoClient object: it's implemented as singleton because the MongoClient object is like an connection pool.
If an admin wants to have access to the database, he will make up a new connection to the database with the global MongoClient instance (get one connection from the pool) and call the authentication method of the driver: an example:
MongoClient mongoClient = new MongoClient("ip", "port");
DB adminDB = mongoClient.getDB("admin");
boolean isAuth = adminDB.authenticate("Admin", "Admin1234".toCharArray());
DB anotherAdminDB = mongoClient.getDB("admin");
boolean isAuth2 = anotherAdminDB.authenticate("UserAdmin", "UserAdmin1234".toCharArray());
If I do so, I will get the exception:
java.lang.IllegalStateException: can't authenticate twice on the same
database
But each admin user has to authenticate with it's own credentials. Does anyone had this problem already? How could you solve that problem?
If I create a new MongoClient per admin, then there is no exception thrown and all is correct. But then I can't use the connection pooling of Mongo.
Thank you and best regards.

I think that limitation is by design. Maybe mongodb authentication is more appropriate in the context of application <-> database, not from user <-> application. If you need to authenticate user access to your application, better to implement it your own (eg: using Java EE / Spring Security)

Related

which is better for operate db from java jdbc

that's a question which has confuse me a lot.
for example:
when I design the Dao layer,sometimes,I must do some insert operation,and than
I should do some query such as select the data's id by auto-generate in db.
my question was that:
when I use spring to help manage datasource,
when I do more than two sql operation one by one,
how many times the java client connect to the db?? only one ? or more?
code,such as fellows:
getSimpleJdbcTemplate().update(some params...);
getSimpleJdbcTemplate().query(some params...);
It depends on your Transactional settings.
Spring-transactions in local mode, work on a thread-local connection for all the db activities within single transaction.
If you have not configured transactions, then basically each DB call will retrieve connection from datasource using Datasource.getConnection()
In terms client connecting to DB, if you are using datasource with connection pooling capability, then connections are returned from the pool.
But if datasource is not backed by pool, then it will instantiate connection to DB server on demand ( on getConnection() ) call

How to add string parameters in lookup method in jdbc connection?

In my web application I'm using JDBC connectivity basically its working fine with below code
connObj = DriverManager.getConnection(dbaseUrl, usrName, Paswrd);
But when I'm using veracode tool its showing flaw as J2EE Bad Practice:getConnection so that i need to implement.
InitialContext ctx= new InitialContext();
DataSource dsrc=(DataSource)ctx.lookup(dbaseUrl, usrName, Paswrd);
dsrc.getConnection();
How can I pass 3 parameters in lookup so that it should not disturb my previous flow of code. Can anybody guide me please?
You cannot change the lookup method parameter. But you can use bind or rebind methods of InitialContext to retrieve your datasource.See sample
ctx.bind("java:/comp/env/jdbc/nameofmyjdbcresource", dsrc);
For details example check here.
A DataSource is a connection to one database and you configure a DataSource with a single username and password. If you really need specific (and changing) usernames/passwords depending on application logic, then you can use DataSource.getConnection(String username, String password). However keep in mind with some (most?) connection pools this will give you a non-pooled connection.
If you want to access a different database (or a different configuration), then you need to specify a data source for each database you want to access and ask for that specific data source.
If that is not possible for your situation, then you should just ignore/suppress the veracode warning and continue using DriverManager.

How to create and maintain one jdbc connection per user in web app (Spring/Vaadin)?

How to create an application which can handle thousand of jdbc connection at runtime without implementing connection pool ? AFAIK to establish connection pool, we need username, passowrd and required dbinstance url but here all of them will be provided at runtime to connect particular database, and there would be more than 1000 user at one time to connect to set of databases.(memory intensive !)
So typically it going to be like this:
Users: User-A,User-B,User-C.....User-n
db: DB1, DB2, DB3....DBn
Can anyone please guide me how can I achieve this task ?
I only have one thing in my mind, i.e. to create single connection with each session and use it whereever required specific to that user.
I've used Apache Commons DBCP2 for connection pooling, MyBatis-Spring implementation, Spring and Vaadin for different application but not sure if anyone of them gonna help me !
Here's another approach:
Oracle supports proxy authentication. It would work something like this:
setup limited rights user for your application (say webgui)
connect to database as webgui (w connection pooling)
authenticate the real user (say JoeSmith) by simply trying to connect as him (JoeSmith/password), perhaps w a second connection
in first connection change user to JoeSmith (not sure what oracle syntax is, in postgres it's SET ROLE)
reset user at end of database session
EclipseLink has a postAcquireClientSession method, not sure about MyBatis
You might have to wipe any caching in your ORM if it uses it
Finally, I had to settle down with following approach. Though I am not sure if its a good approach.
I created a SqlSessionFactory by providing DataSource with dynamic Username, Password and Database.
public SqlSessionFactory build() throws IOException, SQLException
{
OracleDataSource dataSource = new OracleDataSource();
dataSource.setURL(this.dbUrl);
dataSource.setUser(this.dbUsername);
dataSource.setPassword(this.dbPassword);
dataSource.setDriverType(properties.getProperty("db.driver"));
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment(properties.getProperty("db.environment"), transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMappers("com.app.dao");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(configuration);
// final test connection to db
sessionFactory.openSession().getConnection();
return sessionFactory;
}
Then I am getting one SqlSession out of factory:
SqlSession session = sessionFactory.openSession();
and I am setting it across Vaadin session :(, so that it would be available throughout session. Hence I can use it whenever I need by taking it from session.
UI.getCurrent().getSession().setAttribute(SqlSession.class,session);
I am discarding it when logout:
UI.getCurrent().getSession().setAttribute(SqlSession.class, null);
I feel its dirty and may create memory issue. but didn't find any other easy solution. Please feel free to comment or answer.

How to use one instance of MongoClient in java application server

According to mongodb java concurrency driver we can use one instance of MongoClient for multiple threads for example inside application servers. The only way I know to do this is to create MongoClient in static block:
static {
MongoClient mongoClient = new MongoClient("localhost", 27017);
}
the problem is I can't catch MongoException and return some helpfull information to user. So how to share a single instance of MongoClient between multiple threads inside Java EE application servers?
You can do one of the following:
Create a service class and initiate the mongo connection lazily on first request, showing an error when you fail
Add a try catch and remember the error statically (I really don't like this one! But better than failing on exception in static context)
Use spring to initialize mongo (my preferred option)

MongoDB configuration in a java web app

I'm looking for some advice on the proper way to set up mongoDB for my web application that runs with java.
From the mongoDB tutorial, i understand that I should have only one instance of the Mongo class.
The Mongo class is designed to be thread safe and shared among threads. Typically you create only 1 instance for a given DB cluster and use it across your app.
So I've got a singleton provider for this (I'm using guice for injection)
#Singleton
public class MongoProvider implements Provider<Mongo> {
private Mongo mongo;
public Mongo get() {
if (mongo == null)
mongo = new Mongo("localhost", 27017);
return mongo;
}
}
And whenever I have to work with mongo in my webapp i inject the provider and get the same instance of mongo.
public class MyService {
private Provider<Mongo> mongoProvider;
#Inject
private MyService(Provider<Mongo> mongoProvider) {
this.mongoProvider = mongoProvider;
}
public void execute() {
DB db = mongoProvider.get().getDB("mydatabase");
DBCollection coll = db.getCollection("mycollection");
// Do stuff in collection
...
}
}
What I find weird is that everytime i access my database, i get logs like this from mongo :
[initandlisten] connection accepted from 192.168.1.33:54297 #15
[initandlisten] connection accepted from 192.168.1.33:54299 #16
So far, I haven't had any problems but I'm wondering if it's good practice and if I won't run into any problems when the number of connections accepted gets too high.
Should I also have only one instance of the DB object for my entire app ?
Do I have to configure MongoDB differently to automatically close the connections after some time ? Or do I have to close connections manually ? I've read something about using the close() method on Mongo but I'm not sure when or if to call it.
Thank you for you advice.
This is good practice. Each instance of Mongo manages a connection pool, so you will see multiple connections in the mongod logs, one for each connection in the pool. The default pool size is 10, but that can be configures using the connectionsPerHost field in MongoOptions.
Mongo instances also maintain a cache of DB instances, so you don't have to worry about maintaining those as singletons yourself.
You do not have to configure Mongo to automatically close connections. You can call Mongo#close at the appropriate time to close all the sockets in the connection pool.
Founded something like this om MondoDB site:
"The Java MongoDB driver is thread safe. If you are using in a web serving environment, for example, you should create a single MongoClient instance, and you can use it in every request. The MongoClient object maintains an internal pool of connections to the database (default pool size of 10). For every request to the DB (find, insert, etc) the Java thread will obtain a connection from the pool, execute the operation, and release the connection. This means the connection (socket) used may be different each time."
And from FAQ from MongoSite which I think completely anwsers on you question.
http://docs.mongodb.org/manual/faq/developers/#why-does-mongodb-log-so-many-connection-accepted-events

Categories