Short question: Is it possible to do a redirection, say when a user isn't logged in, when a page is rendered?
For that you should use a Filter.
E.g.
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
if (((HttpServletRequest) request).getSession().getAttribute("user") == null) {
((HttpServletResponse) response).sendRedirect("error.jsf"); // Not logged in, so redirect to error page.
} else {
chain.doFilter(request, response); // Logged in, so just continue.
}
}
Here I assume that the User is been placed in the session scope as you would normally expect. It can be a session scoped JSF managed bean with the name user.
A navigation rule is not applicable as there's no means of a "bean action" during a normal GET request. Also doing a redirect when the managed bean is about to be constructed ain't gong to work, because when a managed bean is to be constructed during a normal GET request, the response has already started to render and that's a point of no return (it would only produce IllegalStateException: response already committed). A PhaseListener is cumbersome and overwhelming as you actually don't need to listen on any of the JSF phases. You just want to listen on "plain" HTTP requests and the presence of a certain object in the session scope. For that a Filter is perfect.
Yes:
if(!isLoggedIn) {
FacesContext.getCurrentInstance().getExternalContext().redirect(url);
}
You can use a PhaseListener to specify when you want to do redirection.
In a PhaseListener try:
FacesContext ctx = FacesContext.getCurrentContext();
ctx.getApplication().getNavigationHandler()
.handleNavigation(ctx, null, "yourOutcome");
Related
I'm having a JavaEE Website running on a cloud-platform.
Now I want to use two types of authentications:
Is from an SSO-System, which is well integrated in the platfrom and works very nicely.
Is the problematic part: I want to authorize a user from 1) for the time of a session, and give him access to a more restricted resource.
Some details
I get the user and his data from 1).
The user first has to ask for permission to 2), which can be denyed or granted. A user gets authorization from a service, which is outside of the scope of his servlet.
For this purpose I pass a User-POJO (with the session of this user as a member) to a service.
If the service grants the rights to this user, it will set an attribute to the user session:
userSession.setAttribute("auth", "granted");
To restrict access to that resource I use a Filter:
#WebFilter("/supersecret/*")
public class NiceFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
HttpSession session = req.getSession();
// check
if (session.getAttribute("auth") != "granted")
// redirect to login
else
chain.doFilter(req, res);
}
//...
While this is currently working, I feel that my solution is very sloppy.
Altering the user-session outside the scope of a servlet seems to be bad practice.
Adding an attribute to the session for security-purposes is probably not a good idea?
I'd rather want to use standard JavaEE-mechanisms, but most of them are already used for auth-method 1), like declaring login-config in the web.xml.
Any ideas for a more robust solution to this problem?
Thanks in advance :)
I have Spring app that uses JSP. And I need to redirect one page, but only once. It's due the spring security - once the user comes to this page, I need to call redirection to log him out, but to stay on the same page. Is there any way, how to do this only via java, html or js? Or maybe I've asked wrong - there must be some way, how to do this, but I'm not very into frontend technologies, so I'd be glad, if anybody could post some code to show me, how to make this work.. Thanks :)
So the usecase: user types mywebsite.com/login -> I need to call redirect to log him out in the case he's already logged -> the same site shall appear but now without redirection.
PS: I can't redirect the user to another site - it must be the same site with same source code.
If I understand your use case, I would rather log out a user as a part of the login action (i.e. factor out the logging out process, and call it from both the logout action, as well as from the login action).
If that is not feasible (and I can't of a reason why it wouldn't be), I would focus on "redirect if he's logged in" part rather than "redirect only once" part - the former is very easy to check without almost any modification to your code, assuming you're using some kind of sessions to track the logged-in status.
Disclaimer: I know next to nothing about Sprint, these are all very general comments that should work on any classic webapp.
You can use filter .
#Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException {
HttpServletRequest test1= (HttpServletRequest) arg0;
test1.getRequestURL()); it gives http://localhost:8081/applicationName/menu/index.action
test1.getRequestURI()); it gives applicationName/menu/index.action
String pathname = test1.getServletPath()); it gives //menu/index.action
if(pathname.equals("//menu/index.action")){
arg2.doFilter(arg0, arg1); // call to urs servlet or frameowrk managed controller method
// in resposne
HttpServletResponse httpResp = (HttpServletResponse) arg1;
RequestDispatcher rd = arg0.getRequestDispatcher("another.jsp"); redirect to another page at response time
rd.forward(arg0, arg1);
}
donot forget to put <dispatcher>FORWARD</dispatcher> in filter mapping in web.xml
If you do not want to use filter you can redirect to another jsp from urs controller method.
I'm using ServletRequestListener to attach to new requests, get a ServletRequest object and extract cookies from it.
I've noticed that only HTTPServletRequest has cookies but I haven't found a connection between those two objects.
Is it okay to use
HttpServletRequest request = ((HttpServletRequest) FacesContext.getCurrentInstance()
.getExternalContext().getRequest());
to retrieve the request while in a RequestInitialized method? (I do want to run on every request)
FYI - This is all done in a JSF 1.2 Application
This is not correct. The FacesContext isn't available in a ServletRequestListener per se. The getCurrentInstance() might return null, leading to NPE's.
If you're running the webapp on a HTTP webserver (and thus not some Portlet webserver for example), you could just cast the ServletRequest to HttpServletRequest.
public void requestInitialized(ServletRequestEvent event) {
HttpServletRequest request = (HttpServletRequest) event.getServletRequest();
// ...
}
Note that a more common practice is to use a Filter for this since you can map this on a fixed URL pattern like *.jsf or even on specific servlets so that it runs only when the FacesServlet runs. You might for example want to skip cookie checks on static resources like CSS/JS/images.
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
HttpServletRequest request = (HttpServletRequest) req;
// ...
chain.doFilter(req, res);
}
When you happens to be already inside the JSF context (in a managed bean, phaselistener or whatever), you could just use ExternalContext#getRequestCookieMap() to get the cookies.
Map<String, Object> cookies = externalContext.getRequestCookieMap();
// ...
When running JSF on top of Servlet API, the map value is of type javax.servlet.http.Cookie.
Cookie cookie = (Cookie) cookies.get("name");
Yes, you can do that. In Web scenarios, this will always be ok. If you want to be sure, you could do a check for the type first. (Good practice anyway):
if (FacesContext.getCurrentInstance().getExternalContext().getRequest() instanceof HttpServletRequest) {
...
By the way: Why do you have to use FacesContext? From where are you calling this code?
I need to forward my request (to a jsp but I don't think it's matter) from an http.Filter
if the URI of the original request pass some validation that my filter runs.
I found this page that faced similar task
Still I need to figure the following:
How can I get ServletContext in doFilter() method (in order to call forward API) getServletContext() is not recignized
Do I have to call chain.doFilter() before the forward, after the forward or not at all?
In addition do I have to call chain.doFilter() if my validation passed or only if it fails (because in this case I won't continue to forward my page)?
This question actually continue this thread,
to be more obvious, the code could be something like:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (request instanceof HttpServletRequest) {
HttpServletRequest httpServletRequest = ((HttpServletRequest)request);
String requestURI = httpServletRequest.getRequestURI();
String contextPath = httpServletRequest.getContextPath();
if (<this is my implementation of the validation of this filter>){
getServletContext().getRequestDispatcher(
"MySpecific.jsp").forward(request,response);
}
}
chain.doFilter(request,response);
}
How can I get ServletContext in doFilter() method?
httpServletRequest.getSession().getServletContext();
Do I have to call chain.doFilter() before the forward, after the forward or not at all? In addition do I have to call chain.doFilter() if my validation passed or only if it fails (because in this case I won't continue to forward my page)?
I would say that if you forwarded the request, you should not call chain.doFilter() - the forwarded request will get filtered according to its own filter configuration. If your validation failed though, it depends on what the semantics of your web app are - if the original page is some sort of general error/login/welcome screen, you may want to continue to that when the validation failed. It is hard to say without knowing more of the context.
To get the ServletContext, you've got 2 options:
Store off the FilterConfig during the initialization and call FilterConfig.getServletContext()
call HttpServletRequest.getSession().getServletContext()
I don't think you necessarily need the ServletContext to get the RequestDispatcher as you could just call HttpServletRequest.getRequestDispatcher().
In relation to FilterChain.doFilter() call, if you're forwarding, I would think you wouldn't make the call, as once you forward, I assume you don't want any of the standard behavior to take place.
If you don't forward (you don't fall into your if block), then I'd call the FilterChain.doFilter() method, however that assumes there is a target on the other end to be invoked.
I need to know when tomcat accepts a login using realm authentication for a given context. I've been looking at the possible listeners available (ServletContextListener and ServletContextAttributeListener) but can't figure out how to be notified when a login occurs. This should also work when using tomcat single sign on for multiple contexts. Any ideas?
Unfortunately there's no standard/abstract way to hook on it using the Servlet API. You need either to write appserver specific logic or to implement a global Filter which checks the HttpServletRequest#getUserPrincipal() everytime. E.g.:
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) {
HttpServletRequest request = (HttpServletRequest) req;
Principal user = request.getUserPrincipal();
HttpSession session = request.getSession(false);
if (user != null && (session == null || session.getAttribute("user") == null)) {
request.getSession().setAttribute("user", user);
// First-time login. You can do your intercepting thing here.
}
chain.doFilter(req, res);
}
If you have access to the server configuration, you might try writing a LifecycleListener (http://tomcat.apache.org/tomcat-6.0-doc/api/org/apache/catalina/LifecycleListener.html), which are configured with the server (see the tomcat server config docs for your version).
Not sure if it will do the trick or not, but a good place to check.
Good luck.