#Value variable is null in customFilter implementing Filter - spring-boot

my custom filter is not taking value from .properties/.yml file
Note: property file is located at src/main/resources folder
#Slf4j
public class CustomFilter implements Filter {
#Value("${xyz.domainName:http://localhost:8080/x1}")
private String DOMAIN_NAME;
private static final String REDIRECT_URL_ENDPOINT = "/v1/xyz/abc/";
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String url = request.getRequestURL().toString();
String id = url.substring(url.lastIndexOf("/") + 1);
if (url.startsWith(DOMAIN_NAME)) {
ServletContext context = request.getServletContext();
RequestDispatcher dispatcher = context.getRequestDispatcher(REDIRECT_URL_ENDPOINT + id);
dispatcher.forward(request, response);
}
else
filterChain.doFilter(request, response);
}
}
Edit (Added WebSecurityConfigClass): My WebSecurityConfig class looks like:
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(new CustomFilter(), ApiKeyAuthFilter.class);
}
}

Looking at the code, you filter is not managed by the Spring Context, therefore Spring-related functionalities like #Value do not work. So, let Spring take care of your filter.
#Component
#Slf4j
public class CustomFilter implements Filter {
#Value("${xyz.domainName:http://localhost:8080/x1}")
private String DOMAIN_NAME;
private static final String REDIRECT_URL_ENDPOINT = "/v1/xyz/abc/";
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String url = request.getRequestURL().toString();
String id = url.substring(url.lastIndexOf("/") + 1);
if (url.startsWith(DOMAIN_NAME)) {
ServletContext context = request.getServletContext();
RequestDispatcher dispatcher = context.getRequestDispatcher(REDIRECT_URL_ENDPOINT + id);
dispatcher.forward(request, response);
}
else
filterChain.doFilter(request, response);
}
#Bean
public FilterRegistrationBean registerFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(this);
registration.addUrlPatterns("/*");
return registration;
}
}
If you want to register the filter before a Spring security filter you can do this:
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private Customfilter customfilter;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(customfilter, ApiKeyAuthFilter.class);
}
}

Related

Defined Property from Application.property getting NULL in class file using Spring boot Filter Implementation

I am trying to do one sample of rest template and property injection for variable defined from application.property. For this I created one filter implementation and done like the following. But when I am accessing the property I am getting error like following
java.lang.IllegalArgumentException: URI must not be null
And I created my filter implementation code like the following,
#Component
public class CustomSecurityFilter extends OncePerRequestFilter implements Filter{
#Value ("${securityTriggerServiceApiUrl}" )
public String triggerUrl;
#Override
protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) throws ServletException, IOException {
String authHeaderToken = request.getHeader("authToken");
System.out.println("token :"+authHeaderToken);
if(checkAuthenticationByAuthToken(authHeaderToken))
{
filterChain.doFilter(request, response);
}
else
{
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
}
}
private static HttpHeaders getApiHeaders(){
String plainCredentials="${seccurityTriggerEncodingCredential}";
String base64Credentials = new String(Base64.encodeBase64(plainCredentials.getBytes()));
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Credentials);
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
public Boolean checkAuthenticationByAuthToken(String authTokenRequest) {
AuthorizationRequest authApiRequestObj = new AuthorizationRequest();
authApiRequestObj.auth_token = authTokenRequest;
RestTemplate restTemplate = new RestTemplate();
HttpEntity<Object> request = new HttpEntity<Object>(authApiRequestObj, getApiHeaders());
AuthorizationResponse authorizationResponseObj = restTemplate.postForObject(getApiTriggerStringUrl(), request, AuthorizationResponse.class);
System.out.println("RoleId is :"+authorizationResponseObj.role_id);
if(authorizationResponseObj.role_id >= 0 ) {
return true;
}
return false;
}
public String getApiTriggerStringUrl() {
return this.triggerUrl;
}
}
My application.property file added like the following,
seccurityTriggerEncodingCredential=test:test
securityTriggerServiceApiUrl=http://localhost:8065/test/security/authorizeUser
My Security config file contains like the following way,
#EnableWebSecurity
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.addFilterAfter(new CustomSecurityFilter(), BasicAuthenticationFilter.class);
}
}
Why I am getting the error like this?
The problem is while registering your filter, you have created a new filter with new. So configuration is not picking the one created by Spring. You can do either of following -
1) Autowire the existing spring bean in your configuration class -
#EnableWebSecurity
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private CustomSecurityFilter customSecurityFilter;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.addFilterAfter(customSecurityFilter, BasicAuthenticationFilter.class);
}
}
You can do autowiring any way either directly through #Autowired or through constructor.
2) Second way is to create CustomSecurityFilter bean by yourself. Sample code as per your code -
a) Don't annotate your filter with #Component. Remove #Value and create a setter for your property.
public class CustomSecurityFilter extends OncePerRequestFilter implements Filter{
public String triggerUrl;
public void setTriggerUrl(String triggerUrl) {
this.triggerUrl = triggerUrl;
}
#Override
protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) throws ServletException, IOException {
String authHeaderToken = request.getHeader("authToken");
System.out.println("token :"+authHeaderToken);
if(checkAuthenticationByAuthToken(authHeaderToken))
{
filterChain.doFilter(request, response);
}
else
{
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
}
}
private static HttpHeaders getApiHeaders(){
String plainCredentials="${seccurityTriggerEncodingCredential}";
String base64Credentials = new String(Base64.encodeBase64(plainCredentials.getBytes()));
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Credentials);
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
public Boolean checkAuthenticationByAuthToken(String authTokenRequest) {
AuthorizationRequest authApiRequestObj = new AuthorizationRequest();
authApiRequestObj.auth_token = authTokenRequest;
RestTemplate restTemplate = new RestTemplate();
HttpEntity<Object> request = new HttpEntity<Object>(authApiRequestObj, getApiHeaders());
AuthorizationResponse authorizationResponseObj = restTemplate.postForObject(getApiTriggerStringUrl(), request, AuthorizationResponse.class);
System.out.println("RoleId is :"+authorizationResponseObj.role_id);
if(authorizationResponseObj.role_id >= 0 ) {
return true;
}
return false;
}
public String getApiTriggerStringUrl() {
return this.triggerUrl;
}
}
b) Your configuration class will be then -
#EnableWebSecurity
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.addFilterAfter(customSecurityFilter(), BasicAuthenticationFilter.class);
}
#Bean
public CustomSecurityFilter customSecurityFilter() {
CustomSecurityFilter customSecurityFilter = new CustomSecurityFilter();
customSecurityFilter.setTriggerUrl(<property value>);
return customSecurityFilter;
}
}

Spring Boot register a filter after spring security filter is executed

I have defined 2 filters which should run on every request, but only after SecurityContextHolder's context is set by spring boot.
However, i always get SecurityContextHolder.getContext().getAuthentication() as null.
Here is my filter configuration:
#Bean
public FilterRegistrationBean SecurityContextHystrixRequestVariableSetterBean() throws Exception {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(securityContextHystrixRequestVariableSetterFilter());
registration.setOrder(Ordered.LOWEST_PRECEDENCE);
return registration;
}
#Bean
public FilterRegistrationBean HystrixRequestContextEnablerFilterBean() throws Exception {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(hystrixRequestContextEnablerFilter());
registration.setOrder(Ordered.LOWEST_PRECEDENCE);
return registration;
}
Filter details:
public class SecurityContextHystrixRequestVariableSetterFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
SecurityContextHystrixRequestVariable.getInstance().set(SecurityContextHolder.getContext());
chain.doFilter(request, response);
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void destroy() {
}
}
public class HystrixRequestContextEnablerFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HystrixRequestContext context = HystrixRequestContext.initializeContext();
try {
chain.doFilter(request, response);
} finally {
context.shutdown();
}
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void destroy() {
}
}
You can use OncePerRequestFilter:
public class CustomFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
//do
chain.doFilter(request, response);
}
}
#Configuration
public class CustomConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterAfter(new SecurityFilter(authenticationManager()), AnonymousAuthenticationFilter.class)
}
}

get request header in a Filter

I registered a Filter in Spring boot and been trying to get and Header from the request but getting null.
#Component
#Order(1)
public class ExampleFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws... {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
//null**
final String header = httpServletRequest.getHeader(HEADER);
}
BUT
#GetMapping(value = "example")
public ResponseEntity<Example> example( #RequestHeader(HEADER) String header) {
... the header is NOT null
}
Please check my example here
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class CustomFilter implements Filter {
public CustomFilter() {
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
HttpServletRequest httpRequest = (HttpServletRequest) request;
Enumeration<String> headerNames = httpRequest.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
System.out.println("Header: " + name + " value:" + httpRequest.getHeader(name));
}
}
chain.doFilter(req, res);
}
#Override
public void init(FilterConfig filterConfig) {
}
#Override
public void destroy() {
}
}

Set response header in Spring Boot

How can I set the response header for each call in my application made with Spring Boot?
I would like to try to use a filter to intercept all the calls and be able to set the response header.
I followed the guide Disable browser caching HTML5, but only set the request header, and not always.
There are three ways to do this:
Set the response for a specific controller, in the Controller class:
#Controller
#RequestMapping(value = DEFAULT_ADMIN_URL + "/xxx/")
public class XxxController
....
#ModelAttribute
public void setResponseHeader(HttpServletResponse response) {
response.setHeader("Cache-Control", "no-cache");
....
}
or
#RequestMapping(value = "/find/employer/{employerId}", method = RequestMethod.GET)
public List getEmployees(#PathVariable("employerId") Long employerId, final HttpServletResponse response) {
response.setHeader("Cache-Control", "no-cache");
return employeeService.findEmployeesForEmployer(employerId);
}
Or you can put the response header for each call in the application (this is for Spring annotation-based, otherwise see automatically add header to every response):
#Component
public class Filter extends OncePerRequestFilter {
....
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
//response.addHeader("Access-Control-Allow-Origin", "*");
//response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Cache-Control", "no-store"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setHeader("Expires", "0"); // Proxies.
filterChain.doFilter(request, response);
}
}
The last way I found is using an Interceptor that extends HandlerInterceptorAdapter; for more info see https://www.concretepage.com/spring/spring-mvc/spring-handlerinterceptor-annotation-example-webmvcconfigureradapter
create your Interceptor that extends HandlerInterceptorAdapter:
public class HeaderInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) {
httpServletResponse.setHeader("Cache-Control", "no-store"); // HTTP 1.1.
httpServletResponse.setHeader("Pragma", "no-cache"); // HTTP 1.0.
httpServletResponse.setHeader("Expires", "0"); // Proxies.
return true;
}
}
In your MvcConfig thath extends WebMvcConfigurerAdapter you must Override the addInterceptors method and add new Interceptor:
#Override
public void addInterceptors(InterceptorRegistry registry) {
....
registry.addInterceptor(new HeaderInterceptor());
}
I hope I was helpful!
Implement Filter and is registered by #Component annotation. The #Order(Ordered.HIGHEST_PRECEDENCE) is used for Advice execution precedence.
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class NoCacheWebFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(NoCacheWebFilter.class);
#Override
public void init(FilterConfig filterConfig) throws ServletException {
logger.debug("Initiating WebFilter >> ");
}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HeaderMapRequestWrapper requestWrapper = new
HeaderMapRequestWrapper(req);
// implement you logic to add header
//requestWrapper.addHeader("remote_addr", "");
chain.doFilter(requestWrapper, response);
}
#Override
public void destroy() {
logger.debug("Destroying WebFilter >> ");
}
}

web filter cannot read Property file in spring boot

I have simple ip filter, which will filter ips not in white list.
The code is simple, like
#EnableConfigurationProperties(AppProperties.class)
public class ClientIpFilter implements Filter {
#Autowired
private AppProperties appProperties;
#Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
HashSet<String> trustedIps = loadAccessIPList();
HttpServletRequest req = (HttpServletRequest) request;
Map<String, String> headerMap = new HashMap<String, String>();
Enumeration<String> headers = req.getHeaderNames();
while (headers.hasMoreElements()) {
String str = (String) headers.nextElement();
headerMap.put(str, req.getHeader(str));
}
.............
}
And I define a Configuration to include it.
#Configuration
public class CustomWebSecurityConfigurerAdapter {
#Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
ClientIpFilter securityFilter = new ClientIpFilter();
registrationBean.setFilter(securityFilter);
registrationBean.setOrder(1);
return registrationBean;
}
}
But the Filter cannot autowired AppProperties which includes configuration from my application.preperties.
Your AppProperties file should be like below with annotations and appropriate prefix as mentioned in application.properties file
#Configuration
#ConfigurationProperties(prefix = "com.test")
public class AppProperties {
private String name;
private String age;
}
The #EnableConfigurationProperties should not be required in ClientFilter class. Just autowiring the Properties file should be ok ..
I find the root reason. I need to let the ClientIpFilter to be a component so that it can be autowired, then spring can register other property.
#Component
#EnableConfigurationProperties(AppProperties.class)
public class ClientIpFilter implements Filter {
#Autowired
private AppProperties appProperties;
#Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
HashSet<String> trustedIps = loadAccessIPList();
HttpServletRequest req = (HttpServletRequest) request;
Map<String, String> headerMap = new HashMap<String, String>();
.............
}

Resources