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

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.

Related

Keycloak - how to handle multiple work contexts

I have an application where single user can work in contexts of multiple companies. We call such a connection (user<->company) a permit. Every one of this permits can have different sets of permissions/roles. We want user to login just once and then he can simply change permits within application without need to enter password again.
Till now we had only one application and kept this whole permission model in our own DB. Unfortunately now we have to support second application which should inherit those permits. I was wondering wether is possible to move that model to keycloak so we don't have to replicate it to every single db and keep it in sync manually.
I have searched keycloak documentation regarding this topic but have found no information att all, which seems quite odd, because I don't think we are the first one working with multiple context application.
So now I'm asking is it possible to configure our model in keycloak and if so, how to do it? Eventually are there different options? I guess that I can provided that model as a claim with json structure but that doesn't feel right to me. I was thinking about custom IDP which could provide such claims based on DB so there no spelling errors and less repetition but I feel there should be a better way.
You could try to write your own Keycloak provider (SPI). There is a built in mechanism that allows you to expose REST endpoint on the Keycloak: https://github.com/keycloak/keycloak/tree/master/examples/providers/domain-extension
That REST could be called with authorized context only for example by passing Access-Token (Authorization header with Bearer value). On the provider level (through implementation of: org.keycloak.services.resource.RealmResourceProviderFactory and org.keycloak.services.resource.RealmResourceProvider) you have access to user's Keycloak session and object UserModel like in the following code:
AuthenticationManager.AuthResult authResult = new AppAuthManager().authenticateBearerToken(keycloakSession, keycloakSession.getContext().getRealm());
UserModel userModel = authResult.getUser();
UserModel class has methods for getting and setting attributes, so some information that indicates the current permit/company ID can be stored there. You can use REST methods exposed on the Keycloak to modify the model within the 'session' (represented by Access-Token).
The Github example shows also how to use another Keycloak provider (ex. built-in JPA provider) from you custom provider's level, so using that approach you could try to connect to the database with your permits/company informations. Of course the datasource representing you database should also be registered as Keycloak datasource.

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.

Testing the database connection with spring and hibernate

I'm currently working on a java application. It's a standalone client with Spring and Hibernate. Also C3P0.
In the previous version we used a standard user(hardcoded in the configuration file) for the database connection but now we changed it so that every user has to provide his own credentials.
The beans with the code for the database are basically created on-demand.
I changed the XML-files and added a postprocessor which sets the credentials as well as some connection settings. It looks similar to this now:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();
configurer = new PropertyPlaceholderConfigurer();
// properties are retrieved from a private method
configurer.setProperties(getProperties());
context.addBeanFactoryPostProcessor(configurer);
context.setConfigLocations(new String[] { "first.xml","second.xml" });
context.refresh();
return context.getBean("myClass", MyClass.class);
This all works as expected but now we reach the part where I'm currently stuck.
I want to provide a test functionality for the connection, so that the user can click a button and then is told if his credentials were accepted or not.
My first idea was to do a simple select on the database. Sifting through the logs however, I noticed that Spring tries to connect to the database during the refresh() (or rather the instantiation of the bean) anyway. I can see exceptions in the logs, for example: java.sql.SQLException: Connections could not be acquired from the underlying database!
Unfortunately, Spring doesn't seem to actually care. The exceptions are logged away but refresh() finishes and is not throwing any exceptions because of this. I had hoped that I could simply catch the exception and then I would know that the connection failed.
I could just do the select as planned, but I want to limit the connection attempts as much as possible, because the database server will block the user after several attempts. Even permanently if there are to many attempts(already had some fun with that, before I changed the settings for the connection pool).
My searches regarding this problem came up with practically nothing. Is there a way to get the exception somehow? Or does Spring provide an API of sorts that would tell me about the connection error during the instantiation/refresh?
Failing that, any ideas for an alternative approach? Preferably one that needs only a single attempt to determine if a connection is possible.
Edit: For anyone interested: I went with the suggestion from Santosh and implemented a connection test in JDBC.
Unfortunately there seems to be no easy way to make use of the database errors/exceptions encountered during the bean instantiation.
The kind of functionality you are looking for would be very tricky to accomplish using spring+hibernate.
The connection properties are set at the session-factory level and if credentials are incorrect, the session-factory is not instantiated.
Quoting #Bozo from his answer here.
What you can do is extend LocalSessionFactoryBean and override the
getObject() method, and make it return a proxy (via
java.lang.reflect.Proxy or CGLIB / javassist), in case the
sessionFactory is null. That way a SessionFactory will be injected.
The proxy should hold a reference to a bare SessionFactory, which
would initially be null. Whenever the proxy is asked to connect, if
the sessionFacotry is still null, you call the buildSessionFactory()
(of the LocalSessionFactoryBean) and delegate to it. Otherwise throw
an exception. (Then of course map your new factory bean instead of the
current)
There is also a simple and rudimentary approach wherein before creating ClassPathXmlApplicationContext, simply try to obtain a connection using raw JDBC calls. If that succeed then proceed or else give use appropriate message.
You can limit the connection attempts here as you are in full control.

Using JNDI to share servlet session objects and data in Tomcat

Over the last few weeks i have been looking at solutions to share an object between two contexts/war files. There are a number of ways this can be done and one of them is JNDI.
I am not very familiar with JNDI used in Tomcat so would like a few questions clarified:
Basically i have an instance of an object that would provide the following services to more than one context/application
Check that the user is logged on
Check that the user's session is valid
Logon user - Includes logging the logon details
Logout user - Remove session
Each application will call this object to validate the user before it processes any requests. What i dont understand is how the object would work if it is stored on JNDI. I have seen a few examples of how JNDI is used in Tomcat but 99% of the examples show how to configure a JDBC datasource.
How exactly is the object initialised in JNDI. For example, the following configuration from the Tomcat docs shown the configuration for JDBC
<Resource name="jdbc/db1"
auth="Container"
type="oracle.jdbc.pool.OracleDataSource"
driverClassName="oracle.jdbc.driver.OracleDriver"
factory="oracle.jdbc.pool.OracleDataSourceFactory"
url="jdbc:oracle:thin:#oracle.microdeveloper.com:1521:db1"
user="scott"
password="tiger"
maxActive="20"
maxIdle="10"
maxWait="-1">
How would i do a similar thing in my case and most importantly, how would i initialise the object before it is put on the JNDI tree. Once it is on the JNDI tree, how is it updated?
I guess what i am looking for is a simple example of the use of JNDI in Tomcat but not for database connections but for service provider type objects.
I have been reading this tutorial http://docs.oracle.com/javase/tutorial/jndi/ops/bind.html but it is focused more on LDAP naming directories which doesnt really help.
Edit
Ok i did find an example in the tutorial i listed above that shows how to "bind" an object the the JNDI tree.
class SerObj {
public static void main(String[] args) {
// Set up environment for creating initial context
Hashtable<String, Object> env = new Hashtable<String, Object>(11);
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial");
try {
// Create the initial context
Context ctx = new InitialContext(env);
// Create object to be bound
Button b = new Button("Push me");
// Perform bind
ctx.bind("cn=Button", b);
// Check that it is bound
Button b2 = (Button)ctx.lookup("cn=Button");
System.out.println(b2);
// Close the context when we're done
ctx.close();
} catch (NamingException e) {
System.out.println("Operation failed: " + e);
}
}
}
How would i modify it to use the Tomcat environment instead of the LDAP environment as shown above?
Does the bind store a copy of the object or a reference to the object? What i am not sure of is for example, if 3 webapps access the object, will they all be accesssing the same instance of the object or different instances? I would like there to be only one instance of the object i put in the JNDI tree.
Edit
I must be missing something very simple. Here is another example i found which shows how to configure a JNDI object in Tomcat - http://flylib.com/books/en/4.255.1.275/1/
How is the com.jspservletcookbook.StockPriceBean initialised?
If one webapp uses the com.jspservletcookbook.StockPriceBean object and changes its state, is this change reflected across all other webapps that access this object?
And most importantly, how many instances of the com.jspservletcookbook.StockPriceBean will be created - I need it to be the same instance for all webapps that would access the object.
Edit
#Ben Brunk - At the moment the session data is stored in a Map which is managed by one of the applications(context). All i need is for the other applications to call this application to check if the session is valid. My problem is that for these applications to get the services of the application that manages the session data, i need to use JNDI for them to get a reference to the relevant object.
The data will not be stored in JNDI. I just want to use JNDI as a means for the applications to find and use the Session Manager object. The problem though is that everything i read about JNDI leads me to believe that it is used to create new objects every time an object is searched or 'looked up' in the directory.
Here is diagram i think shows exactly what i want to achieve:
Edit
#EJP - Just to clarify, the functions i listed above are just examples of what the shared object might do. These were provided just as an example. All the functions it would do are related to the user and the logged on session. For example things like account information(username, last login etc), password information (expiry date etc), user privileges (i.e. which areas of the application the user is allowed access to).
Given that the question is really related to multi-context communication via JNDI (Or any other means) and not about the requirements of the object it doesn't really make sense to list everything that the object is supposed to do so i just listed examples of what it could do.
Apologies if the way i put the question confused anyone.
If you don't care to use LDAP, just use the database itself by creating tables in there to manage session information. You should be able to find plenty of examples of how to do that because it is a common need in enterprise applications. In fact, I had not seen an example of doing it using the LDAP directory before. It seems like LDAP would be a bad fit for managing sessions across domains because it really isn't designed to be updated a lot.
Just to be clear: JNDI is not a storage mechanism. It is a mechanism for naming resources in an enterprise environment and then having the container manage connections to those resources. You need to store your session data in a database or you could use the filesystem or a NoSQL map type solution.
There are several other ways of accomplishing this.
Use Tomcat Container Managed Authentication in association with JAAS. Then your module becomes a JAAS LoginModule.
Use Tomcat Container Managed Authentication with the Tomcat Single Sign-on module.

JDBC Connection Pooling for Servlets

Currently I'm using a separate DBConnectionManager class to handle my connection pooling, but I also realized that this was the wrong way to go as the servlet was not calling the same pool each time a doGet() is performed.
Can someone explain to me why the above is happening?
Is JNDI the way to go for java servlets with tomcat for proper connection pooling?
I have links to 2 articles, is this the correct way to implement connection pooling with servlets?
http://www.javaranch.com/journal/200601/JDBCConnectionPooling.html
http://onjava.com/onjava/2006/04/19/database-connection-pooling-with-tomcat.html
Is it possible to save the db manager object in the context like so:
mtdb = (MTDbManager) context.getAttribute("MTDBMANAGER");
if (mtdb == null) {
System.out
.println("MTDbManager is null, reinitialize MTDbManager");
initMTDB(config);
context.setAttribute("MTDBMANAGER", mtdb);
}
And then I call mtdb.getInstance().getConnection() and it will always reference this object.
Thanks.
Generally, the best advice is to leave the connection pooling to the application server. Just look up the data source using JNDI, and let the application server handle the rest. That makes your application portable (different application servers have different pooling mechanisms and settings) and most likely to be most efficient.
Have a look at, and use, C3P0 instead of rolling your own solution: http://sourceforge.net/projects/c3p0/

Categories