Query on <url-pattern> in <filter-mapping> [duplicate] - servlet-filters

We have a situation where we want to use filter for URL's containing some specific request parameters, e.g:
http://mydomain.com/?id=78&formtype=simple_form&.......
http://mydomain.com/?id=788&formtype=special_form&.......
and so on, id are fetched at run time, I want configure filter in web.xml only if formtype=special_form. How should achieve the solution? Can Filter be configured with regex patterns?

As far as I know there is no solution for matching requests to filters by query string directly in web.xml. So you could register the filter in your web.xml using init-params to make the filter configurable and set a pattern via void init(FilterConfig filterConfig) in your javax.servlet.Filter implementation.
package mypackage;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
public class MyFilter implements Filter {
private String pattern;
#Override
public void destroy() {
// TODO Auto-generated method stub
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// check whether we have a httpServletRequest and a pattern
if (this.pattern != null && request instanceof HttpServletRequest) {
// resolve the query string from the httpServletRequest
String queryString = ((HttpServletRequest) request).getQueryString();
// check whether a query string exists and matches the given pattern
if (queryString != null && queryString.matches(pattern)) {
// TODO do someting special
}
}
chain.doFilter(request, response);
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
this.pattern = filterConfig.getInitParameter("pattern");
}
}
The configuration would look like this in your web.xml:
<!-- MyFilter -->
<filter>
<filter-name>myFilter</filter-name>
<filter-class>mypackage.MyFilter</filter-class>
<init-param>
<param-name>pattern</param-name>
<param-value>{{PATTERN HERE}}</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Further readings:
http://java.sun.com/javaee/5/docs/api/javax/servlet/Filter.html

You must parse the URL params in the body of the filter, not in web.xml;
I made such a thing, but I used a phase listener, a configuration entry (in a configuration file) that mapped URL params to FQN of classes that handle a particular "action" (by action I mean a URL param from a GET/POST); than, the phase listener would parse all the URL params from each GET/POST and send each of them to a Dispatcher. The Dispatcher's job is to call the right handler (singleton object corresponding to the FQN for that URL param). The handler then just does the specific thing with the URL value he receives.
The same thing can be made by using a filter instead of phase listener.

Related

Whitelist user IPs in Shiro

I would like to enable Facebook to crawl my website, however it needs user authentication. Facebook says one way to get around this is to whitelist their ips. I am using Apache Shiro and I know that you can get client's ip by calling getHost from BasicHttpAuthenticationFilter, however I do not know how to let certain ip addresses past the authentication.
You will likely have to build a custom implementation of Shrio's
org.apache.shiro.web.filter.authc.AuthenticatingFilter
Minimally, you will have to customize BasicHttpAuthenticationFilter by extending it and adding logic to skip the BasicHttpAuthenticationFilter if the request is coming from a whitelisted IP address.
package com.acme.web.filter.authc;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class WhitelistedBasicHttpAuthenticationFilter extends BasicHttpAuthenticationFilter {
private Set<String> whitelist = Collections.emptySet();
public void setWhitelist(String list) {
whitelist = new HashSet<String>();
Collections.addAll(whitelist, list.split(",")); //make sure there are no spaces in the string!!!!
}
#Override
protected boolean isEnabled (ServletRequest request, ServletResponse response) throws ServletException, IOException
{
if (whitelist.contains(request.getRemoteAddr())) {
return false;
}
return super.isEnabled(request, response);
}
}
In your 'shiro.ini'
authc=com.acme.web.filter.authc.WhitelistedBasicHttpAuthenticationFilter
authc.whitelist=192.168.1.1,192.168.1.2,192.168.2.3

jaxrs queryparam not loaded for interceptor

I have a REST service of the form:
#GET
#NeedsInterception
public void getSomething(#QueryParam("xxx") #MyAnnotation String thing) {
//Stuff
}
I then have an interceptor for #NeedsInterception.
In it, I perform some logic on the element annotated with #MyAnnotation.
However, when the interceptor is called, the MethodInvocation object has not yet been resolved with the value of the QueryParam, instead it is always "";
Is there a way for me to make the interception happen after the QueryParam is resolved?
Don't know which kind of interceptor you are using but a jax-rs ReaderInterceptor is intended to wrap calls to MessageBodyReader.readFrom. As you don't send a request body with a #GET request this kind of interceptor won't be used.
A ContainerRequestFilter should help:
#Provider
public class SomeFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
MultivaluedMap<String,String> queryParameters = requestContext.getUriInfo().getQueryParameters();
}
}

How do I load and store global variables in Jersey/Glassfish

I am creating a RESTful Web Service that wraps an antiquated vendor API. Some external configuration will be required and will be stored on the server either in a file or rdbms. I'm using Jersey 1.11.1 in Glassfish 3.1.2. This configuration data is all in String key/value format.
My first question is this - where can I store global/instance variables in Jersey so that they will be persisted between requests and available to all resources? If this was a pure Servlet application I would use the ServletContext to accomplish this.
The second part to the question is how can I load my configuration once the Jersey server has loaded? Again, my Servlet analogy would be to find the equivalent to the init() method.
#Singleton #Startup EJB matches your requirements.
#Singleton
#Startup // initialize at deployment time instead of first invocation
public class VendorConfiguration {
#PostConstruct
void loadConfiguration() {
// do the startup initialization here
}
#Lock(LockType.READ) // To allow multiple threads to invoke this method
// simultaneusly
public String getValue(String key) {
}
}
#Path('/resource')
#Stateless
public class TheResource {
#EJB
VendorConfiguration configuration;
// ...
}
EDIT: Added annotation as per Graham's comment
You can use a listener for init the variables and set to the context as attribute before the web application start, something like the following:
package org.paulvargas.shared;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class LoadConfigurationListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
// read file or rdbms
...
ServletContext context = sce.getServletContext();
// set attributes
...
}
public void contextDestroyed(ServletContextEvent sce) {
ServletContext context = sce.getServletContext();
// remove attributes
...
}
}
This listener is configured in the web.xml.
<listener>
<listener-class>org.paulvargas.shared.LoadConfigurationListener</listener-class>
</listener>
You can use the #Context annotation for inject the ServletContext and retrieving the attribute.
package org.paulvargas.example.helloworld;
import java.util.*;
import javax.servlet.ServletContext;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
#Path("/world")
public class HelloWorld {
#Context
private ServletContext context;
#GET
#Produces("text/plain; charset=UTF-8")
public String getGreeting() {
// get attributes
String someVar = (String) context.getAttribute("someName")
return someVar + " says hello!";
}
}

GlassFish: How to set Access-Control-Allow-Origin header

I am using the latest version of GlassFish. I want to set the Access-Control-Allow-Origin header in response so that my API which is hosted on GlassFish can be called from any domain. But I am not able to find out where to set it.
In my case, the API requests are exclusively handled by Jersey, therefore I can set response headers in a ContainerResponseFilter:
package my.app;
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;
public class CrossOriginResourceSharingFilter implements ContainerResponseFilter {
#Override
public ContainerResponse filter(ContainerRequest creq, ContainerResponse cresp) {
cresp.getHttpHeaders().putSingle("Access-Control-Allow-Origin", "*");
cresp.getHttpHeaders().putSingle("Access-Control-Allow-Credentials", "true");
cresp.getHttpHeaders().putSingle("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
cresp.getHttpHeaders().putSingle("Access-Control-Allow-Headers", "Content-Type, Accept");
return cresp;
}
}
The filter gets enabled in web.xml:
<servlet>
<servlet-name>Gateway Servlet</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>my.app.CrossOriginResourceSharingFilter</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
If you don't use Jersey, I guess you can create a similar servlet response filter.
The best and easiest way of doing this, is right click on the project
and select Cross-Origin Resource Sharing Filter
Here is a Java EE standard way to do it. It's almost exactly the same as the Jersey example except for the library packages used (javax) and the method call to get the headers is different (getHeaders).
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
#Provider
public class RestResponseFilter implements ContainerResponseFilter{
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException{
responseContext.getHeaders().putSingle("Access-Control-Allow-Origin", "*");
responseContext.getHeaders().putSingle("Access-Control-Allow-Credentials", "true");
responseContext.getHeaders().putSingle("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
responseContext.getHeaders().putSingle("Access-Control-Allow-Headers", "Content-Type, Accept");
}
}
Since you use the tag java-ee-6, I believe #Provider isn't supported. I used the following code, based on the javaee6 tutorial:
import java.io.IOException;
import java.util.logging.Logger;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
#WebFilter(filterName = "AddHeaderFilter", urlPatterns = {"/*"})
public class ResponseFilter implements Filter {
private final static Logger log = Logger.getLogger(ResponseFilter.class.getName() );
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (response instanceof HttpServletResponse) {
log.info("Adding headers");
HttpServletResponse http = (HttpServletResponse) response;
http.addHeader("Access-Control-Allow-Origin", "*");
http.addHeader("Access-Control-Allow-Credentials", "true");
http.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
}
chain.doFilter(request, response);
}

determine target url based on roles for struts2

I am new to struts and spring security.
Can anyone help me to figure out how to redirect to different urls different users with different roles ? In other words, how to provide determine target url based on user role in struts2 using action controller?
I found the following question determine target url based on roles in spring security 3.1 , but I cannot figure out how to configure the action.
I tried the following setup, but it does not work:
security.xml
<form-login login-page="/login" authentication-failure-url="/login?error=true" login-processing-url="/j_security_check" default-target-url="/default"/>
struts.xml
<action name="default" class="com.moblab.webapp.action.RoleRedirectAction" method="defaultAfterLogin"/>
RoleRedirectAction.java
package com.moblab.webapp.action;
import javax.servlet.http.HttpServletRequest;
public class RoleRedirectAction extends BaseAction{
public String defaultAfterLogin(HttpServletRequest request) {
if (request.isUserInRole("ROLE_ADMIN")) {
return "redirect:/<url>";
}
return "redirect:/<url>";
}
}
Thanks a lot.
EDIT 1
I also tried the following annotation
#Action(value="/default",results={#Result(name="success",location="/querySessions")})
EDIT 2
My final solution looks like the following. I am not sure if it is the best approach, but it works:
public class StartPageRouter extends SimpleUrlAuthenticationSuccessHandler {
#Autowired
private UserService userService;
protected final Logger logger = Logger.getLogger(this.getClass());
private RequestCache requestCache = new HttpSessionRequestCache();
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
//default path for ROLE_USER
String redirectPath = <url>;
if (authorities != null && !authorities.isEmpty()) {
Set<String> roles = getUserRoles(authorities);
if (roles.contains("ROLE_ADMIN"))
redirectPath = <url>;
else if (roles.contains("ROLE_INSTRUCTOR"))
redirectPath = <url>;
}
getRedirectStrategy().sendRedirect(request, response, redirectPath);
}
public void setRequestCache(RequestCache requestCache) {
this.requestCache = requestCache;
}
private Set<String> getUserRoles(Collection<? extends GrantedAuthority> authorities) {
Set<String> userRoles = new HashSet<String>();
for (GrantedAuthority authority : authorities) {
userRoles.add(authority.getAuthority());
}
return userRoles;
}
}
EDIT 3
There are even better solutions here:
http://oajamfibia.wordpress.com/2011/07/07/role-based-login-redirect/#comment-12
Assuming that you mean that you want to redirect users to different start pages depending on their assigned roles then you can try this. Note that I do all this outside of Struts.
First create your own class that extends Springs SimpleUrlAuthenticationSuccessHandler and override the onAuthenticationSuccess() method. The actual redirect is performed within the onAuthenticationSuccess() method by the line getRedirectStrategy().sendRedirect(request,response,);
So all you need is a means of substituting your own url's.
So, for example I have
package com.blackbox.x.web.security;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import com.blackbox.x.entities.UserDTO;
import com.blackbox.x.services.UserService;
public class StartPageRouter extends SimpleUrlAuthenticationSuccessHandler {
#Autowired
UserService userService;
#Autowired
LoginRouter router;
protected final Logger logger = Logger.getLogger(this.getClass());
private RequestCache requestCache = new HttpSessionRequestCache();
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication) throws IOException,
ServletException {
requestCache.removeRequest(request, response);
User user = (User) authentication.getPrincipal();
UserDTO userDTO = userService.find(user.getUsername());
getRedirectStrategy().sendRedirect(request, response, router.route(userDTO));
}
public void setRequestCache(RequestCache requestCache) {
this.requestCache = requestCache;
}
}
where LoginRouter is my own class that takes the logged in user and, from the assigned roles determines which URL the user should be directed to.
You then configure Spring Security to use your version using the
authentication-success-handler-ref="customTargetUrlResolver"/>
and
<beans:bean id="customTargetUrlResolver" class="com.blackbox.x.web.security.StartPageRouter"/>
in your security context xml file.