How can jsessionID be suppressed on OC4J? - session

I'm deploying a JSF (myfaces, restfaces, and richfaces) app to OC4J. I don't want the jsessionid to appear in the status bar or the URL address. I have managed to suppress it in almost all cases. The one case that I still have problems with is when the site is first visited with a "clean" browser (with no cache, history, etc.). In this case, jsessionid appears on every link until any link is clicked on, then it disappears, and will not come back (even in subsequent sessions) until the browser's cache is cleared again.
It seems others have run into this problem, but I didn't find any resolutions or work arounds:
Java Servlet - how to remove
jsessionid from embedded URLs
Thread: How to hide JSESSIONID in
first-page Url?

The following code in a servlet filter has worked for us. The idea is override any URL-rewriting logic by employing a custom response wrapper.
public void doFilter(
ServletRequest req,
ServletResponse resp,
FilterChain filterChain )
throws IOException, ServletException
{
if ( req instanceof HttpServletRequest &&
resp instanceof HttpServletResponse )
{
doFilter(
(HttpServletRequest) req,
(HttpServletResponse) resp,
filterChain );
}
else
{
filterChain.doFilter( req, resp );
}
}
private void doFilter(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain )
throws IOException, ServletException
{
RequestHandler requestHandler = getRequestHandler( request );
HttpServletResponse wrappedResponse = getWrappedResponse( response );
filterChain.doFilter( request, wrappedResponse );
}
private HttpServletResponse getWrappedResponse(
HttpServletResponse response )
{
return
new HttpServletResponseWrapper( response )
{
public String encodeRedirectUrl( String url ) { return url; }
public String encodeRedirectURL( String url ) { return url; }
public String encodeUrl( String url ) { return url; }
public String encodeURL( String url ) { return url; }
};
}

Related

Content of HTTP request body changes after return from FilterChain

I have a filter that logs the request body twice. First I print the request body from the request object and then pass the request and response object to the FilterChain. Then in the finally{} I print again the content of the body in the request object. But the content is not anymore the same. Actually the content at Step-1 is empty and at Step-2 looks better. What does happens?
public class RequestAndResponseLoggingFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (isAsyncDispatch(request)) {
filterChain.doFilter(request, response);
} else {
doFilterWrapped(wrapRequest(request), wrapResponse(response), filterChain);
}
}
protected void doFilterWrapped(ContentCachingRequestWrapper request, ContentCachingResponseWrapper response, FilterChain filterChain) throws IOException, ServletException {
try {
// Step-1: Print the request body (at request time)
String requestBody = extractRequestBody(request);
log.info("Request Body: " + requestBody);
// Pass the request and response object to FilterChain
filterChain.doFilter(request, response);
}
finally {
// Step-2: Print again the request body (at response time). Do not get the same output as in Step-1.
String requestBody = extractRequestBody(request);
log.info("Request Body: " + requestBody);
}
}
private static String extractRequestBody(ContentCachingRequestWrapper request) {
byte[] content = request.getContentAsByteArray();
if (content.length > 0) {
return new String(content, request.getContentType());
}
return "";
}
}
I know there could be another Filter or Interceptor that can change it but I don't have a such one. At least not written from me. What is mechanism that changes the request body in the request object during the request processing time? I am using Spring Boot with Spring MVC. My filter extends OncePerRequestFilter from springframework.

Spring - Redirect to a link upon successfully logging in, after a failed Ajax request

I have a website that requires some HTML to be rendered inside an element asynchronously upon an user action. If the user's session expires things get tricky, but it can be solved by creating a custom AuthenticationEntryPoint class like this SO question and this SO question suggest.
My problem comes once the user logs back in because the user gets redirected to the last URL that was requested, which happens to be the Ajax request, therefore my user gets redirected to a fragment of an HTML, instead of the last page it browsed.
I was able to solve this by removing a session attribute on the custom AuthenticationEntryPoint:
if (ajaxOrAsync) {
request.getSession().removeAttribute("SPRING_SECURITY_SAVED_REQUEST");
}
Here comes my question's problem.
While the previous code solves my issue, it has the side effect of redirecting the user to the home page instead of the last page it browsed (as there is no saved request). It wouldn't be much of a problem, but it makes the website inconsistent because if the last request was an asynchronous request, it gets redirected home but if it was a normal request it gets redirected to the last page browsed. =(
I managed to code this to handle that scenario:
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.PortResolver;
import org.springframework.security.web.PortResolverImpl;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.savedrequest.DefaultSavedRequest;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
import static org.apache.commons.lang.StringUtils.isBlank;
public class CustomAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {
... // Some not so relevant code
#Override
public void commence(final HttpServletRequest request,
final HttpServletResponse response,
final AuthenticationException authException) throws IOException, ServletException {
... // some code to determine if the request is an ajax request or an async one
if (ajaxOrAsync) {
useRefererAsSavedRequest(request);
response.sendError(SC_UNAUTHORIZED);
} else {
super.commence(request, response, authException);
}
}
private void useRefererAsSavedRequest(final HttpServletRequest request) {
request.getSession().removeAttribute(SAVED_REQUEST_SESSION_ATTRIBUTE);
final URL refererUrl = getRefererUrl(request);
if (refererUrl != null) {
final HttpServletRequestWrapper newRequest = new CustomHttpServletRequest(request, refererUrl);
final PortResolver portResolver = new PortResolverImpl();
final DefaultSavedRequest newSpringSecuritySavedRequest = new DefaultSavedRequest(newRequest, portResolver);
request.getSession().setAttribute(SAVED_REQUEST_SESSION_ATTRIBUTE, newSpringSecuritySavedRequest);
}
}
private URL getRefererUrl(final HttpServletRequest request) {
final String referer = request.getHeader("referer");
if (isBlank(referer)) {
return null;
}
try {
return new URL(referer);
} catch (final MalformedURLException exception) {
return null;
}
}
private class CustomHttpServletRequest extends HttpServletRequestWrapper {
private URL url;
public CustomHttpServletRequest(final HttpServletRequest request, final URL url) {
super(request);
this.url = url;
}
#Override
public String getRequestURI() {
return url.getPath();
}
#Override
public StringBuffer getRequestURL() {
return new StringBuffer(url.toString());
}
#Override
public String getServletPath() {
return url.getPath();
}
}
}
The previous code solves my issue, but it is a very hacky approach to solve my redirection problem (I cloned and overwrote the original request... +shudders+).
So my question is, Is there any other way to rewrite the link that Spring uses to redirect the user after a successful login (given the conditions I'm working with)?
I've looked at Spring's AuthenticationSuccessHandler, but I haven't found a way of communicating the referer url to it in case of a failed Ajax request.
I've found an acceptable solution to my problem thanks to an idea that came up when reading the docs and later on browsing this other SO answer. In short, I would have to create my own custom ExceptionTranslationFilter, and override the sendStartAuthentication to not to save the request cache.
If one takes a look at the ExceptionTranslationFilter code, it looks this (for Finchley SR1):
protected void sendStartAuthentication(HttpServletRequest request,
HttpServletResponse response, FilterChain chain,
AuthenticationException reason) throws ServletException, IOException {
SecurityContextHolder.getContext().setAuthentication(null);
requestCache.saveRequest(request, response); // <--- Look at me
logger.debug("Calling Authentication entry point.");
authenticationEntryPoint.commence(request, response, reason);
}
So, to not save data from Ajax requests I should implement an CustomExceptionTranslationFilter that acts like this:
#Override
protected void sendStartAuthentication(final HttpServletRequest request,
final HttpServletResponse response,
final FilterChain chain,
final AuthenticationException authenticationException) throws ServletException, IOException {
... // some code to determine if the request is an ajax request or an async one
if (isAjaxOrAsyncRequest) {
SecurityContextHolder.getContext().setAuthentication(null);
authenticationEntryPoint.commence(request, response, authenticationException);
} else {
super.sendStartAuthentication(request, response, chain, authenticationException);
}
}
This makes the CustomAuthenticationEntryPoint logic much simpler:
#Override
public void commence(final HttpServletRequest request,
final HttpServletResponse response,
final AuthenticationException authException) throws IOException, ServletException {
... // some code to determine if the request is an ajax request or an async one, again
if (isAjaxOrAsyncRequest) {
response.sendError(SC_UNAUTHORIZED);
} else {
super.commence(request, response, authException);
}
}
And my CustomWebSecurityConfigurerAdapter should be configured like this:
#Override
protected void configure(final HttpSecurity http) throws Exception {
final CustomAuthenticationEntryPoint customAuthenticationEntryPoint =
new CustomAuthenticationEntryPoint("/login-path");
final CustomExceptionTranslationFilter customExceptionTranslationFilter =
new CustomExceptionTranslationFilter(customAuthenticationEntryPoint);
http.addFilterAfter(customExceptionTranslationFilter, ExceptionTranslationFilter.class)
....
.permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.exceptionHandling()
.authenticationEntryPoint(customAuthenticationEntryPoint)
....;
}

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);
}
}
}

Modify request URI in spring mvc

I have a spring mvc based application. I want to modify the request URI before it reaches controller. For example, RequestMapping for controller is "abc/xyz" but the request coming is "abc/1/xyz". I want to modify incoming request to map it to controller.
Solution1: Implement interceptor and modify incoming request URI. But the problem here is that as there is no controller matching the URI pattern "abc/1/xyz", it does not even goes to interceptor.(I might be missing something to enable it if its there)
Get around for it could be to have both of URI as request mapping for controller.
What other solutions could be there? Is there a way to handle this request even before it comes to spring. As in handle it at filter in web.xml, i am just making it up.
You could write a servlet Filter which wraps the HttpServletRequest and returns a different value for the method getRequestURI. Something like that:
public class RequestURIOverriderServletFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
chain.doFilter(new HttpServletRequestWrapper((HttpServletRequest) request) {
#Override
public String getRequestURI() {
// return what you want
}
}, response);
}
// ...
}
The servlet filter configuration must be added into the web.xml.
But sincerly, there is probably other way to solve your problems and you should not do this unless you have very good reasons.
in order to achieve this you should replace every place that affected when you calling uri.
the place that not mentioned is INCLUDE_SERVLET_PATH_ATTRIBUTE which is internally is accessed when going deeper.
public class AuthFilter implements Filter {
private final Logger logger = LoggerFactory.getLogger(AuthFilter.class);
private final String API_PREFIX = "/api";
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String requestURI = httpRequest.getRequestURI();
if (requestURI.startsWith(API_PREFIX)) {
String redirectURI = requestURI.substring(API_PREFIX.length());
StringBuffer redirectURL = new StringBuffer(((HttpServletRequest) request).getRequestURL().toString().replaceFirst(API_PREFIX, ""));
filterChain.doFilter(new HttpServletRequestWrapper((HttpServletRequest) request) {
#Override
public String getRequestURI() {
return redirectURI;
}
#Override
public StringBuffer getRequestURL() {
return redirectURL;
}
#Override
public Object getAttribute(String name) {
if(WebUtils.INCLUDE_SERVLET_PATH_ATTRIBUTE.equals(name))
return redirectURI;
return super.getAttribute(name);
}
}, response);
} else {
filterChain.doFilter(request, response);
}
}
}
You can use a URL Re-Write which are specifically meant for this purpose i.e. transform one request URI to another URI based on some regex.

What is the session size in Seam?

I would like to know my session size in my application to optimize it. To find this size, I use mat which does a heap dump and analyzes it.
Where does Seam store session and conversation beans?
I though it was in org.apache.catalina.session.StandardSession but visibly no (I have only 2 octets in this bean).
Seam stores everything in the HttpSession.
Name("someFilter")
#Filter(around = { "org.jboss.seam.web.ajax4jsfFilter" })
#Scope(ScopeType.APPLICATION)
#Startup
#BypassInterceptors
public class SomeFilter extends AbstractFilter {
private static final LogProvider log = Logging.getLogProvider(SomeFilter.class);
#SuppressWarnings("unchecked")
public void doFilter(ServletRequest request, ServletResponse resp, FilterChain arg2) throws IOException, ServletException {
if (HttpServletRequest.class.isAssignableFrom(request.getClass())) {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse response = (HttpServletResponse) resp;
HttpSession session = req.getSession();
if (log.isInfoEnabled()) {
List<String> attrNames = Collections.list(session.getAttributeNames());
for (String o : attrNames) {
log.info("objects in session " + o);
}
}
}
}

Resources