using servlet filter with session variable - session

I have created a Java web application using JSF 2.
When a user login to my application, I store his identifier in the session, so:
FacesContext context = FacesContext.getCurrentInstance();
context.getExternalContext().getSessionMap().put("userid", myBean.getUserId());
Then I created my filter:
public class PageFilter 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 {
HttpServletRequest httprequest =(HttpServletRequest) request;
HttpServletResponse httpresponse =(HttpServletResponse) response;
HttpSession session = ((HttpServletRequest) request).getSession();
String userid = (String) session.getAttribute("userid");
String pageRequested = httprequest.getRequestURI();
try {
if( userid != null && pageRequested.contains("index.xhtml") ) {
System.out.printf("User authenticated with " + httprequest.getRemoteUser() + " username conected.");
httprequest.getRequestDispatcher("/service/home.xhtml").forward(request, response);
} else {
chain.doFilter(request, response);
}
}catch(IOException | ServletException e){
//do something
}
}
#Override
public void destroy() {
System.out.print("Existing from loginFilter");
}
}
My scope is to manage the refresh button of the browser so if user is already logged then user is redirected to /service/home.xhtml. Also, the url in my web application is always:
localhost:8080/myapplication
So if user browses the site among all the pages, the url is always that (the action is hidden).
The problem is that if user clicks on the url in the browser, the request is for index.xhtml and my session is null (I cannot get user identifier by session.getAttribute("userid");).
Where is my fault?
The index.xhtml is defined as welcome-file-list in my web.xml:
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
Thanks.

Related

Disable jsession id from filter in spring

I have written a filter that extends AbstractAuthenticationProcessingFilter.
The following is the overridden method:
#Override
public Authentication attemptAuthentication(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse)
throws AuthenticationException, IOException, ServletException {
if (StringUtils.isNoneBlank(cookie)) {
return authenticationProvider.authenticate(token);
//Here I want to return jsession id and establish a session.
} else {
return handleInSomeOtherWay(httpServletRequest);
//Here I DONT want to return jsessionid
}
}
How can I achieve returning jsession id in one path and not in another path? I tried to set allowSessionCreation = false, but that did not help.

Session attributes not working in Spring #RestControllers

I have added location as a session attribute as given below
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
com.blife.werp.model.User userSession = userRepository.findByUsername(user.getUsername());
HttpSession session = request.getSession();
session.setAttribute("user", userSession);
session.setAttribute("username", user.getUsername());
session.setAttribute("location",userSession.getLocation());
try {
userService.isloggedIn(true, userSession,request);
} catch (Exception e) {
e.printStackTrace();
}
redirectStrategy.sendRedirect(request, response, "/dashboard");
}
but when I used it in Spring Rest service as given bellow gave me and exception
"org.hibernate.LazyInitializationException: could not initialize proxy - no Session"
#RequestMapping("/get_product_by_location")
public List<ProductStock> getProductByLocation(HttpServletRequest request, #RequestParam String code){
HttpSession session = request.getSession();
Location location = session != null ? (Location) session.getAttribute("location") : null;
System.out.println(code+" "+location);
List<ProductStock> products = productService.getProductByLocation(code,location);
System.out.println(products);
return products;
}
Can any one let me now the issue in my code example to cause this error, If the "location" attribute is already in the session why it gave me an Lazy Initialization I am not going fetch this via any Repositories.

Spring & Security: limit uploads to authenticated users

I'm facing a security problem regarding file uploads.
How do I limit file uploads to specific user roles?
I'm using #PreAuthorize("hasRole('USER')"), but it is uploading the file first and then checking the role. You can especially see this when file upload size is exceeded. User will get an upload size exceeded exception instead of redirecting to the login-form.
This is how my controller looks like:
#Controller
#PreAuthorize("hasRole('USER')")
#Secured("ROLE_USER") // added this just to see if it makes a difference, it doesn't
#RequestMapping(value = "/self/upload", produces = "application/json")
public class JsonUserSelfUpload {
...
#RequestMapping(value = "", method = RequestMethod.POST, consumes="multipart/form-data")
public ModelAndView fileUpload(
#RequestParam(value = "file", required = true) MultipartFile inputFile,
#RequestParam(value = "param1", defaultValue = "") String type,
HttpServletResponse response
) throws Exception {
...
}
}
Anyone know how to secure file uploads to specific roles?
Edit, to be more specific:
I want to reject uploads if user is not authenticated. By reject I mean, close connection before the upload actually finishes. Not sure if spring is capable in doing this or I'd need a filter to reject uploads (multipart).
Update:
Tried with a filter with no success either.
Seems like one has no way to close the connection.
This is what my filter looks like:
public class RestrictUploadFilter implements Filter{
#Override
public void init(FilterConfig arg0) throws ServletException {
}
#Override
public void destroy() {
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String contentType = request.getContentType();
if (HttpMethods.POST.equals(request.getMethod()) && contentType != null && contentType.toLowerCase().indexOf("multipart/form-data") > -1) {
UserSession session = SpringHelper.getUserSession();
if (session != null && session.getRoles().contains(UserRole.USER)) {
// user is allowed to upload
chain.doFilter(req, res);
} else {
// access denied
response.setStatus(HttpStatus.FORBIDDEN_403);
response.setHeader("Connection", "close");
response.flushBuffer();
}
} else {
chain.doFilter(req, res);
}
}
}

Make simple servlet filter work with #ControllerAdvice

I've a simple filter just to check if a request contains a special header with static key - no user auth - just to protect endpoints. The idea is to throw an AccessForbiddenException if the key does not match which then will be mapped to response with a class annotated with #ControllerAdvice. However I can't make it work. My #ExceptionHandler isn't called.
ClientKeyFilter
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Controller
import javax.servlet.*
import javax.servlet.http.HttpServletRequest
#Controller //I know that #Component might be here
public class ClientKeyFilter implements Filter {
#Value('${CLIENT_KEY}')
String clientKey
public void init(FilterConfig filterConfig) {}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
req = (HttpServletRequest) req
def reqClientKey = req.getHeader('Client-Key')
if (!clientKey.equals(reqClientKey)) {
throw new AccessForbiddenException('Invalid API key')
}
chain.doFilter(req, res)
}
public void destroy() {}
}
AccessForbiddenException
public class AccessForbiddenException extends RuntimeException {
AccessForbiddenException(String message) {
super(message)
}
}
ExceptionController
#ControllerAdvice
class ExceptionController {
static final Logger logger = LoggerFactory.getLogger(ExceptionController)
#ExceptionHandler(AccessForbiddenException)
public ResponseEntity handleException(HttpServletRequest request, AccessForbiddenException e) {
logger.error('Caught exception.', e)
return new ResponseEntity<>(e.getMessage(), I_AM_A_TEAPOT)
}
}
Where I'm wrong? Can simple servlet filter work with spring-boot's exception mapping?
As specified by the java servlet specification Filters execute always before a Servlet is invoked. Now a #ControllerAdvice is only useful for controller which are executed inside the DispatcherServlet. So using a Filter and expecting a #ControllerAdvice or in this case the #ExceptionHandler, to be invoked isn't going to happen.
You need to either put the same logic in the filter (for writing a JSON response) or instead of a filter use a HandlerInterceptor which does this check. The easiest way is to extend the HandlerInterceptorAdapter and just override and implement the preHandle method and put the logic from the filter into that method.
public class ClientKeyInterceptor extends HandlerInterceptorAdapter {
#Value('${CLIENT_KEY}')
String clientKey
#Override
public boolean preHandle(ServletRequest req, ServletResponse res, Object handler) {
String reqClientKey = req.getHeader('Client-Key')
if (!clientKey.equals(reqClientKey)) {
throw new AccessForbiddenException('Invalid API key')
}
return true;
}
}
You can't use #ControllerAdvice, because it gets called in case of an exception in some controller, but your ClientKeyFilter is not a #Controller.
You should replace the #Controller annotation with the #Component and just set response body and status like this:
#Component
public class ClientKeyFilter implements Filter {
#Value('${CLIENT_KEY}')
String clientKey
public void init(FilterConfig filterConfig) {
}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String reqClientKey = request.getHeader("Client-Key");
if (!clientKey.equals(reqClientKey)) {
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid API key");
return;
}
chain.doFilter(req, res);
}
public void destroy() {
}
}
Servlet Filters in Java classes are used for the following purposes:
To check requests from client before they access resources at backend.
To check responses from server before sent back to the client.
Exception throw from Filter may not be catch by #ControllerAdvice because in may not reach DispatcherServlet. I am handling in my project as below:
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
String token = null;
String bearerToken = request.getHeader("Authorization");
if (bearerToken != null && (bearerToken.contains("Bearer "))) {
if (bearerToken.startsWith("Bearer "))
token = bearerToken.substring(7, bearerToken.length());
try {
AuthenticationInfo authInfo = TokenHandler.validateToken(token);
logger.debug("Found id:{}", authInfo.getId());
authInfo.uri = request.getRequestURI();
AuthPersistenceBean persistentBean = new AuthPersistenceBean(authInfo);
SecurityContextHolder.getContext().setAuthentication(persistentBean);
logger.debug("Found id:'{}', added into SecurityContextHolder", authInfo.getId());
} catch (AuthenticationException authException) {
logger.error("User Unauthorized: Invalid token provided");
raiseException(request, response);
return;
} catch (Exception e) {
raiseException(request, response);
return;
}
// Wrapping the error response
private void raiseException(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
ApiError apiError = new ApiError(HttpStatus.UNAUTHORIZED);
apiError.setMessage("User Unauthorized: Invalid token provided");
apiError.setPath(request.getRequestURI());
byte[] body = new ObjectMapper().writeValueAsBytes(apiError);
response.getOutputStream().write(body);
}
// ApiError class
public class ApiError {
// 4xx and 5xx
private HttpStatus status;
// holds a user-friendly message about the error.
private String message;
// holds a system message describing the error in more detail.
private String debugMessage;
// returns the part of this request's URL
private String path;
public ApiError(HttpStatus status) {
this();
this.status = status;
}
//setter and getters

Why I can't read session attribute from portlet that is set in AutoLogin class

I try unsuccessful to access from my portlet the session attribute that I have set during the AutoLogin phase.
Setting attribute in AutoLogin class:
#Override
public String[] login(HttpServletRequest request, HttpServletResponse response) throws AutoLoginException {
request.getSession().setAttribute("My-Attribute-Key", "Hello World");
...
}
Access attribute from Portlet:
#Override
public void doView(RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException {
Object attribute = PortalUtil.getHttpServletRequest(renderRequest).getSession().getAttribute("My-Attribute-Key");
...
}
Take a look at Session Sharing on Liferay Wiki.

Resources