I've written a application with a custom login system. And then written my own security filter for it which sets the area that can be accessed. Yet I always get redirected to the login page and then to the index page with is the logged in home page. I have discovered that the session ID is different from when I login to when I try to use something that is restricted. Here is my code:
public class securtityFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
//To change body of implemented methods use File | Settings | File Templates.
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
// if there is no userBean, then they have not gone through
// the login, so kick them to the login page
if(null==req.getSession().getAttribute("username"))
{
((HttpServletResponse)servletResponse).sendRedirect("../Login.jsp");
System.out.println("Redirected - No session");
}
// otherwise, let them go to the page/resource they want
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("Gone through Filter");
// System.out.println("In Filter Servlet: "+ req.getSession().getId());
}
public void destroy() {
//To change body of implemented methods use File | Settings | File Templates.
}
}
Here is my web.xml file:
<filter>
<filter-name>SecurityFilter</filter-name>
<filter-class>filters.securtityFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SecurityFilter</filter-name>
<url-pattern>/add/*</url-pattern>
</filter-mapping>
In your login servlet you have
while (rs.next())
{
HttpSession session = request.getSession(true);
String tmp = rs.getString(1);
System.out.println(tmp);
session.setAttribute("username", tmp);
count++;
}
So if you have no username attribute in your session, it is because this code block is not being executed. I assume that you are looping through the results of a database query, so check whether the actual query that you are executing returns any results.
Try changing
if(null==req.getSession().getAttribute("username"))
to
HttpSession ses = req.getSession(false); // null if no current
if(null == ses ||
null == ses.getAttribute("username"))
so that it never creates a new session inside your filter. Let the login page create the sessions.
Related
It is possible to set up #RequestMapping annotation to only allow viewing a page if a session exists? (The user is logged on.)
If you don't want to use spring-security for some reason and want to have your custom implementation to allow access only is session exists, then you could also write a RequestFilter that implements javax.servlet.Filter, and check if the request has a valid session then allow it to go through else show an error page. Here's an example.
public class RequestAuthenticationFilter implements Filter {
private static final Logger LOG = Logger.getLogger(RequestAuthenticationFilter.class);
protected static final List<String> ALLOWED_URL_LIST = Arrays.asList("/login.htm", "/400.htm", "/403.htm", "/404.htm", "/405.htm", "/500.htm", "/503.htm");
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest req, ServletResponse response, FilterChain filterChain) throws IOException,
ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpSession session = request.getSession(false);
String url = (request.getRequestURI());
if(ALLOWED_URL_LIST.contains(url) || url.endsWith(".css") || url.endsWith(".js") || url.endsWith(".png")
|| url.endsWith(".jpg") || url.endsWith(".jpeg") || url.endsWith(".ttf") || url.endsWith(".woff")
|| url.endsWith(".csv")) {
filterChain.doFilter(request, response);
}
else if((null == session) || session.getAttribute("user") == null
|| StringUtils.isEmpty(((User) session.getAttribute("user")).getUsername().trim())) {
((HttpServletResponse) response).sendRedirect("/login.htm");
}
else {
filterChain.doFilter(request, response);
}
}
#Override
public void destroy() {
}
}
In this example the additional check is that if the request is for any image,js,css file then we skip the session check.
Once you have added the filter implementation, you will have to next make sure that all the requests that you want to validate with session go through this Filter. For that you will have to create a bean for this filter and then reference that bean in your web.xml
Here's what you will have to include in your web.xml. Here the is the name with which you create the bean for your filter. And the can be used for deciding which url's you want verified for session check with this filter
<filter>
<filter-name>requestAuthenticationFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>requestAuthenticationFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
You can set it up through Spring-Security fairly easily - for eg. consider a sample configuration from Spring-security site:
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**", "/signup", "/about").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/db/**").access("hasRole('ROLE_ADMIN') and hasRole('ROLE_DBA')")
.anyRequest().authenticated()
.and()
// ...
.formLogin();
}
here paths mapped with /resources is allowed for everybody(including anonymous users), everything else requires the user to have some role or atleast to have logged in.
I am new to web programming. I am asking a common pattern to do things like checking authentication. Here is the scenario:
The website has a login page for visitors. It will take username and encrypted password and sent them to server, then get either a error code (username/password doesn't match)or an auth key from the server. When the user logged in successfully, I want the website automatically jump to the main.jsp page that presents the main functionality of the website.
In this case, I want main.jsp check the user authentication. That is, I don't want such thing happens like user can directly open www.example.com/main.jsp, and if they did thing like this, I want to redirect them to login page.
So how could I pass authentication information across page, and how could I prevent user from directly accessing the main.jsp without login? Do I need to use session or anything?
you could try using filters:
Filter can pre-process a request before it reaches a servlet,
post-process a response leaving a servlet, or do both.
Filters can intercept, examine, and modify requests and responses.
NOTE: be sure to add a session attribute once your user is logged in, you can use that session attribute on the filter
on your login.jsp add:
session.setAttribute("LOGIN_USER", user);
//user entity if you have or user type of your user account...
//if not set then LOGIN_USER will be null
web.xml
<filter>
<filter-name>SessionCheckFilter</filter-name>
<filter-class>yourjavapackage.SessionCheckFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SessionCheckFilter</filter-name>
<!--url-pattern>/app/*</url-pattern-->
<url-pattern>/main.jsp</url-pattern> <!-- url from where you implement the filtering -->
</filter-mapping>
SessionCheckFilter.java
public class SessionCheckFilter implements Filter {
private String contextPath;
#Override
public void init(FilterConfig fc) throws ServletException {
contextPath = fc.getServletContext().getContextPath();
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain fc) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
if (req.getSession().getAttribute("LOGIN_USER") == null) { //checks if there's a LOGIN_USER set in session...
res.sendRedirect(contextPath + "/login.jsp"); //or page where you want to redirect
} else {
String userType = (String) req.getSession().getAttribute("LOGIN_USER");
if (!userType.equals("ADMIN")){ //check if user type is not admin
res.sendRedirect(contextPath + "/login.jsp"); //or page where you want to
}
fc.doFilter(request, response);
}
}
#Override
public void destroy() {
}
}
How JSP page should check authentication
It shouldn't. You should use Container Managed Authentication, and define the login/security in web.xml via URL patterns.
Added by Glen Best:
E.g. Add something like this to web.xml:
<security-constraint>
<display-name>GET: Employees Only</display-name>
<web-resource-collection>
<web-resource-name>Restricted Get</web-resource-name>
<url-pattern>/restricted/employee/*</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>Employee</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
This also works for me
<filter>
<filter-name>SessionCheckFilter</filter-name>
<filter-class>yourjavapackage.SessionCheckFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SessionCheckFilter</filter-name>
<!--url-pattern>/app/*</url-pattern-->
<url-pattern>/main.jsp</url-pattern> <!-- url from where you implement the filtering -->
</filter-mapping>
public class SessionCheckFilter implements Filter {
private String contextPath;
#Override
public void init(FilterConfig fc) throws ServletException {
contextPath = fc.getServletContext().getContextPath();
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain fc) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
if (req.getSession().getAttribute("LOGIN_USER") == null) { //checks if there's a LOGIN_USER set in session...
req.getRequestDispatcher("login.jsp").forward(req, resp); //or page where you want to redirect
} else {
String userType = (String) req.getSession().getAttribute("LOGIN_USER");
if (userType.equals("ADMIN")){ //check if user type is admin
fc.doFilter(request, response); it redirected towards main.jsp
}
}
}
#Override
public void destroy() {
}
}
How about using:
String username = request.getRemoteUser();
I have problems with AccessFilter in java web. When I am calling /main.jspx it redirect to the login.jsp. But when I am trying to log-in some error appeared
public class AccessFilter implements Filter {
private FilterConfig filterConfig;
#Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpSession session = ((HttpServletRequest) request).getSession();
HttpServletResponse res = (HttpServletResponse) response;
Client client = (Client) session.getAttribute("client");
if (client != null) {
chain.doFilter(request, response);
} else {
RequestDispatcher dispatcher = request.getRequestDispatcher(
ConfigurationManager.getInstance().getProperty(ConfigurationManager.LOGIN_PAGE_PATH));
dispatcher.forward(request, response);
}
}
#Override
public void destroy() {
this.filterConfig = null;
}
}
web.xml:
<filter>
<filter-name>AccessFilter</filter-name>
<filter-class>ua.kpi.shop.filter.AccessFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AccessFilter</filter-name>
<url-pattern>/jsp/main.jspx</url-pattern>
<url-pattern>/jsp/pokemons.jspx</url-pattern>
</filter-mapping>
Error:
HTTP Status 404 - /PokemonsShop/login.jspx
type Status report
message /PokemonsShop/login.jspx
description The requested resource is not available.
filterConfig.getServletContext().getRequestDispatcher takes the absolute path as opposed to request-getRequestDispatcher. Though whether that is the solution I cannot say.
Two things came into my head when seeing your message:
1) Did you check whether the client object is null or not ? May be when executing the login action (method) you are not setting correctly the client into session ?
2) In the server error, it says "not found /PokemonsShop/login.jspx" but in your filter mapping you are mentioning /jsp/xxx. Would it be because your login page is under the folder jsp and you are redirecting (in the filter) to /PokemonsShop/login.jspx, which should be under webapp root folder to be accessible.
Hope one of them be of help
I creating a web application using JSF,Hibernate,Spring. I have added a filter for checking session. My Filter code is :
public class AdminFilter implements Filter{
private ArrayList<String> urlList;
#Override
public void init(FilterConfig filterConfig) throws ServletException {
String urls = filterConfig.getInitParameter("avoid-urls");
StringTokenizer token = new StringTokenizer(urls, ",");
urlList = new ArrayList<String>();
while (token.hasMoreTokens()) {
urlList.add(token.nextToken());
}
}
// Checking if user is logged in
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req= (HttpServletRequest) request;
HttpServletResponse resp= (HttpServletResponse) response;
String url = req.getServletPath();
HttpSession session = req.getSession();
if(!urlList.contains(url) && session.getAttribute("user")==null)
{
resp.sendRedirect(req.getContextPath() + "/backend/login/index.xhtml");
}
chain.doFilter(req, resp);
}
#Override
public void destroy() {
// throw new UnsupportedOperationException("Not supported yet.");
}
}
In the init method of filter i have some avoid URL for which session checking should be skipped, like for login page itself. This is working correct but this filter is restricting my CSS,images and JS to load on the login page.
Suggest me what is the problem in my filter ?
Your login page needs some resources (CSS, JS, Images) which are requested from browser in separate request which will be intercepted by Filter and since you don't have any parameters that skips such requests for resources (being used on login page) it will block this request
Suggestion:
You could use Spring-Security, rather than investing time in writing yours, it has got lots of flexibility by configuration
Based on your current config, Currently your filter is ignoring if the URL is for fetching css, images or any other resource.
boolean staticResources = (url.contains("css") || url.contains("images"));
if(!urlList.contains(url) && session.getAttribute("user")==null && !staticResources) {
resp.sendRedirect(req.getContextPath() + "/backend/login/index.xhtml");
}
This will avoid session checking for static contents.
Better way of doing this will be using the declarative security as part of Java EE Web Security using realm.
I'm running a web application in JBoss AS 5. I also have a servlet filter which intercepts all the requests to the server. Now, I want to redirect the users to the login page, if the session has expired. I need to do this 'isSessionExpired()' check in the filter and need to redirect the user accordingly. How do I do it? I'm setting my session time limit in web.xml, as below:
<session-config>
<session-timeout>15</session-timeout>
</session-config>
You could use a Filter and do the following test:
HttpSession session = request.getSession(false);// don't create if it doesn't exist
if(session != null && !session.isNew()) {
chain.doFilter(request, response);
} else {
response.sendRedirect("/login.jsp");
}
The above code is untested.
This isn't the most extensive solution however. You should also test that some domain-specific object or flag is available in the session before assuming that because a session isn't new the user must've logged in. Be paranoid!
How to redirect to Login page when Session is expired in Java web application?
This is a wrong question. You should differentiate between the cases "User is not logged in" and "Session is expired". You basically want to redirect to login page when user is not logged in. Not when session is expired. The currently accepted answer only checks HttpSession#isNew(). But this obviously fails when the user has sent more than one request in the same session when the session is implicitly created by the JSP or what not. E.g. when just pressing F5 on the login page.
As said, you should instead be checking if the user is logged in or not. Given the fact that you're asking this kind of question while standard authentication frameworks like j_security_check, Shiro, Spring Security, etc already transparently manage this (and thus there would be no need to ask this kind of question on them), that can only mean that you're using a homegrown authentication approach.
Assuming that you're storing the logged-in user in the session in some login servlet like below:
#WebServlet("/login")
public class LoginServlet extends HttpServlet {
#EJB
private UserService userService;
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response);
}
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = userService.find(username, password);
if (user != null) {
request.getSession().setAttribute("user", user);
response.sendRedirect(request.getContextPath() + "/home");
} else {
request.setAttribute("error", "Unknown login, try again");
doGet(request, response);
}
}
}
Then you can check for that in a login filter like below:
#WebFilter("/*")
public class LoginFilter implements Filter {
#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 loginURI = request.getContextPath() + "/login";
boolean loggedIn = session != null && session.getAttribute("user") != null;
boolean loginRequest = request.getRequestURI().equals(loginURI);
if (loggedIn || loginRequest) {
chain.doFilter(request, response);
} else {
response.sendRedirect(loginURI);
}
}
// ...
}
No need to fiddle around with brittle HttpSession#isNew() checks.
you can also do it with a filter like this:
public class RedirectFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req=(HttpServletRequest)request;
//check if "role" attribute is null
if(req.getSession().getAttribute("role")==null) {
//forward request to login.jsp
req.getRequestDispatcher("/login.jsp").forward(request, response);
} else {
chain.doFilter(request, response);
}
}
}
Check for session is new.
HttpSession session = request.getSession(false);
if (!session.isNew()) {
// Session is valid
}
else {
//Session has expired - redirect to login.jsp
}
Inside the filter inject this JavaScript which will bring the login page like this.
If you don't do this then in your AJAX call you will get login page and the contents of login page will be appended.
Inside your filter or redirect insert this script in response:
String scr = "<script>window.location=\""+request.getContextPath()+"/login.do\"</script>";
response.getWriter().write(scr);
You need to implement the HttpSessionListener interface, server will notify session time outs.
like this;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class ApplicationSessionListener implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent event) {
System.out.println("Session Created");
}
public void sessionDestroyed(HttpSessionEvent event) {
//write your logic
System.out.println("Session Destroyed");
}
}
Check this example for better understanding
http://www.myjavarecipes.com/how-to-catch-session-timeouts/
Until the session timeout we get a normal request, after which we get an Ajax request. We can identify it the following way:
String ajaxRequestHeader = request.getHeader("X-Requested-With");
if ("XMLHttpRequest".equals(ajaxRequestHeader)) {
response.sendRedirect("/login.jsp");
}
i found this posible solution:
public void logout() {
ExternalContext ctx = FacesContext.getCurrentInstance().getExternalContext();
String ctxPath = ((ServletContext) ctx.getContext()).getContextPath();
try {
//Use the context of JSF for invalidate the session,
//without servlet
((HttpSession) ctx.getSession(false)).invalidate();
//redirect with JSF context.
ctx.redirect(ctxPath + "absolute/path/index.jsp");
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
When the use logs in, put its username in the session:
`session.setAttribute("USER", username);`
At the beginning of each page you can do this:
<%
String username = (String)session.getAttribute("USER");
if(username==null)
// if session is expired, forward it to login page
%>
<jsp:forward page="Login.jsp" />
<% { } %>