Hibernate datasource config based on login user credentials - spring

I am developing a Java webapp with Spring 3.2.1 and Hibernate 4.1.9 tied to Postgres Advanced Server backend (for row level security). The problem I am trying to solve is how to tie the webapp login user to the to the Hibernate session. To be specific, if user A logs in, then I want the webapp connection to the database to use A' credentials (only then I will be able to filter records that A has permissions to view / alter). Webapp & database users are validated against the same ldap server.
My config info is as follows:
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="annotatedClasses">
<list>
<value>com.mycom.proj.model.A</value>
<value>com.mycom.proj.model.B</value>
<value>com.mycom.proj.model.C</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${db.hibernate.dialect}</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
</props>
</property>
</bean>
Based on the above config, dataSource and sessionFactory beans are singleton's.
One approach I could take is to set the dataSource and sessionFactory to "session" scope. I am hesitant to take that approach for the following reasons:
a) If the database connection is at a session scope, then I cannot make use of connection pooling. (I think I may have to live with it)
b) I am afraid that setting the sessionFactory to session scope will mess up the Hibernate' cache mechanism.
Any thoughts / ideas about how I could solve this issue?
Thanks in advance.

Another alternative is to make all connections as an unprivileged user that has NOINHERIT membership of all the user roles. You then SET ROLE to the logged in user before running queries. If you fail to SET ROLE due to a programming error harm is minimized because you haven't granted the unprivileged user you're connecting with any rights and it hasn't inherited any, so it can't do anything.
It should be pretty easy to do this with servlet filters (if you use one connection for a whole request), CDI interceptors, a wrapper around your connection pool, using hooks provided by your connection pool implementation, or various other options to make sure it always happens.
It'd be nice if you could use SET SESSION AUTHORIZATION instead, but that requires a superuser connection. I don't recommend that applications use superuser connections even if they're just going to decrease their rights. One mistake could have very serious consequences.
I wrote in a lot more detail about this in response to a DBA question a while ago.

Usually connections pools handle per user pooled connections, so you only need an adapter to redirect getConnection() calls to getConnection(user, passwd).
Spring provides one, see: org.springframework.jdbc.datasource.UserCredentialsDataSourceAdapter
you can set the credentials on the Datasource via setCredentialsForCurrentThread() method in the login filter, for example.

Related

Spring JdbcTemplate , How to dynamically set username and password in Spring config XML file?

Spring JDBC: while using JdbcTemplate how to set username and password for every user ?, Currently I am Configuring datasource object as a spring bean (Spring config.xml file ) and able to login with sinlge username and password , also used properties file and placeholder for the same
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/apu"></property>
<property name="username" value="root"></property>
<property name="password" value=""></property>
</bean>
What are the ways to set username value and password value for every user who logsin ?
This is my first Spring application hence not able to find right approach ..
Generally, in a web application, each user do not use its own identity to access the database. The common pattern is to have one single database user for the application, and let the application manage the permission of its own users.
As M.Deinum said, this pattern allows the application to use a connection pool, where database connections are recycled across different requests which dramatically reduces the database load (establishment of the connection is expensive)
If you look at (almost) all the spring examples an tutorial, they consitently use that approach with one single database user for the whole web application.
If you really need that each user uses it own database identity you must use a UserCredentialsDataSourceAdapter as suggested by M. Deinum, with no database pool.

Spring Security Twitter Access Token

I'm trying to get the ability to write to someone's Twitter account through Java and Spring Social.
Whenever I request write access through my application on twitter, I get the following exception:
org.springframework.social.NotAuthorizedException: Invalid or expired token
org.springframework.social.twitter.api.impl.TwitterErrorHandler.handleClientErrors(TwitterErrorHandler.java:104)
org.springframework.social.twitter.api.impl.TwitterErrorHandler.handleError(TwitterErrorHandler.java:58)
org.springframework.web.client.RestTemplate.handleResponseError(RestTemplate.java:537)
However, when I turn off access, I don't get this exception, but I (obviously) lose the ability to write. From all the research I have done, I have yet to be able to find anything about spring social except that I need an access token. I cannot find Spring Social documentation that tells me where to get that.
Anyway, this is in my controller:
#Autowired
ConnectionRepository connectionRepository
private Twitter getTwitter() {
connectionRepository.findPrimaryConnection(Twitter.class).api
}
#RequestMapping(value = "/connect/twitter/connect/twitter")
String loggedIn(Model model) {
if (twitter?.authorized) {
model.addAttribute("screenName", twitter.userOperations().screenName)
twitter.timelineOperations().updateStatus("Welcome to Miami #helloWorld")
HOME
}
else {
"redirect:/twitter"
}
}
My ConnectionRepository implementation is a basic one for MongoDB. I don't think it is the issue, but if it is it is nearly identical to:
https://github.com/CarloMicieli/spring-social-mongo/blob/master/src/main/java/org/springframework/social/connect/mongo/MongoConnectionRepository.java
Here is my dispatch xml:
<bean class="org.springframework.social.connect.web.ConnectController">
<property name="applicationUrl" value="http://localhost:8081/MinnesotaCows/" />
</bean>
<bean class="org.springframework.social.connect.web.ProviderSignInController">
<property name="applicationUrl" value="http://localhost:8081/MinnesotaCows/" />
<property name="signUpUrl" value="/register" />
</bean>
<bean id="twitterConnectionFactory"
class="org.springframework.social.twitter.connect.TwitterConnectionFactory">
<constructor-arg value="bUC8VEWgkfkeTXuTBuxCg" />
<constructor-arg value="5I1CNYKBCkNbsbgL2JfTNdSnSA9JVY4KHI4myxV7k4" />
</bean>
<bean id="connectionFactoryLocator"
class="org.springframework.social.connect.support.ConnectionFactoryRegistry">
<property name="connectionFactories">
<list>
<ref bean="twitterConnectionFactory" />
</list>
</property>
</bean>
<bean id="textEncryptor" class="org.springframework.security.crypto.encrypt.Encryptors"
factory-method="noOpText" />
Note: I'm running at localhost. Could the problem be that? Since there is no callback? Also, I'm not using the signUpUrl in the ProviderSignInController for anything. I'm not quite sure what that is for either.
Anyone have any ideas on what I might be doing wrong - or how I can exactly get the access token through the API?
Thanks for your time!
I haven't tested CarloMicieli's mongo based connection repositories, but looking the code I can see that primary connection is the first connection created. This is the same behavior that the built in jdbc based repository in Spring Social has. But I think it's wrong, primary connection should be always the last issued connection/login to the provider (the connection with rank 1 can be expired even though there are newer connections).
You could try to empty the connections collection in your mongo db and test if your code works after that. If the token works then, it is the issue that I described.
I have created my own mongo based social repositories that rank the connections by timestamp and order them so that the last issued connection is the primary one. That way you can issue multiple logins and the last login will be the primary connection.
See reference from github: https://github.com/trautonen/spring-social-mongodb/tree/master/src/main/java/org/eluder/spring/social/mongodb
You also defined ConnectController which map the social provider connection paths. You can initialize login flow by doing POST request to /connect/twitter and if completed without problems should result a working connection in your connections collection in mongodb.
See full reference here: http://docs.spring.io/spring-social/docs/1.1.0.RELEASE/reference/htmlsingle/#creating-connections-with-connectcontroller

Multi-tenant webapp using Spring MVC and Hibernate 4.2.0.Final

I have developed a small webapp using and SpringMVC(3.1.3.RELEASE) and Hibernate 4.2.0.Final.
I'm trying to convert it to be a multi-tenant application.
Similar topics have been covered in other threads, but I couldn't find a definitive solution to my problem.
What I am trying to achieve is to design a web app which is able to:
Read a datasource configuration at startup (an XML file containing multiple datasource definitions, which is placed outside the WAR file and it's not the application-context or hibernate configuration file)
Create a session factory for each one of them (considering that each datasource is a database with a different schema).
How can i set my session factory scope as session? ( OR Can i reuse the same session factory ?) .
Example:
Url for client a - URL: http://project.com/a/login.html
Url for client b - URL: http://project.com/b/login.html
If client "a" make request,read the datasource configuration file and Create a session factory using that XML file for the client "a".
This same process will be repeating if the client "b" will send a request.
What I am looking, how to implement datasource creation upon customer subscription without editing the Spring configuration file. It needs to be automated.
Here is my code ,that i have done so far.
Please anyone tell me,What modifications i need to be made?
Please give an answer with some example code..I am quite new in spring and hibernate world.
Spring.xml
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close" p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.databaseurl}"
p:username="${jdbc.username}" p:password="${jdbc.password}" />
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${jdbc.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
JDBC.properties File
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.dialect=org.hibernate.dialect.MySQLDialect
jdbc.databaseurl=jdbc:mysql://localhost:3306/Logistics
jdbc.username=root
jdbc.password=rot#pspl#12
hibernate.cfg.xml File
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<mapping class="pepper.logis.organizations.model.Organizaions" />
<mapping class="pepper.logis.assets.model.Assets" />
</session-factory>
</hibernate-configuration>
Thanks,
First create a table for Tenant with tenant_id and associate it with all users.Now, you can fetch this details while the user logs in and set it in session.
We are using AbstractRoutingDataSource to switch DataSource for every request on Spring Boot. I think it is Hot Swapable targets/datasource mentioned by #bhantol above.
It solves our problems but I don't think it is sound solution. I guess JNDI could be a better one than AbstractRoutingDataSource.
Wondering what you ended up with.
Here are some ideas for you.
Option 1) Single Application Instance.
It is somewhat ambitious to to this using what you are actually trying to achieve.
The gist is to simply deploy the same exact application with different context root on the same JVM. You can still tune the JVM as a whole like you would have if you had a truely multi-tenant application. But this comes at the expense of duplication of classes, contexts, local caching, start up times etc.
But as of today the Spring Framework 4.0 does not provide much of an multi-tenancy support (other than Hot Swapable targets/datasource) etc. I am looking for a good framework but it may be a wash to move away from Spring at this time for me.
Option 2) Multiple deployments of same application (more practical as of today)
Just have your same exact application deploy to the same application server JVM instance or even different.
If you use the same instance you may now need to bootstrap your app to pickup a DataSource based on what the instance should serve e.g. client=a property would be enough to pickup a **a**DataSource" or **b**DataSource I myself ended up going this approach.
If you have a different application server instance you could just configure a different JNDI path and treat things generically. No need for client="a" property because you have liberty to define your datasource differently with the same name.

Websphere, Spring, Hibernate, JAX-WS Global Transactions

I am attempting to write a demo of a JAX-WS service participating in a global transaction. This is a model my organization will be doing more of as time goes on and we need to figure it out, but I am struggling.
I have a WSDL service being invoked from a client (which is also in a Java EE servlet with the same config...in fact it is the same server, but I can see that it is calling out over the wire to itself). Both are updating their rows, and then I throw an exception but the service will not rollback.
I have annotated a method that invokes both a local DAO update and the WSDL service client with #Transactional(propagation=Propagation.REQUIRED). That service in turn invokes another method, also anotated in the same way, which in turn calls a dao method to do another db update.
app-config.xml:
<jee:jndi-lookup id="wsdlDataSource" jndi-name="${es.ds.jndi}" />
<bean id="wsdlSessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="wsdlDataSource" />
<property name="packagesToScan" value="com.wsdl" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.DB2Dialect</prop>
<prop key="hibernate.connection.driver_class">com.ibm.db2.jcc.DB2Driver</prop>
<prop key="hibernate.bytecode.provider">javassist</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
<prop key="hibernate.default_schema">k702prdr</prop>
<prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</prop>
<prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.WebSphereExtendedJTATransactionLookup</prop>
<prop key="jta.UserTransaction">java:comp/UserTransaction</prop>
</props>
</property>
<property name="annotatedClasses">
<list>
<value>com.wsdl.db.DBTrans</value>
<value>com.wsdl.db.UsrTrans</value>
</list>
</property>
</bean>
<!-- END Data sources -->
<!-- BEGIN Hibernate config and dependencies -->
<bean id="transactionManager"
class="org.springframework.transaction.jta.WebSphereUowTransactionManager" >
</bean>
<tx:annotation-driven transaction-manager="transactionManager"
proxy-target-class="true" />
I have followed some tutorials that had me go in to the Services view and add the WSTRansaction policy sets and bindings o the client and service (both generated initially from the RAD wizard), and then again into Admin Console applications->application Types->Websphere enterprise apps->my app->Service provider/client policy sets and bindings. There I added WSTransaction to client and service respectively at the parent application level (the policy inherits down to the endpoint).
But at the end of the day, no rollback is happening. Help! What am I missing? What have I misconfigured?
(update) - I found how to turn on the websphere transaction trace log in the admin console. It says (edited for brevity):
No transaction context found
Exit
Entry parm0=Operation: isAlive
No transaction context from incoming request
getTransactionManager parm0=com.ibm.ws.tx.jta.TranManagerSet#306e306e
These messages come with a bunch of what appear to be inspections of objects, and they repeat many times. Okay, so I appear to not be sending a transaction context from my client. But I still don't understand why. Anyone?
(update 2) - I discovered that my WSTRansaction policy sets for the service and client was not set to share, so i set it to share via the wsdl, and the trace log now seems to indicate that it is finding the transaction context...or at least, it's no longer explicitly saying it can't as above. It is saying some things like the following that may or may not means what i think they mean (again, edited for brevity if there is something meaningful you are not seeing, tell me, there is alot more info in there):
Entry parm0=XATransactionWrapper# 5f175f17 XAResource: com.ibm.ws.rsadapter.spi.WSRdbXaResourceImpl#5b7d5b7d enlisted: falseHas Tran Rolled Back = false mcWrapper.hashCode()490085686 parm1=XARESOURCE_NOTASSOCIATED
xa_start with flag: 0=TMNOFLAGS
setResourceStatus parm0=from NONE to REGISTERED
[at this point I see a log stmt that indicates my first update in the service]
setResourceStatus parm0=from REGISTERED to COMPLETING_ONE_PHASE
**setResourceStatus parm0=from COMPLETING_ONE_PHASE to COMMITTED**
setResourceStatus parm0=from NONE to REGISTERED
[at this point I see a log stmt that indicates my second update, which is done in the client]
setResourceStatus parm0=from REGISTERED to COMPLETING
setResourceStatus parm0=from COMPLETING to ROLLEDBACK
[at this point I see the stack trace of the hardcoded exception I am throwing]
So it seems pretty clear that while the transaction manager now sees both the client and service transaction, it thought it was supposed to complete the transaction on the service side as soon as that part was done, not realizing it was supposed to continue. Somehow I triggered a premature commit I guess. Ideas?

Validating Connection Before Handing over to WebApp in ConnectionPooling

I have connection pooling implemented in spring using Oracle Data Source. Currently we are facing an issue where connections are becoming invalid after a period of time. (May be Oracle is dropping those idle connections after a while). Here are my questions:
Can Oracle database be configured to drop idle connections automatically after a specific period of time. Since we expect those connections to lie idle for a while; if there is any such configuration; it may be happening.
In our connection pooling properties in spring we didn't have "validateConnection" property. I understand that it validates the connection before handing it over to web application? But does that mean that if a connection passes validateConnection test then it'll always connect to database correctly. I ask this, as I read following problem here:
http://forum.springsource.org/showthread.php?t=69759
If suppose validateConnection doesn't do the whole 9 yards of ensuring that connection is valid, is there any other option like "testBeforBorrow" in DBCP , which runs a test query to ensure that connection is active before handing it over to webapp?
I'll be grateful if you could provide answers to one ore more queries listed above.
Cheers
You don't say what application server you are using, or how you are configuring the datasource, so I can't give you specific advice.
Connection validation often sounds like a good idea, but you have to be careful with it. For example, we once used it in our JBoss app servers to validate connections in the pool before handing them to the application. This Oracle-proprietary mechanism used the ping() method on the Oracle JDBC driver, which checks that the connection is still alive. It worked fine, but it turns out that ping() executes "select 'x' from dual' on the server, which is a surprisingly expensive query when it's run dozens of times per second.
So the moral is, if you have a high-traffic server, be very careful with connection validation, it can actually bring your database server to its knees.
As for DBCP, that has the ability to validate connections as their borrowed from the pool, as well as returned to the pool, and you can tell it what SQL to send to the database to perform this validation. However, if you're not using DBCP for your connection pooling, then that's not much use to you. C3PO does something similar.
If you're using an app server's data source mechanism, then you have to find out if you can configure that to validate connections, and that's specific to your server.
One last thing: Spring isn't actually involved here. Spring just uses the DataSource that you give it, it's up to the DataSource implementation to perform connection validation.
Configuration of data source "was" as follows:
<bean id="datasource2"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName">
<value>org.apache.commons.dbcp.BasicDataSource</value>
</property>
<property name="url">
<value>ORACLE URL</value>
</property>
<property name="username">
<value>user id</value>
</property>
<property name="password">
<value>user password</value>
</property>
<property name="initialSize" value="5"/>
<property name="maxActive" value="20"/>
</bean>
have changed it to:
<bean id="connectionPool1" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close">
<property name="connectionCachingEnabled" value="true" />
<property name="URL">
<value>ORACLE URL</value>
</property>
<property name="user">
<value>user id</value>
</property>
<property name="password">
<value>user password</value>
</property>
<property name="connectionCacheProperties">
<value>
MinLimit:1
MaxLimit:5
InitialLimit:1
ConnectionWaitTimeout:120
InactivityTimeout:180
ValidateConnection:true
</value>
</property>
</bean>

Resources