javaspringrestspring-security-oauth2spring-oauth2

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

  • 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
        }
    
        ...
    
    }