I am trying to implement simple log in functionality in a JSF application. Following this answer, I have implemented an AuthenticationFilter. I am trying to set an object in my managed bean as :
FacesContext facesContext = FacesContext.getCurrentInstance();
HttpSession session = (HttpSession) facesContext.getExternalContext().getSession(true);
session.setAttribute("user", user);
doFilter method of AuthenticationFilter looks like this:
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
if (((HttpServletRequest) req).getSession().getAttribute("user") == null){
((HttpServletResponse) resp).sendRedirect("../login.jsf");
} else {
chain.doFilter(req, resp);
}
}
I always get ((HttpServletRequest) req).getSession().getAttribute("user") == null (true). I have searched and applied many alternatives like (in my bean) :
facesContext.getExternalContext().getSessionMap().put("user", user);
request.getSession().setAttribute("user", user);
session.getServletContext().setAttribute("user", user); // DISASTER
I don't have a clue how to manage this thing. Seemingly duplicate question did'nt help either. What am I doing wrong? How can I make it work? Is there a good and clean way to do it using JSF capabilities?
I recommend you use a security library like the previous answer. There are too many ways to do this incorrectly...
But if you're dead set on doing it yourself, don't set this in the Session. Declare a ManagedBean and scope it as the session level. Have a property of the bean be the username.
Related
I am upgrading older Spring 2.5 code to Spring 3.0 (as a first step). During this I found the following problem:
The method getExtraInformation() from the type AuthenticationException is deprecated
The point is that this happens in a subclass of UsernamePasswordAuthenticationFilter:
#Override
protected void unsuccessfulAuthentication(final HttpServletRequest req, final HttpServletResponse res, final AuthenticationException authException) throws IOException, ServletException
{
req.setAttribute("exception", authException);
super.unsuccessfulAuthentication(req, res, authException);
if (authException instanceof CredentialsExpiredException)
{
final User user = ((UserDetailsImpl)authException.getExtraInformation()).getUser();
if (user.getCredentials().getUserCannotChange())
{
throw authException;
}
req.setAttribute("user", user);
req.setAttribute("msg", this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.credentialsExpiredPleaseChange"));
}
}
Until now I found no way to get the User in another way. So my question is how to get the user when it is no longer transported via the exceptions extra information?
The point is that the User is required here, because a decision has to be made if the exception is only rethrown or if a message should be presented to the user.
Btw. I have found no code that creates a CredentialsExpiredException with ExtraInformation, so I assume this will be done by the Spring/Spring Security Framework?
I think you have to step back and do this "extra information" check when Spring Security checks if there is CredentialsExpiredException. Assuming you are using the default settings , the CredentialsExpiredException is checked in the postAuthenticationChecks UserDetailsChecker in DaoAuthenticationProvider. The default implementation is DefaultPostAuthenticationChecks which you can override it with yours :
public class MyPostAuthenticationChecks extends DefaultPostAuthenticationChecks {
public void check(UserDetails user) {
UserDetailsImpl userImpl = (UserDetailsImpl)user;
if (user.getCredentials().getUserCannotChange()){
throw new CredentialsExpiredException("Some customized error message blalblbal");
}else{
super.check(user);
}
}
}
I've already read the another article about it but it doesn't help me to find a generic solution for the entire application.
I've kept a big legacy web application (Struts2, Spring Boot, and Tomcat embedded) and I'm facing these following error.
2018-08-14 11:01:11.872 [http-nio-10010-exec-114] ERROR o.a.c.c.C.[.[localhost].[/].[jsp] - Servlet.service() for servlet jsp threw exception java.lang.IllegalStateException: Cannot create a session after the response has been committed
at org.apache.catalina.connector.Request.doGetSession(Request.java:2953)
at org.apache.catalina.connector.Request.getSession(Request.java:2367)
at org.apache.catalina.connector.RequestFacade.getSession(RequestFacade.java:896)
at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:231)
at org.apache.catalina.core.ApplicationHttpRequest.getSession(ApplicationHttpRequest.java:592)
at org.apache.catalina.core.ApplicationHttpRequest.getSession(ApplicationHttpRequest.java:537)
at org.apache.jasper.runtime.PageContextImpl.initialize(PageContextImpl.java:137)
at org.apache.jasper.runtime.JspFactoryImpl.internalGetPageContext(JspFactoryImpl.java:109)
at org.apache.jasper.runtime.JspFactoryImpl.getPageContext(JspFactoryImpl.java:60)
at org.apache.jsp.jsp.errorPage_jsp._jspService(errorPage_jsp.java:127)
Other example:
2018-08-14 11:01:11.870 [http-nio-10010-exec-114] ERROR o.a.c.c.C.[.[.[.[.q.q.c.RedirectResourceServlet] - Servlet.service() for servlet [com.mydomain.myapplication.control.RedirectResourceServlet] in context with path [] threw exceptionjava.lang.IllegalStateException: Cannot create a session after the response has been committed
at org.apache.catalina.connector.Request.doGetSession(Request.java:2953)
at org.apache.catalina.connector.Request.getSession(Request.java:2367)
at org.apache.catalina.connector.RequestFacade.getSession(RequestFacade.java:896)
at org.apache.catalina.connector.RequestFacade.getSession(RequestFacade.java:908)
at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:240)
at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:240)
It occurs in different places like *Actions.java and JSP files.
Does someone know how and which is the best approach to intercept all request.getSession() to check if it was already committed? And how could I in a Struts 2 context create a new session? The request.getSession(true) doesn't work when the response.isCommitted() is true.
I've already tried to create a #WebFilter where I check and try to create a new session, but it doesn't work as expected. I also believe it is not the best approach.
#WebFilter(urlPatterns = "/*")
public class SessionValidatorFilter implements Filter {
private Logger logger = LoggerFactory.getLogger(getClass().getName());
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
if (servletResponse.isCommitted() && servletRequest instanceof HttpServletRequest && servletResponse instanceof HttpServletResponse) {
logger.debug("Response was already committed. Trying to create a new session.");
try {
HttpSession session = ((HttpServletRequest) servletRequest).getSession(true);
if (session != null)
logger.debug("Session created.");
filterChain.doFilter(servletRequest, servletResponse);
} catch (Exception e) {
logger.debug("Error trying to create new Session.");
}
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
}
}
I have a few controllers that use the #RequestHeader annotation to get the logged in user. I cannot seem to find the correct way to alter the header before the method is called.
I already tried to wrap the request and using an interceptor (in the prehandle method, if I'm not mistaken) and pass along the request,but it seems like the headers are not being queried. An exception is thrown by the servlet dispatcher that the username is missing in the header.
Therefore I'm wondering whether someone knows how and when spring handles this annotation, so I can write the proper interceptor.
Don't have the code at hand, but if needed, I will post fragments later on. But the question is simple: how to inject a param into the request header when #RequestHeader is used on a controller method?
Kind regards,
Tom
First edit:
#Sotirios
I tried using the Filter, which works. But this is less convenient for me than the handlerinterceptor. Since I only need the filter for debugging. So again the better question: why isn't this not working with an interceptor?
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
final HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletRequestWrapper wrapper = new HttpServletRequestWrapper(httpRequest) {
#Override
public Enumeration getHeaders(String name) {
Enumeration headers = super.getHeaders(name);
if( isUseFilter() && Constants.REMOTE_USER.equalsIgnoreCase(name) ){
String user = super.getHeader(name);
headers = enumeration(asList(isEmpty(user)? getDebuggingUserId() :user));
}
return headers;
}
};
chain.doFilter(wrapper, response);
}
Is there a way to access the URL resolved from a Spring MVC controller - e.g.
#RequestMapping("/{language}/news/{articleId}")
public String newsPage(...) {
}
Resolves to:
/en/news/63421
I'd like to store this with the session so I can keep a track of last place visited. The motivation here is if the page is secured the login filter will come into play and we have used
SavedRequestAwareAuthenticationSuccessHandler
to route users back to the page they were trying to access.
However if they are viewing unsecured pages and choose to log in using a form that drops down from the top of the screen (the page's menu bar) the 'last page' seems to be the login form so the success handler drops them back to the root context.
I'd like to intercept controller calls and store a single URL with the session, override SavedRequestAwareAuthenticationSuccessHandler to allow us to modify the RequestCache and then let Spring redirect on login success.
Ideally we'd like a generic way to do this across all controllers but not sure if there is a filter we can use to pick this up - filtering requests gets all sorts of noise like css, js, images and html fragment pages so we're hoping someone knows a way to do this just with the controllers themselves.
There are two questions:
1) obtain the url in a controller method
#RequestMapping("/{language}/news/{articleId}")
public String newsPage(..., HttpServletRequest request) {
String uri = request.getRequestUri();
...
}
If you need this very often then you can implement a HandlerMethodArgumentResolver. *See this answer https://stackoverflow.com/a/8769670/280244 for an example (it implements a HandlerMethodArgumentResolver for the current user, but you can easyly adapt it for urls)
2.) store the url for each request in the session
You can implement a Servlet Filter or Spring HandlerInterceptor, both get a HttpServletRequest (In a Servlet Filter you need to cast the ServletRequest to an HttpServletRequest first.
Then you can obtain the url and the Session httpServletRequest.getSession() and then store the url in the session.
public class MyFilter implements Filter {
#Override
public void init(final FilterConfig filterConfig) throws ServletException {
//do nothing
}
#Override
public void doFilter(ServletRequest requ, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
if (requ instanceof HttpServletRequest) {
HttpServletRequest httpServletRequest = (HttpServletRequest) requ;
httpServletRequest.getSession().setAttribute(
"myFilter.LAST_URL",
httpServletRequest .getRequestURI());
}
chain.doFilter(request, response);
}
#Override
public void destroy() {
}
}
To get the URL path you can use the HttpServletRequest - so for example you have:
www.mysite.com/en/news/63421
req.getPathInfo() = /en/news/63421
Storing it in the session though could cause problems if someone is to use your site with multiple tabs open.
I am using spring security 3 and would like to display the time when user logged in to current session.
Does Spring security provide any such token?
Thanks,
- Akshay
The most reliable option would be customizing your Spring Security filter chain to save a timestamp in the user's session when a successful login occurs. Then you would access it in the same way you access any session attribute.
According to the documentation, you can add your own filters to the Spring Security filter chain.
You could add a filter after UsernamePasswordAuthenticationFilter, if you are using http/form-login, or after BasicAuthenticationFilter, in case of http/http-basic, so we guarantee that the session is already created.
To cover both, you can add a filter after the last one, and add the information to the session.
Declare your filter-bean:
<bean id="myFilter" class="com.MyFilter"/>
Add it to the chain, right after BasicAuthenticationFilter:
<http>
<custom-filter ref="myFilter" after="BASIC_AUTH_FILTER"/>
...
Your doFilter method should look like:
private static final String LOGGED_TIME_KEY = "LOGGED_TIME";
#Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.isAuthenticated()) {
HttpSession session = request.getSession(false);
if (session != null && session.getAttribute(LOGGED_TIME_KEY) == null) {
session.setAttribute(LOGGED_TIME_KEY, new Date());
}
}
chain.doFilter(req, res);
}
Keep in mind that you can use other hooks. You can add it even to your AuthenticationProvider.
EDIT:
There is a easier way to do that, if you are using form-login.
You can use a custom AuthenticationSuccessHandler. To define it, update your form-login tag, adding the attribute authentication-success-handler-ref.