I'm trying to use WebFilter with JSF 2, but my filter not is working. The urlPattern is not recognized.
My Filter class:
#WebFilter(urlPatterns = {"/rws/*"})
public class AuthorizationFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) request;
HttpSession session = req.getSession(true);
Object o = session.getAttribute("user");
HttpServletResponse res = (HttpServletResponse) response;
if(o == null)
res.sendRedirect(req.getContextPath() + "/login.xhtml");
else
chain.doFilter(request, response);
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void destroy() {
}
}
In my structure I want to protect all pages that are in the rws folder, but I could not configure the filter.
I've tried
# WebFilter ("/ rws / *")
# WebFilter ("/ faces / rws / *")
My filter never is executed!!
I noticed that the url does not change when I browse pages.
For example, the user opens the index.xhtml performs login and then redirects to page loginOk.xhtml.
LoginOk.xhtml page has links to pages that are in the folder rws.
When I click the link url does not change, ie, I'm browsing in a folder page rws but the url in the browser remains the same (http://jsftest.com:8080/TestePrimeFaces/faces/loginOK.xhtml). Is that the problem?
Used a commandLink as link, do not know if it is the most suitable.
Does anyone know where is the problem?
add "#Component" like this.
#Component
#WebFilter(urlPatterns = {"/rws/*"})
public class AuthorizationFilter implements Filter { ...
Servlet filters don't get triggered when you perform a non-redirect JSF navigation on postback. JSF navigation does namely by default not create a new HTTP request (which would trigger the filter), but it just changes the content of the HTTP response while still keeping the same HTTP request (that's also exactly why you don't see a change in browser's address bar).
Adding the FORWARD dispatcher to the filter mapping as some may suggest won't work as JSF on Facelets doesn't use RequestDispatcher#forward() unlike "plain" JSP/Servlet and many other MVC frameworks.
If you want to trigger the filter, just send a new request by a redirect.
So, instead of
public String login() {
// ...
return "home";
}
just do
public String login() {
// ...
return "home?faces-redirect=true";
}
If you worry about faces messages being lost due to the redirect, just make use of the flash scope.
See also:
What is the difference between redirect and navigation/forward and when to use what?
How to navigate in JSF? How to make URL reflect current page (and not previous one)
How to show faces message in the redirected page
Related
I've done my java web app in Java EE with HttpServlet and JSP. I normally map my Servlet like this:
#WebServlet(urlPatterns = "/main")
public class MainServlet extends HttpServlet{
I do my servlet stuff and would like to pass data to JSP file like this:
RequestDispatcher dispatcher = req.getRequestDispatcher("/main.jsp");
dispatcher.forward(req, resp);
The main.jsp is in my web app folder (I use IntelliJ Idea).
The question is, I've initially made my UI with Vaadin 8. Using following:
#Theme("mytheme")
#CDIUI("users")
#SuppressWarnings("serial")
public class Vaadin extends UI
and then override init.
Now I would like to add a single HttpServlet and override doGet and then call the dispatcher to forward data to jsp. Here's the problem adding Vaadin somehow broke the path to tsp, as jsp does not display, instead a standard vaadin
Request was not handled by any registered handler.
appears, I know the servlet was mapped properly as the servlet starts and does work, what does not work is the running the JSP file.
Can anyone advise?
It seems that you need to implement yet a WebFilter to process JSP. Your dispatcher forwards the request but it is then a request that is again handled by some filter by Vaadin I guess. Also I am not sure if you need any servlet and/or dispatcher (not sure what your actual use is).
Anyway, with WebFilter it is possible to intercept this processing. Check the following example
#WebFilter(filterName="jspFilter", urlPatterns="*")
public class JspFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
try {
HttpServletRequest hreq = (HttpServletRequest)request;
String path = hreq.getPathTranslated();
if(path.toLowerCase().endsWith(".jsp")) {
try(Writer writer = response.getWriter();
Reader reader = new FileReader(path) ) {
processJsp(reader, writer);
return;
} catch (Exception e) { /* TODO: handle exception */};
}
} catch (Exception e) { /* TODO: handle exception */};
chain.doFilter(request, response); // forward to filter chain by default
}
#Override public void destroy() {}
#Override public void init(FilterConfig filterConfig)
throws ServletException {}
}
This filter checks all request. If URI (here checked from translated/absolute path) is ending with .jsp it is processed with processJsp(reader, writer) that you might want to implement to do the forwarding to JSP parser or so.
What I am trying to do is the following:
Modify the logback to write out the users id and request id on the log lines.
e.g.
2017-11-24 [userid:abcd123 - requestId:12345679] [ClassA:MethodA1] message...
2017-11-24 [userid:abcd123 - requestId:12345679] [ClassA:MethodA2] message...
2017-11-24 [userid:abcd123 - requestId:12345679] [ClassB:MethodB1] message...
Notice that the requestId remains the same as it is all part of one request made to the system by the end user.
I have created a Filter based off of several examples where it shows how to set values into the MDC. e.g.(https://logback.qos.ch/manual/mdc.html1)
...
#Component
public class RequestFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
String mdcData = String.format("[userId:%s | requestId:%s] ", user(), requestId());
MDC.put("mdcData", mdcData); //Referenced from logging configuration.
chain.doFilter(request, response);
} finally {
MDC.clear();
}
}
private String requestId() {
return UUID.randomUUID().toString();
}
private String user() {
return "tux";
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void destroy() {
}
}
...
If I make a request to a rest service it executes one time without the system making any additional requests to itself for information. This is what I had expected and a I can see the log entries where they all contain the same requestId.
If I make a browser page request to one of our Swagger pages then the web page makes multiple internal requests for additional information that will appear on the page. The logging captures about 20 requests made by the loading of the web page request due to all of the additional requests for information that the page needs to render. When this occurs then I end up with X number of log entries where each of the internal requests are generating a unique request and requestId gets logged for each of them. This was not my intention.
HOW do I determine with a request to the system the initiating portion over the internal request calls that are created?
I need to not set the MDC values for the requestId over and over. I only need it set once per call based on the first request that gets made from the external user.
Not even sure what you would call this other than lifecycle of a request but I'm not finding the answer.
Appreciate any guidance. Thanks.
EDIT: Link to another question I have out there that is only dealing with identifying the original user request.
One way to address this is to map you RequestFilter to the URL pattern of your services that you want to log and not to "/*".
EDIT: Another idea would be to map the filter to "/*" but in your doFilter method, do not MDC any requests that contain "swagger" in the URL. You might have to experiment and possibly include all the URL's that get generated from the Swagger page, as some may not contain the word "swagger" in them.
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (isRequestSwaggerUrl(request)) {
chain.doFilter(request, response);
return;
}
try {
String mdcData = String.format("[userId:%s | requestId:%s] ", user(), requestId());
MDC.put("mdcData", mdcData); //Referenced from logging configuration.
chain.doFilter(request, response);
} finally {
MDC.clear();
}
}
I have a simple implementation of login filter.
public class LoginFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
if (session == null || session.getAttribute("loggedInUser") == null) {
response.sendRedirect(request.getContextPath() + "/login.jsp");
} else {
chain.doFilter(request, response);
}
}
#Override
public void destroy() {}
}
When I go to any registered page(i.e. /account?id=1) without session attribute loggedInUser, filter works fine. It redirects me to login page.
But if I go to non-exists page (i.e. /blablabla.html), filter redirects me to login page again. Is there any method to get 404 error on entering non-exists pages and redirect to /login on exists?
The bug is in the requirement: you filter all requests to deny access to guests but still want the request to be processed if it's a 404. This would be conceptually wrong: a 404 is still an applicative response in the sense that it gives the user a view of the internals of the system - so the user must be authorized before knowing that something is or is not there.
Another option is splitting your app in a public and a private zone:
/public/style.css
/public/app.js
...
/private/customer/123
/private/oder/8932
...
and just filter requests in the private zone.
Note: if you are concerned about the beauty of the URL consider that the /private/ prefix is not a requirement. The filter can be attached in such a way that any prefix can be omitted
Remember the filters are there to filter any incoming request or outcoming response, so actually the flow is something like this.
client -----> request ---- > filter ----> servlet dispather ----> resources
So now, unfortunately the request will be intercepted by the filter no matter is the resource exist or not, and this happens before the servlet dispather can get the request and get realize that the resource doesn't exist.
I hope, this explanation can answer your question.
Thanks.
In My application I did java project with ajax calling here I have a problem without Login also user can type url accessing the pages for that I used the below code but when i add the below code it's not working. I am getting Page not found error even I am unable to getting a login page also.
#WebFilter("/*")
public class LoginFilters implements Filter {
#Override
public void init(FilterConfig config) throws ServletException {
// If you have any <init-param> in web.xml, then you could get them
// here by config.getInitParameter("name") and assign it as field.
}
private static final String AJAX_REDIRECT_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<partial-response><redirect url=\"%s\"></redirect></partial-response>";
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
String loginURL = request.getContextPath() + "/Login.jsp";
boolean loggedIn = (session != null) && (session.getAttribute("Username") != null);
boolean loginRequest = request.getRequestURI().equals(loginURL);
boolean resourceRequest = request.getRequestURI().startsWith(request.getContextPath() + "/Login.jsp");
boolean ajaxRequest = "partial/ajax".equals(request.getHeader("Faces-Request"));
if (loggedIn || loginRequest || resourceRequest) {
if (!resourceRequest) { // Prevent browser from caching restricted resources. See also https://stackoverflow.com/q/4194207/157882
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0); // Proxies.
}
chain.doFilter(request, response); // So, just continue request.
}
else if (ajaxRequest) {
response.setContentType("text/xml");
response.setCharacterEncoding("UTF-8");
response.getWriter().printf(AJAX_REDIRECT_XML, loginURL); // So, return special XML response instructing JSF ajax to send a redirect.
}
else {
response.sendRedirect(loginURL); // So, just perform standard synchronous redirect.
}
}
#Override
public void destroy() {
// TODO Auto-generated method stub
}
// ...
}
can anyone tell me how can i do this
You should take a look to this : Securing a Web Application
Securing a Web Application
This guide walks you through the process of creating a simple web
application with resources that are protected by Spring Security.
What you’ll build
You’ll build a Spring MVC application that secures the page with a
login form backed by a fixed list of users.
Spring is absolutely the best solution and I really recommend to use it: it helps you on everything! If you don't want to use it right now and you don't care about security too much you can roughly use a session token or a simple static token(even a boolean, a char or a string) that checks if the user is coming from a certain page or not:
if the code in a certain servlet(or in spring controller) is executed you should set this boolean-whateverYouWant field to a certain value: when you load a page you can check the value of that field(spring mvc-angularJs or javascript) and then you can show the right page: "Not Allowed" if the token is null or void or what you prefer!
The best and definitely solution would be spring security-angularJs and web services exposed in a spring mvc controller. Seriously... think about learning spring!
I'm currently writing a little dynamic web-application in Java.
The application is supposed to be an event-platform where you can create a user-account, log in, and then you can see all open events (in a later iteration, users can create/participate in those events).
Right now, the structure of the web-app could be (simplified) described like this:
Register-Servlet -> Register.jsp
|
V
Login-Servlet -> Login.jsp
|
V
Main-page-Servlet -> Main.jsp
So right now, a user could go to Login.jsp, his login-information would be sent to the Login-Servlet, which would validate it and then send it to the Main-Page-Servlet.
The Main-Page-Servlet then (after validating login again) gets all current events from a database, attaches it to the request, and forwards it to the Main.jsp, which displays it for the user to see.
Now, if a user wants to access the Main.jsp directly (without coming from the Main-Page-Servlet), it obviously can not display the available events. The workaround I'm using currently is doing a null-check to see if the events are there, and if not, redirect to the Main-Page-Servlet.
It bothers me to solve my problem like that, as I don't think that's the best practice and I think it will just create a lot of other problems the bigger my application gets.
My first thought about this was, that it might be useful if I could simply "hide" all .jsp's from the user, so the user would be landing on servlets only and could not access the .jsp's in a different way.
Is there a way to do that? Or, if not, what would be the best practice solution if I would be writing a professional enterprise-level application?
This can be handled in a Filter and there are great explanation and example in StackOverflow Servlet-Filter wiki.
Adapting the code there for your problem (note the addition and usage of the needsAuthentication method):
#WebFilter("/*")
public class LoginFilter implements Filter {
#Override
public void init(FilterConfig config)
throws ServletException {
// If you have any <init-param> in web.xml, then you could get them
// here by config.getInitParameter("name") and assign it as field.
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
String requestPath = httpServletRequest.getRequestURI();
if (needsAuthentication(requestPath) ||
session == null ||
session.getAttribute("user") == null) { // change "user" for the session attribute you have defined
response.sendRedirect(request.getContextPath() + "/login"); // No logged-in user found, so redirect to login page.
} else {
chain.doFilter(req, res); // Logged-in user found, so just continue request.
}
}
#Override
public void destroy() {
// If you have assigned any expensive resources as field of
// this Filter class, then you could clean/close them here.
}
//basic validation of pages that do not require authentication
private boolean needsAuthentication(String url) {
String[] validNonAuthenticationUrls =
{ "Login.jsp", "Register.jsp" };
for(String validUrl : validNonAuthenticationUrls) {
if (url.endsWith(validUrl)) {
return false;
}
}
return true;
}
}
I would recommend to move all the pages that require authentication inside a folder like app and then change the web filter to
#WebFilter("/app/*")
In this way, you can remove the needsAuthentication method from the filter.
There're several ways to do it such as servlet filter as above. I saw in some projects they use a simpler mechanism to do it by creating a common action (servlet). So instead of extends HttpServlet, all servlet will be extended the common action. And you can implement a lot of common stuffs such as authentication, validations, permissions...
Here's common action example:
public class CommonServlet extends HttpServlet {
................
................
protected boolean validate(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html; charset=UTF-8");
request.setCharacterEncoding("UTF-8");
String email = (String) request.getSession().getAttribute("email");
Object salaryGroup = request.getSession().getAttribute("SALARY_GROUP");
if (email == null || email.equals("")) {
request.setAttribute("err", "You have not logged in");
request.getRequestDispatcher("/login.jsp").forward(request, response);
return false;
}
................
................
}
public void setRoleAndValidate(HttpServletRequest request, HttpServletResponse response, String role)
throws ServletException, IOException {
if (!validate(request, response)) {
return;
}
setRoleCode(role);
}
................
................
}
Your action servlet will be as below:
#WebServlet("/employeeManager")
public class EmployeeManager extends CommonServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
request.setCharacterEncoding("UTF-8");
setRoleAndValidate(request, response, Permission.EMPLOYEE_LIST.toString());
String action = request.getParameter("action");
.....
Here's the simple implementation