Should a Shiro Authenticating Realm be transactional? - java

I'm using Shiro to secure my Spring MVC webapp. I'm using Hibernate for persistence and so I have a HibernateRealm to get and populate an AuthenticationInfo object.
#Override
#Transactional
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
Account account = accountDao.findByUsername((String)token.getPrincipal());
SimplePrincipalCollection principals = new SimplePrincipalCollection(account, getName());
SimpleAccount info = new SimpleAccount(principals, account.getPassword());
return info;
}
Account is my custom user class. I use the DAO to retrieve an Account by username. I was wondering if there is any point in making this method #Transactional. This is a read only operation after all.
I'm also having the following problem: the DAO does sessionFactory.getCurrentSession() to get a session, but I'm getting a
HibernateException: No Session found for current thread
when the method gets called. I have these in my application context:
<tx:annotation-driven transaction-manager = "transactionManager" />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
I can't understand why Spring isn't opening a session for me.
Edit: To login, we do this in a Spring #Controller method using Shiro's Subject
#RequestMapping(value = "/account/login", method = RequestMethod.POST)
public String login(#RequestParam("username") String username, #RequestParam("password") String password) {
Subject currentUser = SecurityUtils.getSubject();
if (!currentUser.isAuthenticated) {
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
currentUser.login(token);
return "profile";
}
return "home";
}
Internally, Shiro uses the realm method I have above to get the stored username/password information. It uses an #Autowired DAO to check my database for the right account. It then matches the passwords with a CredentialsMatcher implementation.

So you have two problems. It is usually better to split such questions into two, since these problems are not really connected to each other.
No Session found for current thread
It seems that #Transactional annotations does not work. To be sure you may run you code or tests in Debug mode and look for the JdkDynamicAopProxy or something similar in the stack - if it is present, than your Realm is invoked through transactions-intercepting proxy, but I suppose that there is no proxy curently. For it to work you need to take from the SpringContext not the HibernateRealm directly but the interface that this realm is implementing. This is due to the fact that built-in standard java library proxies can deal only with interfaces.
As for making the read-only service methods transactional.
There are several valid reasons to do so:
Since you are using Hibernate it is really possible that you actually use more than one query to get your Account object. And if this account is modified concurrently it may lead to inconsistent state:
first query for Account retrieval
Account is modified or deleted
second query for Account retrieval - this query will see the results of modification that together with the results of the first query may lead to inconsistent behavior, but if first and second query were in the same transaction with the proper level of transaction isolation second query would not see the modifications.
Uniform access to the database - it is really helpful when all your database connectivity layer access the DB in one and the same way - I greatly simplifies maintaining and extending of the application.
Using some transactional hints like #Transactional(readOnly=true) may improve your performance with proper configuration (e.g. for the really high-loaded application readOnly queries may use secondary replica of the DB Server). It is really easier to setup the java.sql.Connection.setReadOnly() method as part of the Spring transactions, than in the other way.

It appears that Spring isn't creating a transactional proxy for your Realm bean. This is the only reason that I can see why a Hibernate Session isn't available - because the backing infrastructure isn't there (on the thread) ready for use.
As to your question, if you do want to mark it #Transactional, you might consider specifying #Transactional(readOnly=true)

Shiro creates it's own instance of my Realm and therefore Spring has no power over it to wrap it in a proxy. That's why it can't add the transactional behavior.

Related

Does calling the method "SecurityUtils.getSubject();" will always hit the redis database?

I am implementing a redis-shiro session management feature in my project and currently I have very little information about Shiro & Redis.
I want to know whether calling the below will hit the redis database everytime to check whether any sessionId exist in the redis database or not.
Code in Service
Subject currentUser = SecurityUtils.getSubject();
Session session = currentUser.getSession();
Code in Controller:
public String getSomrthing(#CookieValue("JSESSIONID") String fooCookie){
callingSomeServiceMethod(fooCookie);
return "It does not matter";
}
Does we have to match the sessionId manually like below in our service or does Shiro will match it automatically, since my application will be running in a multi instance environment.?
Subject currentUser = SecurityUtils.getSubject();
if(currentUser.getId.equals(fooCookie)){
//.....Some Code
//.....Some Code
}
The session will looked up a max of once per request, less depending on any additional caching you have configured.
You wouldn't manage/lookup the sessionId directly from your controller though. All of this logic would be transparent and handled by Shiro and/or your servlet container's session management.

How can I use Hibernate/JPA to tell the DB who the user is before inserts/updates/deletes?

Summary (details below):
I'd like to make a stored proc call before any entities are saved/updated/deleted using a Spring/JPA stack.
Boring details:
We have an Oracle/JPA(Hibernate)/Spring MVC (with Spring Data repos) application that is set up to use triggers to record history of some tables into a set of history tables (one history table per table we want audited). Each of these entities has a modifiedByUser being set via a class that extends EmptyInterceptor on update or insert. When the trigger archives any insert or update, it can easily see who made the change using this column (we're interested in which application user, not database user). The problem is that for deletes, we won't get the last modified information from the SQL that is executed because it's just a plain delete from x where y.
To solve this, we'd like to execute a stored procedure to tell the database which app user is logged in before executing any operation. The audit trigger would then look at this value when a delete happens and use it to record who executed the delete.
Is there any way to intercept the begin transaction or some other way to execute SQL or a stored procedure to tell the db what user is executing the inserts/updates/deletes that are about to happen in the transaction before the rest of the operations happen?
I'm light on details about how the database side will work but can get more if necessary. The gist is that the stored proc will create a context that will hold session variables and the trigger will query that context on delete to get the user ID.
From the database end, there is some discussion on this here:
https://docs.oracle.com/cd/B19306_01/network.102/b14266/apdvprxy.htm#i1010372
Many applications use session pooling to set up a number of sessions
to be reused by multiple application users. Users authenticate
themselves to a middle-tier application, which uses a single identity
to log in to the database and maintains all the user connections. In
this model, application users are users who are authenticated to the
middle tier of an application, but who are not known to the
database.....in these situations, the application typically connects
as a single database user and all actions are taken as that user.
Because all user sessions are created as the same user, this security
model makes it very difficult to achieve data separation for each
user. These applications can use the CLIENT_IDENTIFIER attribute to
preserve the real application user identity through to the database.
From the Spring/JPA side of things see section 8.2 at the below:
http://docs.spring.io/spring-data/jdbc/docs/current/reference/html/orcl.connection.html
There are times when you want to prepare the database connection in
certain ways that aren't easily supported using standard connection
properties. One example would be to set certain session properties in
the SYS_CONTEXT like MODULE or CLIENT_IDENTIFIER. This chapter
explains how to use a ConnectionPreparer to accomplish this. The
example will set the CLIENT_IDENTIFIER.
The example given in the Spring docs uses XML config. If you are using Java config then it looks like:
#Component
#Aspect
public class ClientIdentifierConnectionPreparer implements ConnectionPreparer
{
#AfterReturning(pointcut = "execution(* *.getConnection(..))", returning = "connection")
public Connection prepare(Connection connection) throws SQLException
{
String webAppUser = //from Spring Security Context or wherever;
CallableStatement cs = connection.prepareCall(
"{ call DBMS_SESSION.SET_IDENTIFIER(?) }");
cs.setString(1, webAppUser);
cs.execute();
cs.close();
return connection;
}
}
Enable AspectJ via a Configuration class:
#Configuration
#EnableAspectJAutoProxy
public class SomeConfigurationClass
{
}
Note that while this is hidden away in a section specific to Spring's Oracle extensions it seems to me that there is nothing in section 8.2 (unlike 8.1) that is Oracle specific (other than the Statement executed) and the general approach should be feasible with any Database simply by specifying the relevant procedure call or SQL:
Postgres for example as the following so I don't see why anyone using Postgres couldn't use this approach with the below:
https://www.postgresql.org/docs/8.4/static/sql-set-role.html
Unless your stored procedure does more than what you described, the cleaner solution is to use Envers (Entity Versioning). Hibernate can automatically store the versions of an entity in a separate table and keep track of all the CRUD operations for you, and you don't have to worry about failed transactions since this will all happen within the same session.
As for keeping track who made the change, add a new colulmn (updatedBy) and just get the login ID of the user from Security Principal (e.g. Spring Security User)
Also check out #CreationTimestamp and #UpdateTimestamp.
I think what you are looking for is a TransactionalEvent:
#Service
public class TransactionalListenerService{
#Autowired
SessionFactory sessionFactory;
#TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
public void handleEntityCreationEvent(CreationEvent<Entity> creationEvent) {
// use sessionFactory to run a stored procedure
}
}
Registering a regular event listener is done via the #EventListener
annotation. If you need to bind it to the transaction use
#TransactionalEventListener. When you do so, the listener will be
bound to the commit phase of the transaction by default.
Then in your transactional services you register the event where necessary:
#Service
public class MyTransactionalService{
#Autowired
private ApplicationEventPublisher applicationEventPublisher;
#Transactional
public void insertEntityMethod(Entity entity){
// insert
// Publish event after insert operation
applicationEventPublisher.publishEvent(new CreationEvent(this, entity));
// more processing
}
}
This can work also outside the boundaries of a trasaction if you have the requirement:
If no transaction is running, the listener is not invoked at all since
we can’t honor the required semantics. It is however possible to
override that behaviour by setting the fallbackExecution attribute of
the annotation to true.

Need a way to annotate service methods following repository pattern

I'm trying to refactor the existing code base of one of my project following Repository pattern, so that i can make the project more re-usable and testable.
I've written services, repositories, when I try to set Authentication, Authorization and Transactional annotation on service layer, I am facing issues.
These annotations works only on controller level, but not on service layer, so I want a way for annotate service methods.
Is it possible to do so?
It would be helpful, if someone points me samples using repository pattern on Play framework or better way to proceed further.
Authentication and authorization only make sense on a request, so sticking them on anything but a controller method is not going to work either way.
Transactional is just a helper annotation to wrap the entire request in a JPA transaction. It is usually advisable to do the wrapping yourself anyway, so you don't really need that. Example taken from the documentation:
#Inject
private JPAApi jpaApi;
public void updateSomething() {
// do something with the entity manager, per instance
// save, update or query model objects.
jpaApi.withTransaction(() -> {
EntityManager em = jpaApi.em();
Query query = em.createNativeQuery("update people set active = 1 where age > 18");
query.executeUpdate();
});
}

Jersey rest framework - authorization - some doubts

I read about jersey framework for rest service on this page http://howtodoinjava.com/jersey/jersey-restful-client-api-authentication-example/|
And I don't understand one thing.
For instance, when we have
#Path("/users")
public class JerseyService
{
#RolesAllowed("USER")
public String doLogin(#QueryParam("username") String uname,
#QueryParam("password") String result)
It means that user with role user can modify (by this method) ALL the users? Not only himself in the database? I am writing android app and I can imagine situation where someone is using for instance Advanced REST client. He logs on the service and modifying queries in appropriate way and strongly mess my database. For instance write some points to other user or something similar. How can I shut out this situation?
Jersey (and similar Spring Security) operate on Resource Types and Roles.
So, if you permit Role "USER" to operate on resource "Users", you can't block specific user from editing other users with Jersey only.
What you can do is use SecurityContext to get current user, and block dangerous operations if his credentials are different from user being changed.
Here's a good example on SecurityContext:
https://simplapi.wordpress.com/2015/09/19/jersey-jax-rs-securitycontext-in-action/

Hibernate/Spring: Is There Row-Level Security?

I am not sure if I'm getting it right what Spring Security is capable of.
What my problem is, is that I want to prevent a logged in user to send arbitrary IDs to my server and therefore access data that does not belong to him. But every tutorial I can find is about a simple login procedure. But how can I use that to get rid of
if(item .getStore().getId() == store.getId()) { /* .. */ }
in this example:
// StoreService.java
#Transactional
public ItemDTO deleteItem(String sessionId, Long storeId, ItemDTO itemDto) {
// sessionId is the cookie I have placed in my database
// This way I want to ensure that I am only accessing a store
// that is associated with the logged in store owner (the user basically)
Store store = this.storeOwnerRepository.getStore(sessionId, storeId);
Item item = ConvertDTO.convertItem(store, itemDto);
// THIS CHECK IS WHAT I WANT TO GET RID OF:
// Check if the store ID that I got using the cookie is the
// same ID as the store ID from the item that should be deleted
if(item.getStore().getId() == store.getId()) {
item = this.storeOwnerRepository.deleteItem(item);
} else {
// If this didn't work we have a potentially hostile user:
throw new RuntimeException("Is somebody trying to delete items from a store he doesn't own?");
}
itemDto = ConvertEntity.convertItem(item);
return itemDto;
}
using Spring Annotations? Is that even possible with Spring Security?
Another thing that might work would be Hibernate Filters but I am not sure if I want my database to know about security aspects of my data.
So I am quite confused about how to do that correctly. Any ideas?
We've implemented this kind of security on domain objects with Spring's ACL API. This involves:
creating an implementation of Spring's org.springframework.security.acls.model.AclService interface that knows how to return the permissions a given principal has on a given domain object. E.g. if the principal has relationship foo to this domain object, then grant READ and WRITE permissions; if relationship bar, then grant READ, WRITE, and DELETE permissions.
adding to the service methods that operate on the domain objects annotations like org.springframework.security.access.prepost.PreAuthorize and org.springframework.security.access.prepost.PreAuthorize that define the access-control assertions to be enforced. E.g. this method requires the current authenticated user to have the "WRITE" permission on the argument of type X, or that method requires the current authenticated user to have the "READ" permission on the return object. If either assertion fails, an AccessDeniedException will be thrown.
adjusting your Spring Social config to turn on method-level security. I used the global-method-security element in Spring Security's XML namespace.
There are a lot of details to consider, but we use this approach in several web applications to good effect. It allows you to separate the who-gets-what-permissions-on-which-objects logic from the what-permissions-are-needed-to-perform-this-action logic, and it keeps both away from your database queries.
Of course, in some cases you'll want to enforce access control in the queries instead of querying first, and then filtering the results. I've seen the term "early binding" used to describe enforcement of access control in database queries, and "late binding" used to describe access control on the results of the queries. The Spring Security ACL API is a very good, robust solution for late binding.
You would end up with business service methods like:
#PostAuthorize("hasPermission(returnObject, 'READ')")
public MyItem getMyItem(Long id) {
return dao.getMyItem(id);
}
#PreAuthorize("hasPermission(#toDelete, 'DELETE')")
public void deleteMyItem(MyItem toDelete) {
dao.delete(toDelete);
}
And an AclService with a method like:
public Acl readAclById(ObjectIdentity objectIdentity, List<Sid> sids) throws NotFoundException {
/*
examines objectIdentity which identifies domain object in question, and sids which identifies the principal who wants permissions on the domain object, then returns an ACL instance with permission grants on that domain object for that/those principals
*/
return new AclImpl(...);
}
And the following in your applicationContext-security.xml:
<beans:bean id="permissionEvaluator"
class="org.springframework.security.acls.AclPermissionEvaluator">
<beans:constructor-arg ref="aclServiceImpl" />
</beans:bean>
<beans:bean id="expressionHandler"
class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<beans:property name="permissionEvaluator" ref="permissionEvaluator" />
</beans:bean>
<global-method-security pre-post-annotations="enabled">
<expression-handler ref="expressionHandler" />
</global-method-security>
Probably you should implement Spring security and work roles and permissions, in this way you will be able to ensure you wont get requests by users that are not admin (by delimiting the method with #Secured("ROLE_SOMEROLE")) , this can help you in case in the future you will have other roles.
Then you should work more with role permissions
Spring Security with roles and permissions
And then add permissions over stores, to read or write them. You can associate many permissions to a user, so, can read/write/whatever only to the stores you want.
Check this tutorial, it could help you.
http://slackspace.de/articles/roles-permissions-with-spring-security-3/
http://springinpractice.com/2010/10/27/quick-tip-spring-security-role-based-authorization-and-permissions
I think what you are talking about has more to do with validation than security.
As long as you store data for multiple clients/customers in the same database, you must take care to prevent users from inadvertently (or maliciously) accessing each other's data.
I suggest that you perform this validation at the web service layer and keep the business logic focused on the details of what needs to be done.

Categories

Resources