I need to implement a web app that will be used by different users. Each user has different privileges on various tables, e.g.
Student
Student
I will have something at the UI level to limit certain access, e.g. hide the "edit" button for users that don't have permission to modify entries. However, I think I should have something at a lower level (at a database level maybe?) just to ensure data security.
I am using Hibernate, JBoss, DB2 and Struts for my app. I think I should use a JBoss LoginModule of some sort, which authenticates the user against a database with user/password/roles (but I may be wrong(?)). I have done some research and came up with the following options, but none seems to fit my case. I would think this is a very common data access problem in multi-user web apps. Could somebody please point me to the right direction? Thank you in advance!
Use the 'grant' tag in hibernate.cfg.xml
with JACC event listeners. This can set "insert" "update" "read" permissions on all hibernate entities. However, what if I need finer controls? I need to set permissions on certain fields instead of the entire object. http://www.hibernate.org/hib_docs/v3/reference/en-US/html/objectstate-decl-security.html
Limit permissions on getter/setter method of each ejb. If I understood this correctly, this requires manual configuration of every single bean for every user profile, which seems unrealistic for me. EJB Method Permissions
Code the DAO's to check for user permissions. Roll my own utility function that checks a giant permission table everytime a particular DAO method is called to determine if the logged in user can perform the action or not.
Use 'interceptor' and 'events' in Hibernate. Define specific "onLoad", "onSaveorUpdate" etc. events and interceptors for each class. Can I specify permission level for individual fields in this case? http://www.hibernate.org/hib_docs/v3/reference/en-US/html/objectstate-events.html
I might be barking at the wrong tree. All of the above seem to be labour-intensive and not very intelligent. None of the above options give me programmatic ways to change user permissions at runtime, which would be useful when an admin-level user want to give another user more control in this app.
What is a good way of doing data-access control here?
Add a security key to your entities, create a table for permissions and link user with permission with entitytype and also with security key with role. This way you can say things like: Admin_role can access Student (Entitiy type) and do read (Operation in Permission) and Write (Operation) while Student_role can access Student_key for him-/herself and Read_permission. You can fix the address by refactoring that into an entity and adding a security key to it.
Your number four could have a closed-world assumption and say that unless you can for the current role of the user, link the property-name with a flag in a dictionary (entity+property)-hash to flag, the closed world-assumption being that reads are not allowed by default. Then of course you don't get any writes-permissions etc.
You can define views in your database and assign rights to them using the database authentication system. This is probably the most clean way if you are able to code yourself, the way of selecting which view to call depending on which role we are. (My former RDBMS-teacher would love me for saying this ;)) This also goes away a bit from Hibernate and couples your stuff more to the database. It depends on how movable/portable your code needs to be, I guess.
Use an aspect around your generic dao (IRepository) which rewrites the queries based on your permissions; this implies you have the permission-based security in code of course.
The edit-button hiding in the gui can really only be done if you first port the permissions to code, like in my point 1. I suggest you have a look at Ayendes blog for an open-source implementation of this, he's a very skilled coder.
Another option might be to use custom types. For example, instead of mapping a char to a String, map it to a custom type like SecureString. Give it a parameter with some kind of unique identifier in the mapping, e.g. table.column. Then in the custom type's nullSafeGet method, you can call out to a security service to see whether to populate the value or just set it to null. You'd proably also have to use a ThreadLocal to store something to identify the user or role. You'd only have to create a handful of custom types to wrap string, double, date, integer, etc. I've done something similar to allow dates to be converted to the user's time zone.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With