I am about to graduate from university with a web application that needs be implemented at school, everything is working perfect and this needs to be ready before november but I'm having a real trouble taking care of the security. The application must be able to have different users with one or more different roles, ( user1: roles: student; user 2: admin, user 3: professor, boss ).
When a user logs in it should be redirected to a different view depending on the roles it has and then if he tries to access to resources not allowed for his role, an error page should be shown.
This is what I've tried so far:
Method 1:
Authentication Method: Specified in web.xml as
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
</form-login-config>
</login-config>
Then using the names j_username and j_password along with j_security_check on a custom jsp.
Authorization Method: Used Container Security (Tomcat) via DataSourceRealm, wich allow us to connect to a database and get the user and the roles associated with him from 2 Tables that need to be mapped in the server.xml:
<Resource auth="Container" driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver" maxActive="100" maxIdle="30" maxWait="1000" name="jdbc/sstt" password="pass" type="javax.sql.DataSource" url="jdbc:sqlserver://localhost;databaseName=BDTT" username="sa"/>
web.xml:
<security-constraint>
<web-resource-collection>
<web-resource-name>Students Only</web-resource-name>
<url-pattern>/student/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>student</role-name>
</auth-constraint>
</security-constraint>
// Same mapping for professor, admin, and boss (/professor/* maps to professor role)
Results: Whenever I tried to access a restricted area, for example, /members/ (configured in the web.xml inside a security constraint) it would work just perfect, so authorization goal was achieved.
The problem:
When I submit the login form it fires the j_security_check so I'm not able to fire a Struts2 Action that could help me to redirect depending on the user roles this is the main problem. Everything was perfect but I can't find a way to redirect after logging in with the Container security.
Method 2:
Authentication Method: A LoginAction class that queries the database and checks if the password is correct. It also checks on the user roles and here we should be able to return a String like "admin", or "student" and redirect to the appropriate index.jsp resource, but that would work only if users were allowed to have only one role, but they can have many, so how should the view be constructed depending on the total user roles? What String would we return?
Authorization Method: I wrote a custom Interceptor wich retrieves the User object from the session (this User object should be in the session only if the user authenticated successfully) and then perform the authorization logic here.
The problem:
Unable to find a way to construct a view depending on several roles, and the problem about the Interceptor is that it only protects my actions, so the authorization goal was achieved but only on actions, that means I could write /students/ and the URL would change to /students/index.jsp without even trying to authorize.
Other plans
I was thinking that maybe I could use filters to achieve the authorization ( that way I could protect both the dynamic and static resources ) but I don't know if that would be a good practice since we have configured the Struts2 filter which maps to /*
I was also looking that I could use JAAS or Spring Security but I don't know if I could achieve this, authenticate, redirect based on roles and authorizate. I wouldn't want to spend more several hours to find out that I can't do what I need, and I have just a very short time to finish this.
Other questions
Is it really a good practice to put jsp under WEB-INF? if so I should rewrite all the access to my jsp's in the struts.xml to WEB-INF/jsp/students/index.jsp? ( for example ). Or should I stick to a security constraint defined in web.xml to avoid direct access to the /jsp/* url pattern?
Thank You very much in advance for all your time and help.
For problem in method 1: You can write Struts2 interceptor to achieve what you want.
For Spring Security examples see my answer to this question https://stackoverflow.com/questions/12615354/how-to-implement-role-based-login/12629731#12629731
And YES it is a good practice to put jsp under WEB-INF folder. See Why put JSP in WEB-INF?
Related
How apply auth restriction in JSPUI? I was wanting in JSPUI apply when the user tries to access the feedback form, the dspace require authentication, but I could not understand how the pages that require authentication as in 'mydspace' works in JSPUI.
It is possible for jsp pages? or need change java class?
The authentication requirement is set up in web.xml (link to 5.x version). It may be enough to add another filter-mapping clause for the feedback URL, eg
<filter-mapping>
<filter-name>registered-only</filter-name>
<url-pattern>/feedback</url-pattern>
</filter-mapping>
But I haven't tried it! This may not work.
I am developing a Java EE business management application using the following technologies:
JSF
JPA
GlassFish 4
Derby 10.10.1.1
As a start, I created the following objects:
Person (JPA Entity)
Name
Address
Email
etc.
PersonManager (Stateless EJB)
createPerson
deletePerson
updatePerson
findPersonById
I then created the following xhtml pages with backing beans.
PersonCreater
PersonViewer
PersonUpdater
Using JSF and JPA, I found it easy to create the xhtml with backing bean to support creating, viewing and updating my person object.
Using the Java EE Security #RolesAllowed annotation, it was easy to limit access to the PersonManager methods to specific roles, and using the web.xml security-constraint element it was easy to limit JSF page access to specific roles.
I am now to the point where I want to add sensitive information such as social security number to my Person entity, but I only want specific roles to be able to create, read and update the sensitive information. Is there a standard way to add sensitive information to an entity and then control access?
My fundamental problem is with the PersonManager's getPersonById method. Currently, this method looks like the following:
#RolesAllowed("Reader")
public Person findPersonById(long id) {
return em.find(Person.class, id);
}
If I add the social security number property to the Person entity, the method will return the social security number with the returned Person to all users with role Reader. Of course, I want everyone to be able to read most of the data associated with my Person object, but I don't want everyone to be able to read the Person's social security number.
I could add logic to the gerPersonById method to remove sensitive information from the Person object based on the current role using the EJBContext's getCallerPrincipal and isCallerInRole methods. Is this a good way to limit access to the social security property?
I thought about putting all the sensitive information in another entity called PersonSensitive and then creating a OneToOne relationship between Person and PersonSensitive. However, this leads me back to the problem of how do I limit access to specific entity fields based on the current role. I tried using #RolesAllowed on the Person entity but this did not work.
I might be able to use some type of inheritance scheme where the sensitive data belongs to a descendant of Person and only specific roles can access the descendant's manager methods. However, this leads me to creating sets of JSF pages where each set is designated for use by a specific role. Maybe this is the best way to move forward but it seems like it will require much extra work.
I would like to apply security constraints for all webapps deployed on a Tomcat7 server. To do this I have set up a Realm and Valve. My understanding is that the contents of context.xml get included for all apps deployed to a server - that part seems to work as I can add all manner of configuration and I see the effects as it gets included in the various deployed app contexts. It works wonderfully for enforcing consistency across web apps.
What doesn't seem to work is trying to define a security-constraint like the one below outside of web.xml:
<security-constraint>
<web-resource-collection>
<web-resource-name>myServletWAR</web-resource-name>
<url-pattern>*.jsp</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>my_role</role-name>
</auth-constraint>
</security-constraint>
I'm doing it in context.xml between the Context tags. No complaints from Tomcat, but no security constraint is applied, e.g I can hit the app without a password. With the constraint above in context.xml I see:
Aug 14, 2013 3:03:32 PM org.apache.catalina.authenticator.AuthenticatorBase invoke
FINE: Not subject to any constraint
...in the logs, and can get to the "protected" resource with no auth.
Moving the same constraint to a webapps's web.xml, of course, yields the expected constraint behaviour, but I need to ensure the constraint is applied consistently across all deployed apps on a given server.
Does security-constraint need to be inside of a web-app? If it does how can I define a security-constraint across several (as yet deployed) web-apps if not in context.xml?
This is exactly what I am trying to set up, but I want to enforce the constraint outside (above) web.xml. Again, so that it will be consistent for the entire server.
I did see another similar question, but I'm trying to find a way to do this in Tomcat configuration without having to use the Servlet API from the code base (that is already written).
Thanks!
The second after I posted my question I realized that:
$CATALINA_BASE/conf/web.xml was the answer I was looking for.
It's root element, as one would expect, is web-app, and the contents get added to each deployed web app (like context.xml for each context) adding the security-constraint worked.
I did have to re-start Tomcat (it doesn't auto deploy for changes in that file apparently), but that is not an issue as this shouldn't change in production.
I'm new at Spring Security. I've read the docs and I have two questions, in order to integrate it in my webapp:
(1) I use Hibernate. Is it better to config the authentication customizing the authentication provider by implementing the UserDetailsService, accessing the Dao?
Or is it better to config it with a JDBC-user-service referencing the database connection and specifying the querys on the user and user_roles tables?
I think using Hibernate Dao is more difficult, but it would be a more database independent solution, isn't it?
(2) In either of both cases above (Hibernate vs JDBC), do I have to implement in the presentation layer the methods to login and logout? Or Spring Security framework dooes it automatically for me? I know I can use the UserDetails to know the info about the current user logged in, in order to use it in the views, for example to show or not the links for login/logout depending on wether the user is logged in or not. But what about the methods?
Any help would be appreciate. Thank you very much in advanced.
As far as I understand, implementing the UserDetailsService is more for user customization . If you can get the data by a straightforward query, use JDBC-user-service .
You do not need to implement the methods . Spring will take care of login and logout depending on your configuration. For clogoff ,you could wrap the link with 'j_spring_security_logout'
<c:url value="/j_spring_security_logout"/>">
Check the form-login element for more info . A sample is as below.
<form-login login-page="/login.jsp"
default-target-url="/welcome.jsp"
always-use-default-target="true"
authentication-failure-url="/login.jsp?error=true" />
I've been a little puzzled with this as I have not seen many examples that gave me the complete picture. The best explanation I found so far is this.
By defining a security role in web.xml such as "admin" for example, and having my login form with all the necessary fields (i.e j_security_check as action, and fields j_username, j_password), how/where does the actual authentication occur?
I plan to use a custom authentication using username/passwords (hashes) stored in the database. When the user submits the form, how do I make the Java EE Web Container invoke my sevlet/bean method do perform the actual authentication? I didn't notice any place to add a hook to my code in web.xml which would do the actual authentication.
By defining a security role in web.xml such as "admin" for example, and having my login form with all the necessary fields (i.e j_security_check as action, and fields j_username, j_password), how/where does the actual authentication occur?
In the servlet implementation, the servletcontainer. In Tomcat for example, it's done by the AuthenticatorBase class (source code here).
I plan to use a custom authentication using username/passwords (hashes) stored in the database. When the user submits the form, how do I make the Java EE Web Container invoke my sevlet/bean method do perform the actual authentication? I didn't notice any place to add a hook to my code in web.xml which would do the actual authentication.
If you'd like to keep using container managed authentication, but instead want to check the login against a database, then you need to configure the so-called "realm" accordingly. It's unclear which servletcontainer you're using, but in for example Tomcat, the documentation is available here: Tomcat 6.0 Realm HOW-TO.
If you really want to have your own homegrown authentication system invoked instead, then you need to drop the container managed security and homegrow it further. Which is not recommended.
The actual authentication is doing via either two ways:
Via a Server Proprietary way, e.g. the *LoginModules in JBoss, or the Tomcat one BalusC mentioned. These are different for each Server.
Via JASPIC, which was introduced in Java EE 6.
JASPIC pretty much has standardized the proprietary methods, but it's a fairly low-level API and unfortunately only available for full profile Java EE 6 and 7 implementations.
See Implementing container authentication in Java EE with JASPIC for more details.