j_security_check vs Programmatic Security - jsf

I'm building a Web application using jsf, ejbs and jpa.
I currently use form based j_security_check to handle authentication.
I need to implement support for cookies ie "Remember me" option.
Also I want to prevent brute force attacks. ie Lock a certain user after 5 failed logons.
I understand that the other option will be to do it programmatically using ServletFilters etc.
Is there any way of implementing all these Using j_security_check? or should I just switch back to doing it programmatically?

This has to be custom implementation around j_security_check. You can attach a servlet filter with j_security_check
<filter-mapping>
<filter-name>SecurityFilter</filter-name>
<url-pattern>/j_security_check</url-pattern>
</filter-mapping>
In the SecurityFilter, after security check returns userPrincipal, set further details in session and continue. But if userPrincipal is null, fetch the fail count from database and put the failure message (including fail count) in session, which can be displayed in login page.
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
Principal userPrincipal = null;
String username = httpServletRequest.getParameter("j_username");
String rememberme = httpServletRequest.getParameter("rememberme");
chain.doFilter(request, response);
userPrincipal = httpServletRequest.getUserPrincipal();
Remember me has to be set at cookies and the value of the variable "rememberme" will be available after the j_security_check is completed. Based upon success or failure in login, cookie can be set.

Related

How to add csrf token for immediate file upload for Spring Security 3.2?

I have been trying to add CSRF token for file uploads in my Spring application having spring security 3.2. The Spring Security CSRF documentation suggests we add MultipartFilter before the spring security filter so that temporary file upload becomes possible without spring security altogether (and hence without CSRF checking also). But wouldn't that be less secure?
Although, to have a working software atleast, I applied the above method but its not working. In error log it looks like the multipart filter is being triggered before the spring security filter, but still it IS going in the spring security filter and then to CSRF filter.
I am using <rich:fileUpload> with immediateUpload="true" to upload the file in the form.
May I get some help in applying this? It would be better if we can add the CSRF token itself instead of circumventing the security filter.
MultipartFilter does not stop the spring security filters from being invoked. But by putting it as the first filter in the filter chain, when there is a csrf token available in body as a param, it makes it possible for csrf token filter to extract the csrf token from body and verify it.
Short answer
You still neef to send csrf token but you can send it in body as a hidden param or in the url as a query param.
Note:
I dont have knowledge about the ui component you use but in your previous get request, you should have received a _csrf token as hidden param and you should include it as part of the url or as a hidden param in the multipart request.
If it is not clear, just to make a GET and POST request working without fileupload to understand the csrf flow
Alternative: Skip the csrf only for file upload
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf()
.requireCsrfProtectionMatcher(new CustomRequiresCsrfMatcher())
.and()
......
}
private static final class CustomRequiresCsrfMatcher
implements RequestMatcher {
private final HashSet<String> allowedMethods = new HashSet<>(
Arrays.asList("GET", "HEAD", "TRACE", "OPTIONS"));
#Override
public boolean matches(HttpServletRequest request) {
String upload_url = "your file upload url";//update it
return !this.allowedMethods.contains(request.getMethod()) &&
!request.getRequestURL().toString().contains(upload_url);
}
}

How do I limit a user from accesing sertain pages in JSF? [duplicate]

This question already has answers here:
How implement a login filter in JSF?
(2 answers)
Closed 2 years ago.
Like the title says, how do I limit users from accessing certain pages in JSF? I have two different kinds of pages that I want to limit access to. The first one is pages that need parameters to load, would it be possible to redirect if a user tries to redirect access that page without any parameters? The second one is pages that only certain users should have access to. In my app you have the ability to create and edit competitions, however, I only want the host of the event to be able to access the edit page for that event - which at the moment anyone can access if they know the right parameters. Is there something in JSF that lets me do this?
General page access
Have a look at #WebFilter and its doFilter method. Inside you can check if your user is logged in retrieving your session scoped bean from the HttpSession.
#WebFilter(filterName = "UserAuthenticationFilter", urlPatterns =
{
"/sites/user/account.xhtml"
} , dispatcherTypes =
{
DispatcherType.FORWARD, DispatcherType.REQUEST, DispatcherType.ERROR
})
public class UserAuthenticationFilter extends HttpFilter
{
#Override
public void doProductionFilter(final HttpServletRequest request, final HttpServletResponse response, final HttpSession session, final FilterChain chain) throws IOException, ServletException
{
final UserBean userBean = session.getAttribute("userBean");
// check if logged in and redirect to login page if not
if (userBean.isLoggedIn()
chain.doFilter(request, response);
else
response.sendRedirect(request.getContextPath() + "/login.xhtml");
}
}
Specific page access
Check your request param either in your #PostConstruct or better in your viewAction or initPreRenderView methods since in the later two you have access to your injected view parameters.
If user does not has sufficient rights to access the data redirect or/and show faces message or do something else.

Liferay Portlet Response: how to set status code?

I have a simple method accepting PortletResponse and PortletRequest in my liferay portlet
public void remove(PortletResponse response, PortletRequest request) {
}
I want to set response status to 404, like I can do with HttpServletResponse by httpResponse.sendError(HttpServletResponse.SC_BAD_REQUEST)
Can you tell me how I can do it?
What does Portlet Specification 2.0 have to say - you can set the response status only when handling resource request:
If the portlet want to set a response status code it should do this
via setProperty with the key ResourceResponse.HTTP_STATUS_CODE.
That means, you can set the response status code this way when serving resources:
resourceResponse.setProperty(ResourceResponse.HTTP_STATUS_CODE,
Integer.toString(HttpServletResponse.SC_BAD_REQUEST));
With Liferay, you can get instance of the underlying HttpServletResponse and set status code there. The portal will return it to the client. This way, you can set the response status for any portal request, not only resource request.
HttpServletResponse httpServletResponse = PortalUtil.getHttpServletResponse(portletResponse);
httpServletResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST);
However, such practice is strongly discouraged as well explained in Olaf Kock's answer. See it to get the bigger picture.
In addition to Tomas Pinos' answer (please accept his answer): Note that a portlet is never delivered directly by an HttpServletRequest - it's embedded in a page which is generated by the portal. Thus the HTTP response codes don't have any meaning (for portlets) in the portal world: The page might still be there, just contain or not contain the portlet in question - it's the business of the portal to show whatever it likes then.
The only exception to this rule is what Tomas describes correctly: When handling a resource request, you're serving exclusive content - thus you have the option to do more to the request than just piping HTML that would otherwise be embedded in a page generated by someone else (the portal, together with other unknown portlets)

Invalidate Session of a specific user

So for my webapp, if I remove a user that is currently logged in, and I want to invalidate his/her session. So that as soon as he/she refresh the page or navigate, they are no longer log in. The way I have now is that if a User logged in successfully, I will store the user object in my SessionScoped bean, and store the HttpSession to the Application Map. Below is my code
This is my SessionScoped bean
#PostConstruct
public void init() {
User user = UserDAO.findById(userId, password);
Map<String, Object> appMap = FacesContext.getCurrentInstance().
getExternalContext().getApplicationMap();
HttpSession session = (HttpSession) FacesContext.getCurrentInstance().
getExternalContext().getSession(false);
appMap.put(userId, session);
}
Is this a correct approach? If so, how do I clean up my application map?
Is this a correct approach?
There are basically 2 ways.
Store the HttpSession handle in the application scope by the user ID as key so that you can get a handle of it and invalidate it. This may work for a small web application running on a single server, but may not work on a web application running on a cluster of servers, depending on its configuration.
I would only store it in another map in the application scope, not directly in the application scope like as you did, so that you can easier get an overview of all users and that you can guarantee that an arbitrary user ID won't clash with an existing application scoped managed bean name, for example.
Add a new boolean/bit column to some DB table associated with the user which is checked on every HTTP request. If the admin sets it to true, then the session associated with the request will be invalidated and the value in the DB will be set back to false.
how do I clean up my application map?
You could use HttpSessionListener#sessionDestroyed() for this. E.g.
public void sessionDestroyed(HttpSessionEvent event) {
User user = (User) event.getSession().getAttribute("user");
if (user != null) {
Map<User, HttpSession> logins = (Map<User, HttpSession>) event.getSession().getServletContext().getAttribute("logins");
logins.remove(user);
}
}
I think you can use your approach (with some modifications proposed by #BalusC) plus some notification mechanism (to make it work in distributed environment). You can do one of the following:
Use a topic queue subscribed by all your servers. When you remove user from your admin panel the JMS message will be created and sent to the topic. Every server will be responsible for invalidating the user session if it exists on the particular server (if the session is referenced in servletContext map).
Implement some action to invalidate the user session and run this action on every server in the cluster (The admin panel should send HTTP request to every server).
Use JGroups and TCP reliable multicast.
All of these solutions are not simple but much faster than polling the DB server on every request.

JSF PhaseListener viewId always one behind

Im trying to prevent users to access special pages with a phaselistener. for that reason im trying to figure out on which page they try to access.
but my problem is, i only get the page they where before. not the actual page.
public void afterPhase(PhaseEvent event)
{
FacesContext fc = event.getFacesContext();
System.out.println("test1" + fc.getViewRoot().getViewId());
}
and same here
public void afterPhase(PhaseEvent event)
{
FacesContext fc = event.getFacesContext();
HttpServletRequest request = (HttpServletRequest) fc.getExternalContext().getRequest();
String uri = request.getRequestURI();
System.out.println("uri: " + uri);
}
why is that, and how do i get the pagename the user is trying to access? Not that one that they required one step before, or better the page they are coming from.
It is one step behind because that is the way sequence of HTTP POST request behaves. When you are navigating in JSF application via command buttons each request goes as a post request.
Since you are protecting some resources make sure they are accessed via HTTP GET than you will get exact view id, this can be achieved as
User directly hits the url from address bar of browser.
After a post of jsf app redirect it to the resource instead of simple JSF navigation. POST-REDIRECT-GET pattern falls into this have a look here.
If you are showing some messages after each POST, you might need Flash map for that, which is new feature in JSF2, if you are on JSF1.x hard luck, you can implement flash if you want to.
To conclude catch the view ids on HTTP GET request.
Hope this helps...

Resources