How to disable JWT Authorization on specific API endpoints (Java)? - java

I have API endpoints configured for JWT Authorization:
#Bean
public FilterRegistrationBean<EsgJwtAuth> esgJwtAuthBean() {
EsgJwtAuth esgJwtAuth;
try {
HashMap<String, String> myConf = new HashMap<>();
myConf.put("header", "Authorization");
myConf.put("jwksUrl", jwksUrl);
myConf.put("jwksCacheSize", jwksCacheSize);
myConf.put("jwksExpiresIn", jwksExpiresIn);
myConf.put("jwksRateLimitSize", jwksRateLimitSize);
myConf.put("jwksRateLimitRefillRate", jwksRateLimitRefillRate);
esgJwtAuth = new EsgJwtAuth(myConf);
} catch (Exception e) {
esgJwtAuth = new EsgJwtAuth();
}
FilterRegistrationBean<EsgJwtAuth> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(esgJwtAuth);
registrationBean.addUrlPatterns("/a/*");
registrationBean.addUrlPatterns("/b/*");
registrationBean.addUrlPatterns("/c/*");
return registrationBean;
}
Now, i wanted to make /a/noauth to not require a JWT authorization. But for other endpoints such as /a/withauth/, /a/* i want it to require JWT authorization (as registered on the FilterRegistrationBean)
So far, i tried extending my class with OncePerRequestFilter and implemented the ff codes:
#Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
List<String> excludeUrlPatterns = new ArrayList<String>();
excludeUrlPatterns.add("/a/noauth/");
excludeUrlPatterns.add("/b/noauth/");
return excludeUrlPatterns.stream()
.anyMatch(exclude -> request.getRequestURI().contains(exclude));
}
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
chain.doFilter(request, response);
}
But when i run a request for /a/noauth without the Header: <JWT token>, it is Unauthorized. How to allow it? Thank you.

I do think that your excludeUrlPatterns List contains the wrong values (i.e. put /a/noauth instead of /a/noauth/).
I would rather suggest to use the AntPathMatcher class to check your excluding patterns. See below a naive implementation:
private AntPathMatcher pathMatcher = new AntPathMatcher();
#Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
List<String> excludeUrlPatterns = new ArrayList<String>();
excludeUrlPatterns.add("/a/noauth");
excludeUrlPatterns.add("/b/noauth");
return excludeUrlPatterns.stream()
.anyMatch(p -> pathMatcher.match(p, request.getRequestURI()));
}

Related

Injecting custom headers into ServletRequest in Spring Boot JAVA

I have a requirement to inject custom headers into every request a spring boot application is getting, for this, I have written some code but it seems it is not doing its work. For a brief, I have implemented the Filter interface and defined the doFilter method, extended the HttpServletRequestWrapper class, and overridden getHeader() and getHeaderNames() method to take into account the custom headers I am reading from the properties file.
But, the moment I get into the controller and check the request I am not getting my custom headers that were set through the MyReqWrapper. Below is the code, I've also tried searching it in Stackoverflow but couldn't find the solution on what is/could be wrong here. Can someone point me in the right direction?
Also, please point me on how to test whether custom headers are actually set or not.
This is Filter implementation
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class ReqFilter implements Filter {
private static final String CUSTOMHEADERENABLED = "customheadersenabled";
private static final String CUSTOMHEADERCOUNT = "customheaderscount";
#Autowired
private Environment env;
#Override
public void init(FilterConfig filterConfig) throws ServletException {
//
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
try {
boolean customHeadersEnabled = Boolean.parseBoolean(env.getProperty(CUSTOMHEADERENABLED, "false"));
int count = Integer.parseInt(env.getProperty(CUSTOMHEADERCOUNT, "0"));
if (customHeadersEnabled && count > 0) {
MyReqWrapper myReq = new MyReqWrapper((HttpServletRequest) servletRequest);
myReq.processMyHeaders(count, env);
filterChain.doFilter(customRequest, servletResponse);
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
}
catch(ServletException ex){
throw ex;
}
}
#Override
public void destroy() {
//
}
}
This is custom request wrapper extending HttpServletRequestWrapper
final class MyReqWrapper extends HttpServletRequestWrapper {
private static final String CUSTOMHEADERPREFIX = "header1";
private final Map<String, String> myHeaders;
public MyReqWrapper(HttpServletRequest request) {
super(request);
myHeaders = new HashMap<>();
}
#Override
public String getHeader(String name) {
String headerValue = myHeaders.get(name);
if (headerValue != null){
return headerValue;
}
return ((HttpServletRequest) getRequest()).getHeader(name);
}
#Override
public Enumeration<String> getHeaderNames() {
Set<String> set = new HashSet<>(myHeaders.keySet());
Enumeration<String> headerNames = ((HttpServletRequest) getRequest()).getHeaderNames();
while (headerNames.hasMoreElements()) {
String n = headerNames.nextElement();
set.add(n);
}
return Collections.enumeration(set);
}
public void processMyHeaders(int headerCount, Environment env) {
while(headerCount > 0){
String [] headerKeyValue = Objects.requireNonNull(env.getProperty(String.format("%1$s%2$s", CUSTOMHEADERPREFIX, headerCount--)))
.split(":");
this.myHeaders.put(headerKeyValue[0], headerKeyValue[1]);
}
}
}
This was solved for me and I forgot to update this with an answer.
So the problem was I was using HttpServletRequest class from two different namespaces in the ReqFilter and controller classes, namely one from "org.apache.catalina.servlet4preview.http.HttpServletRequest" and another from "javax.servlet.http.HttpServletRequest".
Once I used uniform namespace in both the files I could access the headers from controller classes.

Java Spring boot - OnceRequestPerFilter allow only controller requestmappings

I'm currently implementing audit trail in my project, I tried using HandlerInterceptor and it seems it won't work in my project, so i looked for another way and I discovered that it's possible with OncePerRequestFilter.
Here's the code of my OncePerRequestFilter class:
#Component
#Order
public class LogFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String method = request.getMethod();
String username = SecurityContextHolder.getContext().getAuthentication().getName();
String url = request.getRequestURL().toString();
// Log the info you need
// ...
filterChain.doFilter(request, response);
}
}
The only problem so far that I see with my current configuration of OncePerRequestFilter is it also includes the resources such as css / javascripts.
example these links will be also go to the filter:
http://localhost:8000/project/css/style.css
http://localhost:8000/project/3277a64fcca0dbde907d8684aed8f170.png
http://localhost:8000/project/js/script.js.map
What i want is to filter only the controller request mappings, and ignore the resources
example:
http://localhost:8000/project/accounts/client-users
http://localhost:8000/project/accounts
This code is a workaround to ignore resource file. not sure if it's the best practice tho.
#Component
#Order
public class LogFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String method = request.getMethod();
String username = SecurityContextHolder.getContext().getAuthentication().getName();
String url = request.getRequestURL().toString();
filterChain.doFilter(request, response);
}
protected boolean shouldNotFilter(HttpServletRequest request)
throws ServletException {
String url = request.getRequestURL().toString();
return isResourceUrl(url);
}
private boolean isResourceUrl(String url) {
boolean isResourceUrl = false;
List<String> resourceRequests = Arrays.asList(
"/css/", "/js/", "/scss/", "/fonts/", "/emails/",
".css", ".js", ".scss", ".eot", ".svg", ".ttf", ".woff", ".otf", ".ico", ".png");
for (String resourceRequest : resourceRequests) {
if (url.contains(resourceRequest)) {
isResourceUrl = true;
}
}
return isResourceUrl;
}
}
Use something like this:
#Override
public void configure(final WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(
"/example/docs",
"/swagger-resources/**",
"/swagger-ui.html");
}

Required request body is missing after making a copy using HttpServletRequestWrapper

In my project, I have a set of api calls which should filtered through certain set of common validation. In that case, I have to intercept the request before it hits the REST controller, read the request body, do the validations and pass it to the controller if the request passes the validations.
Since the HttpServletRequest cannot be deserialized more than once, I used a HttpServletRequestWrapper to make a copy of the actual request. Using the copy it makes, I do the validations.
Following is the configuration class for intercepting the requests.
public class InterceptorConfig extends WebMvcConfigurerAdapter {
#Autowired
CustomInterceptor customInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(customInterceptor).addPathPatterns("/signup/**");
}
}
Here is my preHandle method inside CustomInterceptor class which extends HandlerInterceptorAdaptor
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
ServletRequest copiedRequest = new HttpRequestWrapper(request);
Map<String, Object> jsonMap = mapper.readValue(copiedRequest.getInputStream(), Map.class);
if(jsonMap.containsKey("userId")){
long userId = jsonMap.get("userId");
MyClass myObject= myAutowiredService.getMyObject(userId);
if(myObject == null){
response.setStatus(HttpStatus.SC_NOT_ACCEPTABLE);
return false;
}
// some more validations which end up returning false if they are met
}
return true;
}
This is my HttpRequestWrapper
public class HttpRequestWrapper extends HttpServletRequestWrapper {
private byte[] requestBody;
public HttpRequestWrapper(HttpServletRequest request) throws IOException{
super(request);
try {
requestBody = IOUtils.toByteArray(request.getInputStream());
} catch (IOException ex) {
requestBody = new byte[0];
}
}
#Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(requestBody);
return new ServletInputStream() {
#Override
public boolean isFinished() {
return byteArrayInputStream.available() == 0;
}
#Override
public boolean isReady() {
return true;
}
#Override
public void setReadListener(ReadListener listener) {
throw new RuntimeException("Not implemented");
}
public int read () throws IOException {
return byteArrayInputStream.read();
}
};
}
}
All set now. Now, when I send a request to any url with the pattern of /signup/**, all the validations are happening fine. However, once the request hits the controller method, error pops out saying the request body is not available.
Required request body is missing: public
com.mypackage.myResponseObject
com.mypackage.myController.myControllerMethod(com.mypackage.myDTO)
I am struggling to find the reason for this and also a way to overcome the issue. Is there anything I have done wrong in RequestWrapper class? or anything missing?
Help me to sort this thing out.
Thanks!
The Problem seems to be that you are using an Interceptor to read the HttpServletRequest's InputStream and just wrap it in HttpRequestWrapper but the wrapper is never returned.
I think you should use a Filter
public class CustomFilter extends OncePerRequestFilter {
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
ServletRequest copiedRequest = new HttpRequestWrapper(request);
Map<String, Object> jsonMap = mapper.readValue(copiedRequest.getInputStream(), Map.class);
if(jsonMap.containsKey("userId")){
long userId = jsonMap.get("userId");
MyClass myObject= myAutowiredService.getMyObject(userId);
if(myObject == null){
response.setStatus(HttpStatus.SC_NOT_ACCEPTABLE);
//return false;
}
// some more validations which end up returning false if they are met
}
filterChain.doFilter(copiedRequest, (ServletResponse) response);
}
}
And you need to use this Filter in either web.xml or WebApplicationInitializer

How to write ResponseEntity to HttpServletResponse?

How to write ResponseEntity to HttpServletResponse (as it makes #ResponseBody)?
For example I have authentication success handler:
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
Map responseMap = new HashMap();
responseMap.put("user", "my_user_name");
ResponseEntity responseEntity = new ResponseEntity(response, HttpStatus.OK);
}
If use MappingJackson2HttpMessageConverter I have error: "Could not write content: not in non blocking mode."
Code:
HttpOutputMessage outputMessage = new ServletServerHttpResponse(response);
messageConverter.write(responseEntity, null, outputMessage);
What are the best practices of implementation handlers with HttpServletResponse?
You can use a custom response object, convert it to a JSON string using the Jackson's ObjectMapper and write the result into the request.
Example
MyResponseObject.java
private String user;
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
MyAuthenticationSuccessHandler.java
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
MyResponseObject responseObj = new MyResponseObject();
responseObj.setUser("my_user_name");
String json = new ObjectMapper().writeValueAsString(responseObj);
httpServletResponse.setStatus(HttpStatus.OK.value());
httpServletResponse.getWriter().write(json);
httpServletResponse.flushBuffer();
}
Based on andrearro88's answer, I have made this generic function to copy a ResponseEntity to a HttpServletResponse:
public static void populateResponse(ResponseEntity<String> responseEntity, HttpServletResponse servletResponse)
throws IOException {
for (Map.Entry<String, List<String>> header : responseEntity.getHeaders().entrySet()) {
String chave = header.getKey();
for (String valor : header.getValue()) {
servletResponse.addHeader(chave, valor);
}
}
servletResponse.setStatus(responseEntity.getStatusCodeValue());
servletResponse.getWriter().write(responseEntity.getBody());
}

Spring security OAuth2 accept JSON

I am starting with Spring OAuth2. I would like to send the username and password to /oauth/token endpoint in POST body in application/json format.
curl -X POST -H "Authorization: Basic YWNtZTphY21lc2VjcmV0" -H "Content-Type: application/json" -d '{
"username": "user",
"password": "password",
"grant_type": "password"
}' "http://localhost:9999/api/oauth/token"
Is that possible?
Could you please give me an advice?
Solution (not sure if correct, but it seam that it is working):
Resource Server Configuration:
#Configuration
public class ServerEndpointsConfiguration extends ResourceServerConfigurerAdapter {
#Autowired
JsonToUrlEncodedAuthenticationFilter jsonFilter;
#Override
public void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(jsonFilter, ChannelProcessingFilter.class)
.csrf().and().httpBasic().disable()
.authorizeRequests()
.antMatchers("/test").permitAll()
.antMatchers("/secured").authenticated();
}
}
Filter:
#Component
#Order(value = Integer.MIN_VALUE)
public class JsonToUrlEncodedAuthenticationFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
if (Objects.equals(request.getContentType(), "application/json") && Objects.equals(((RequestFacade) request).getServletPath(), "/oauth/token")) {
InputStream is = request.getInputStream();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[16384];
while ((nRead = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
byte[] json = buffer.toByteArray();
HashMap<String, String> result = new ObjectMapper().readValue(json, HashMap.class);
HashMap<String, String[]> r = new HashMap<>();
for (String key : result.keySet()) {
String[] val = new String[1];
val[0] = result.get(key);
r.put(key, val);
}
String[] val = new String[1];
val[0] = ((RequestFacade) request).getMethod();
r.put("_method", val);
HttpServletRequest s = new MyServletRequestWrapper(((HttpServletRequest) request), r);
chain.doFilter(s, response);
} else {
chain.doFilter(request, response);
}
}
#Override
public void destroy() {
}
}
Request Wrapper:
public class MyServletRequestWrapper extends HttpServletRequestWrapper {
private final HashMap<String, String[]> params;
public MyServletRequestWrapper(HttpServletRequest request, HashMap<String, String[]> params) {
super(request);
this.params = params;
}
#Override
public String getParameter(String name) {
if (this.params.containsKey(name)) {
return this.params.get(name)[0];
}
return "";
}
#Override
public Map<String, String[]> getParameterMap() {
return this.params;
}
#Override
public Enumeration<String> getParameterNames() {
return new Enumerator<>(params.keySet());
}
#Override
public String[] getParameterValues(String name) {
return params.get(name);
}
}
Authorization Server Configuration (disable Basic Auth for /oauth/token endpoint:
#Configuration
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
...
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.allowFormAuthenticationForClients(); // Disable /oauth/token Http Basic Auth
}
...
}
From the OAuth 2 specification,
The client makes a request to the token endpoint by sending the
following parameters using the "application/x-www-form-urlencoded"
Access token request should use application/x-www-form-urlencoded.
In Spring security, the Resource Owner Password Credentials Grant Flow is handled by ResourceOwnerPasswordTokenGranter#getOAuth2Authentication in Spring Security:
protected OAuth2Authentication getOAuth2Authentication(AuthorizationRequest clientToken) {
Map parameters = clientToken.getAuthorizationParameters();
String username = (String)parameters.get("username");
String password = (String)parameters.get("password");
UsernamePasswordAuthenticationToken userAuth = new UsernamePasswordAuthenticationToken(username, password);
You can send username and password to request parameter.
If you really need to use JSON, there is a workaround. As you can see, username and password is retrieved from request parameter. Therefore, it will work if you pass them from JSON body into the request parameter.
The idea is like follows:
Create a custom spring security filter.
In your custom filter, create a class to subclass HttpRequestWrapper. The class allow you to wrap the original request and get parameters from JSON.
In your subclass of HttpRequestWrapper, parse your JSON in request body to get username, password and grant_type, and put them with the original request parameter into a new HashMap. Then, override method of getParameterValues, getParameter, getParameterNames and getParameterMap to return values from that new HashMap
Pass your wrapped request into the filter chain.
Configure your custom filter in your Spring Security Config.
Hope this can help
With Spring Security 5 I only had to add .allowFormAuthenticationForClients() + the JsontoUrlEncodedAuthenticationFilter noted in the other answer to get it to accept json in addition to x-form post data. There was no need to register the resource server or anything.
Also you can modify #jakub-kopřiva solution to support http basic auth for oauth.
Resource Server Configuration:
#Configuration
public class ServerEndpointsConfiguration extends ResourceServerConfigurerAdapter {
#Autowired
JsonToUrlEncodedAuthenticationFilter jsonFilter;
#Override
public void configure(HttpSecurity http) throws Exception {
http
.addFilterAfter(jsonFilter, BasicAuthenticationFilter.class)
.csrf().disable()
.authorizeRequests()
.antMatchers("/test").permitAll()
.antMatchers("/secured").authenticated();
}
}
Filter with internal RequestWrapper
#Component
public class JsonToUrlEncodedAuthenticationFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (Objects.equals(request.getServletPath(), "/oauth/token") && Objects.equals(request.getContentType(), "application/json")) {
byte[] json = ByteStreams.toByteArray(request.getInputStream());
Map<String, String> jsonMap = new ObjectMapper().readValue(json, Map.class);;
Map<String, String[]> parameters =
jsonMap.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
e -> new String[]{e.getValue()})
);
HttpServletRequest requestWrapper = new RequestWrapper(request, parameters);
filterChain.doFilter(requestWrapper, response);
} else {
filterChain.doFilter(request, response);
}
}
private class RequestWrapper extends HttpServletRequestWrapper {
private final Map<String, String[]> params;
RequestWrapper(HttpServletRequest request, Map<String, String[]> params) {
super(request);
this.params = params;
}
#Override
public String getParameter(String name) {
if (this.params.containsKey(name)) {
return this.params.get(name)[0];
}
return "";
}
#Override
public Map<String, String[]> getParameterMap() {
return this.params;
}
#Override
public Enumeration<String> getParameterNames() {
return new Enumerator<>(params.keySet());
}
#Override
public String[] getParameterValues(String name) {
return params.get(name);
}
}
}
And also you need to allow x-www-form-urlencoded authentication
#Configuration
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
...
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.allowFormAuthenticationForClients();
}
...
}
With this approach you can still use basic auth for oauth token and request token with json like this:
Header:
Authorization: Basic bG9yaXpvbfgzaWNwYQ==
Body:
{
"grant_type": "password",
"username": "admin",
"password": "1234"
}
You can modify #jakub-kopřiva solution to implement only authorization server with below code.
#Configuration
#Order(Integer.MIN_VALUE)
public class AuthorizationServerSecurityConfiguration
extends org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerSecurityConfiguration {
#Autowired
JsonToUrlEncodedAuthenticationFilter jsonFilter;
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.addFilterBefore(jsonFilter, ChannelProcessingFilter.class);
super.configure(httpSecurity);
}
}
Hello based on #Jakub Kopřiva answer I have made improvements in order to create working integration tests.
Just so you know, Catalina RequestFacade throws an error in Junit and MockHttpServletRequest, used by mockmvc, does not contain a field "request" as I expect in the filter (therefore throwning NoSuchFieldException when using getDeclaredField()):
Field f = request.getClass().getDeclaredField("request");
This is why I used "Rest Assured". However at this point I ran into another issue which is that for whatever reason the content-type from 'application/json' is overwritten into 'application/json; charset=utf8' even though I use MediaType.APPLICATION_JSON_VALUE. However, the condition looks for something like 'application/json;charset=UTF-8' which lies behind MediaType.APPLICATION_JSON_UTF8_VALUE, and in conclusion this will always be false.
Therefore I behaved as I used to do when I coded in PHP and I have normalized the strings (all characters are lowercase, no spaces).
After this the integration test finally passes.
---- JsonToUrlEncodedAuthenticationFilter.java
package com.example.springdemo.configs;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import org.apache.catalina.connector.Request;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.security.web.savedrequest.Enumerator;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;
#Component
#Order(value = Integer.MIN_VALUE)
public class JsonToUrlEncodedAuthenticationFilter implements Filter {
private final ObjectMapper mapper;
public JsonToUrlEncodedAuthenticationFilter(ObjectMapper mapper) {
this.mapper = mapper;
}
#Override
public void init(FilterConfig filterConfig) {
}
#Override
#SneakyThrows
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
Field f = request.getClass().getDeclaredField("request");
f.setAccessible(true);
Request realRequest = (Request) f.get(request);
//Request content type without spaces (inner spaces matter)
//trim deletes spaces only at the beginning and at the end of the string
String contentType = realRequest.getContentType().toLowerCase().chars()
.mapToObj(c -> String.valueOf((char) c))
.filter(x->!x.equals(" "))
.collect(Collectors.joining());
if ((contentType.equals(MediaType.APPLICATION_JSON_UTF8_VALUE.toLowerCase())||
contentType.equals(MediaType.APPLICATION_JSON_VALUE.toLowerCase()))
&& Objects.equals((realRequest).getServletPath(), "/oauth/token")) {
InputStream is = realRequest.getInputStream();
try (BufferedReader br = new BufferedReader(new InputStreamReader(is), 16384)) {
String json = br.lines()
.collect(Collectors.joining(System.lineSeparator()));
HashMap<String, String> result = mapper.readValue(json, HashMap.class);
HashMap<String, String[]> r = new HashMap<>();
for (String key : result.keySet()) {
String[] val = new String[1];
val[0] = result.get(key);
r.put(key, val);
}
String[] val = new String[1];
val[0] = (realRequest).getMethod();
r.put("_method", val);
HttpServletRequest s = new MyServletRequestWrapper(((HttpServletRequest) request), r);
chain.doFilter(s, response);
}
} else {
chain.doFilter(request, response);
}
}
#Override
public void destroy() {
}
class MyServletRequestWrapper extends HttpServletRequestWrapper {
private final HashMap<String, String[]> params;
MyServletRequestWrapper(HttpServletRequest request, HashMap<String, String[]> params) {
super(request);
this.params = params;
}
#Override
public String getParameter(String name) {
if (this.params.containsKey(name)) {
return this.params.get(name)[0];
}
return "";
}
#Override
public Map<String, String[]> getParameterMap() {
return this.params;
}
#Override
public Enumeration<String> getParameterNames() {
return new Enumerator<>(params.keySet());
}
#Override
public String[] getParameterValues(String name) {
return params.get(name);
}
}
Here is the repo with the integration test

Categories