I'm trying to write a filter, which checks if user is logged in, and in case is not redirect him to login page. previously I had filter which actually did nothing -_- here it is, and with this filter everythig works ok, and session invalidates:
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpSession session = request.getSession();
if (session == null || session.getAttribute("UserName") == null) {
String command = request.getParameter("command");
request.setAttribute("command", "login");
// String page = ConfigurationManager.getInstance().getProperty(
// ConfigurationManager.LOGIN_PAGE_PATH);
} else {
String username = (String) session.getAttribute("UserName");
UserRole role;
try {
role = UserDAOImpl.getUserRole(username);
session.setAttribute("role", role);
} catch (DAOTechnicException e) {
logger.error(e);
} catch (DAOLogicException e) {
logger.error(e);
}
}
chain.doFilter(req, res);
}
and when I invalidate session then it goes to (if session == null) block, and everything is ok.
but now I have another filter, here it is :
public class UserCheckFilter implements Filter {
static class FilteredRequest extends HttpServletRequestWrapper {
public FilteredRequest(ServletRequest request) {
super((HttpServletRequest) request);
}
public String getParameter(String paramName) {
String value = super.getParameter(paramName);
if(value!=null){
if (value.equals("login")) {
return value;
}
HttpSession session = super.getSession();
if (session == null || session.getAttribute("UserName") == null) {
value = "login";
}
}
return value;
}
}
/**
* Checks if user logged in and if not redirects to login page
*/
#Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpSession session = request.getSession(false);
if (session == null || session.getAttribute("UserName") == null) {
if(request.getParameter("command")!=null){
String command = request.getParameter("command");
if(!command.equals("login")){
FilteredRequest filtrequest = new FilteredRequest(request);
String filteredvalue = filtrequest.getParameter("command");
chain.doFilter(filtrequest, res);
}else{
chain.doFilter(req, res);
}
}else{
chain.doFilter(req, res);
}
} else {
String username = (String) session.getAttribute("UserName");
UserRole role;
chain.doFilter(req, res);
try {
role = UserDAOImpl.getUserRole(username);
session.setAttribute("role", role);
} catch (DAOTechnicException e) {
logger.error(e);
} catch (DAOLogicException e) {
logger.error(e);
}
}
}
in which I wrap getParameter method and check if not logged in user is trying to go to user or admin pages. But when I invalidate session, it does not invalidates, i.e. all parameters are staying the same, and then in the filter where it checks if session != null, it's not null, and in line session.setAttribute("role", role); I get exception "session is already invalidated"
here's the method where i invalidate session :
if(request.getSession(false)!=null){
request.getSession().invalidate();
}
String page = ConfigurationManager.getInstance().getProperty(
ConfigurationManager.LOGIN_PAGE_PATH);
return page;
and in servlet U use
RequestDispatcher dispatcher = getServletContext()
.getRequestDispatcher(page);
dispatcher.forward(request, response);
and btw such things with invalidating session occurs only with second filter
p.s. sorry for probably stupid question, but I really don't know what's wrong,
so any suggestions would be appreciated.
I think this is because you're always calling chain.doFilter().
Per Oracle's docs...
A typical implementation of this method would follow the following
pattern:-
Examine the request
Optionally wrap the request object with a custom implementation to filter content or headers for input filtering
Optionally wrap the response object with a custom implementation to filter content or headers for output filtering
a) Either invoke the next entity in the chain using the FilterChain object (chain.doFilter()),
b) or not pass on the request/response pair to the next entity in the filter chain to block the request processing
Directly set headers on the response after invocation of the next entity in the filter chain.
In step 4, you probably want to do (b) - that is, instead of passing the request to the next filter in the chain, return the result to the user. I mean, it's an invalid session, so why bother trying to perform additional processing?
Related
How can I override the existing Spring Security authentication by invoking a Web Service and when it's failed, need to redirect some third party login page.
For calling this authentication web service, I need to get some ServletRequest parameter and for redirection, I need to access the ServletResponse.
Therefore I need to find out some Authentication method with ServletRequest and ServletResponse parameters.
But still, I failed to find out such a ProcessingFilter or AuthenticationProvider.
According to Spring Security basic it seems I have to override the AuthenticationProvider related authenticate method.
According to use case, I have to implement the Spring Security Pre-authentication,
but the issue is PreAuthenticatedAuthenticationProvider related 'authenticate' method only having the Authentication parameter.
PreAuthenticatedAuthenticationProvider
public class PreAuthenticatedAuthenticationProvider implements
AuthenticationProvider, InitializingBean, Ordered {
public Authentication authenticate(Authentication authentication) {}
}
As solution, is there any possibility to use custom implementation of AuthenticationFailureHandler ?
Thanks.
I have got resolved the issue as following manner,
Implementing a custom AbstractPreAuthenticatedProcessingFilter
Override the doFilter method
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
try {
// Get current Authentication object from SecurityContext
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
// Call for third party WS when the Authenticator object is null
if (auth == null) {
logger.debug("doFilter : Proceed the authentication");
String appId = "My_APP_ID";
String redirectURL = request.getRequestURL().toString();
// Call for third party WS for get authenticate
if (WS_Authenticator.isAuthenticated(appId, redirectURL)) {
// Successfully authenticated
logger.debug("doFilter : WS authentication success");
// Get authenticated username
String userName = WS_Authenticator.getUserName();
// Put that username to request
request.setAttribute("userName", userName);
} else {
String redirectURL = WS_Authenticator.getAuthorizedURL();
logger.debug("doFilter : WS authentication failed");
logger.debug("doFilter : WS redirect URL : " + redirectURL);
((HttpServletResponse) response).setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
((HttpServletResponse) response).sendRedirect(redirectURL);
// Return for bypass the filter chain
return;
}
} else {
logger.debug("doFilter : Already authenticated");
}
} catch (Exception e) {
logger.error("doFilter: " + e.getMessage());
}
super.doFilter(request, response, chain);
return;
}
Override the getPreAuthenticatedCredentials method
#Override
protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
// Get authenticated username
String[] credentials = new String[1];
credentials[0] = (String) request.getAttribute("userName");
return credentials;
}
Implementing a CustomAuthenticationUserDetailsServiceImpl
Override the loadUserDetails method
public class CustomAuthenticationUserDetailsServiceImpl implements AuthenticationUserDetailsService<Authentication> {
protected static final Logger logger = Logger.getLogger(CustomAuthenticationUserDetailsServiceImpl.class);
#Autowired
private UserDataService userDataService;
public UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException {
// Get authenticated username
String[] credentials = (String[]) token.getCredentials();
String userName = credentials[0];
try {
// Get user by username
User user = userDataService.getDetailsByUserName(userName);
// Get authorities username
List<String> roles = userDataService.getRolesByUserName(userName);
user.setCustomerAuthorities(roles);
return user;
} catch (Exception e) {
logger.debug("loadUserDetails: User not found! " + e.getMessage());
return null;
}
}
}
I am trying to auto login user using my SSO system.
So, when user validated, Filter is still redirecting to itself again and again.
This is my Filter code:
#Override
public void doFilter(ServletRequest sr, ServletResponse sr1, FilterChain fc) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) sr;
HttpSession session = ((HttpServletRequest) sr).getSession(false);
if (session != null && session.getAttribute("accountName") != null) {
fc.doFilter(sr, sr1);
return;
}
try {
TicketInfo ticketInfo = sso.getTicketInfo(request);
if (ticketInfo != null && (ticketInfo.getResult().equals(Result.SUCCESS)) && ticketInfo.getUserName() != null) {
if (ticketInfo.getExpireDate().compareTo(new Date()) >= 1) {
String accountName = ticketInfo.getUserName();
if(session!=null){
session.setAttribute("accountName", accountName);
}
fc.doFilter(sr, sr1);
}
}
} catch (Exception e) {
e.printStackTrace();
}
HttpServletResponse response = (HttpServletResponse) sr1;
response.sendRedirect("http://sso-login.test");
}
What am I doing wrong? I thought that in this part of code
if (session != null && session.getAttribute("accountName") != null) {
fc.doFilter(sr, sr1);
return;
}
Filter must stop redirecting and chain my request, but it looks like it still redirecting to sso-login.
Many thanks for attention.
PS I checked, session attribute account name is not null.
It looks you didn't call fc.doFilter(sr, sr1) at the end. response.sendRedirect has no meaning without using doFilter after it.
I've a filter used for the login. It performs a textual checking, on fields "Username" and "Password". If and only if the textual checking is correctly done the request goes to the Servlet. This latter performs the control that has to interact with the Database. Is this chain correct?
Preface: I gather you're using homegrown login instead of container managed login. For all ways, see How to handle authentication/authorization with users in a database?
The filter (the interceptor) shouldn't check the validity of the username/password combo. That's the responsibility of the servlet (the controller).
The filter should merely check if the user is logged-in or not (usually by just checking the presence of a session attribute) and then continue the request or block it by redirecting back to the login page.
#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);
}
}
// ...
}
The servlet should collect the submitted data, find the associated User in database and if found then store it as a session attribute and then redirect to the home page, else redisplay the form with validation errors.
#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");
Map<String, String> messages = new HashMap<String, String>();
if (username == null || username.isEmpty()) {
messages.put("username", "Please enter username");
}
if (password == null || password.isEmpty()) {
messages.put("password", "Please enter password");
}
if (messages.isEmpty()) {
User user = userService.find(username, password);
if (user != null) {
request.getSession().setAttribute("user", user);
response.sendRedirect(request.getContextPath() + "/home");
return;
} else {
messages.put("login", "Unknown login, please try again");
}
}
request.setAttribute("messages", messages);
request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response);
}
}
See also:
Our servlet-filters wiki page
Our servlets wiki page
I am trying to get my first servlets to work. I have found some similar problems and solutions to them, but it´s not excatly what I would like to do.
This is my login servlet:
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String username=request.getParameter("username");
String password=request.getParameter("password");
if(LoginValidator.validate(username, password)){
HttpSession session = request.getSession();
session.setAttribute("user", username);
session.setMaxInactiveInterval(30*60);
Cookie sessionCookie = new Cookie("sessionKuki", username);
sessionCookie.setMaxAge(30*60);
response.addCookie(sessionCookie);
RequestDispatcher rd=request.getRequestDispatcher("paste.jsp"); //INSTEAD of paste.jsp I would like to get session attribute called uri I set in filter. BUT I when I try to use get attribute, Eclipse says there is no attribute called URI.
rd.forward(request,response);
}
else{
out.print("Sorry username or password error");
RequestDispatcher rd=request.getRequestDispatcher("login.html");
rd.include(request,response);
}
out.close();
}
}
And there is filter that I use to redirect to login page, when user is not signed in:
public class SessionFilter implements Filter{
// private ServletContext context;
public void init(FilterConfig filterConfig) throws ServletException {
//this.context = filterConfig.getServletContext();
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
String uri = req.getRequestURI(); //THERE IS uri of the site from where the user gets redirected to login page
HttpSession session = req.getSession(false);
session.setAttribute("uri", uri); // HERE I TRY to set uri to session attribute. My intention is to use that uri in my login servlet
if(uri.endsWith(".css")) {
chain.doFilter(request, response);
return;
}
if(uri.endsWith(".js")) {
chain.doFilter(request, response);
return;
}
if(session == null && !(uri.endsWith("login.html") || uri.endsWith("login") || uri.endsWith("forgot.jsp") || uri.endsWith("signup.jsp"))){
res.sendRedirect("login.html");
System.out.print("redirecting to login");
}else{
chain.doFilter(request, response);
}
}
public void destroy() {
}
}
Is it even possible, what I am trying to do? How to do it? Is there a better way to do it? I dont want to mix html and script. My intention is that, when user comes to a pages, and trys to get access to somewhere, he is redirected to login page. And after he logs in, he should be redirected to the page he wanted to go at the beginning.
Not sure if this would work but please try doing your filter like this:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
String uri = req.getRequestURI();
HttpSession currentSession = req.getSession(false);
if(uri.endsWith(".css")) {
chain.doFilter(request, response);
return;
}
if(uri.endsWith(".js")) {
chain.doFilter(request, response);
return;
}
if(currentSession == null && !(uri.endsWith("login.html") || uri.endsWith("login") || uri.endsWith("forgot.jsp") || uri.endsWith("signup.jsp"))){
HttpSession newSession = req.getSession();
newSession.setAttribute("uri", uri);
res.sendRedirect("login.html");
System.out.print("redirecting to login");
}else{
chain.doFilter(request, response);
}
}
What i did was create a new session in the filter if the session is null.
I need to do some checks before every page is loaded to see if there's a need to redirect the user to another page (for security reasons).
When I was using JSF 2.0 I used a phase listener to do this job. Now that I'm using JSF 2.2 and all my beans are not JSF beans anymore, but CDI beans, I think I'm offered better choices to do this (or not?).
I've heard of the viewAction event, but I wouldn't like to be repeating metadata on every page (only if there's no other option).
So what's the best approach to implement this scenario in JSF 2.2 with CDI?
UPDATE (after #skuntsel suggestion)
This is the filter that I'm using for now. I would like to use it only after authentication to simplify its code. By the way, if you can see any mistake in it, I would appreciate if you told me.
#WebFilter("/*")
public class SolicitacoesFilter implements Filter
{
// I can't just use #Inject private User _user, because it needs to be initialized
// only when the user is authenticated. Otherwise an exception is thrown. If this
// filter was called only after the authentication I could use the mentioned code.
private User _user;
#Inject
private Instance<User> _userGetter;
#Override
public void init(FilterConfig filterConfig) throws ServletException
{
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
if (initializeUser(request))
{
if (_user.isProvisoryPassword())
{
// Redirect to another page...
return;
}
if (_user.getStatus() != Status.ACTIVE)
{
// Redirect to another page...
return;
}
}
chain.doFilter(request, response);
}
#Override
public void destroy()
{
}
private boolean initializeUser(ServletRequest request)
{
boolean userAuthenticated = ((HttpServletRequest) request).getUserPrincipal() != null;
if (userAuthenticated)
{
if (_user == null)
{
_user = _userGetter.get();
}
}
else
{
_user = null;
}
return _user != null;
}
}
Ok, what are the purposes of your redirection need ?
If it's about checking session User for authentification purposes, use filter:
Let's assume there is login form at : http://www.domain.com/login.jsf.
Once the user fires connect button, we want to redirect him to http://www.domain.com/member/welcome.jsf, and avoid other people not to access the member/welcome.jsf domain, I mean all the pages which are in http://www.domain.com/member/....
Here a simple design:
#WebFilter("/member/*")
public class SecurityCheck implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
#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();
if (session == null || session.getAttribute("User") == null) {
response.sendRedirect(request.getContextPath() + "/index.xhtml"); // 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() {
// Cleanup global variables if necessary.
}
Other case, use:
<h:link></h:link>,or <h:commandLink></h:commandLink> // Checking in the managed Beans method
You can also xml file, for redirection.