I'm trying to change JHipster so it uses a JSON object for authentication instead of form parameters. I've managed to make this work for its JWT authentication mechanism. Now I'd like to do it for other authentication options.
Is there an easy way to change Spring Security's default security configuration to allow this? Here's what JHipster uses now:
.and()
.rememberMe()
.rememberMeServices(rememberMeServices)
.rememberMeParameter("remember-me")
.key(env.getProperty("jhipster.security.rememberme.key"))
.and()
.formLogin()
.loginProcessingUrl("/api/authentication")
.successHandler(ajaxAuthenticationSuccessHandler)
.failureHandler(ajaxAuthenticationFailureHandler)
.usernameParameter("j_username")
.passwordParameter("j_password")
.permitAll()
I'd like to send the following as JSON instead of form parameters:
{username: "admin", password: "admin", rememberMe: true}
Either use an export mapping to create a JSON string that you can pass to the Java action and then create a JSON object again from that string or just pass a root object to the Java and then in Java retrieve all the attached objects over the references to that root object.
Our Spring application will support both JSON as well as XML. It will even support XML request with JSON response and vice versa.
Send JSON Data in POST Spring provides a straightforward way to send JSON data via POST requests. The built-in @RequestBody annotation can automatically deserialize the JSON data encapsulated in the request body into a particular model object. In general, we don't have to parse the request body ourselves.
I just needed something very similar, so I wrote it.
This uses Spring Security 4.2, WebSecurityConfigurationAdapter. There instead of using ...formLogin()...
I wrote an own Configurer that uses JSON when available and defaults to Form if not (because I need both functionalities).
I copied all things that needed to be present (but I didn't care about) from org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer
and org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
where the source code and documentation greatly helped me.
It is well possible that you will need to copy over other functions as well, but it should do in principle.
The Filter that actually parses the JSON is in the end. The code sample is one class so can be copied over directly.
/** WebSecurityConfig that allows authentication with a JSON Post request */
@Configuration
@EnableWebSecurity(debug = false)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
// resources go here
@Override
protected void configure(HttpSecurity http) throws Exception {
// here you will need to configure paths, authentication provider, etc.
// initially this was http.formLogin().loginPage...
http.apply(new JSONLoginConfigurer<HttpSecurity>()
.loginPage("/authenticate")
.successHandler(new SimpleUrlAuthenticationSuccessHandler("/dashboard"))
.permitAll());
}
/** This is the a configurer that forces the JSONAuthenticationFilter.
* based on org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer
*/
private class JSONLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractAuthenticationFilterConfigurer<H, JSONLoginConfigurer<H>, UsernamePasswordAuthenticationFilter> {
public JSONLoginConfigurer() {
super(new JSONAuthenticationFilter(), null);
}
@Override
public JSONLoginConfigurer<H> loginPage(String loginPage) {
return super.loginPage(loginPage);
}
@Override
protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) {
return new AntPathRequestMatcher(loginProcessingUrl, "POST");
}
}
/** This is the filter that actually handles the json
*/
private class JSONAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
protected String obtainPassword(JsonObject obj) {
return obj.getString(getPasswordParameter());
}
protected String obtainUsername(JsonObject obj) {
return obj.getString(getUsernameParameter());
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
if (!"application/json".equals(request.getContentType())) {
// be aware that objtainPassword and Username in UsernamePasswordAuthenticationFilter
// have a different method signature
return super.attemptAuthentication(request, response);
}
try (BufferedReader reader = request.getReader()) {
//json transformation using javax.json.Json
JsonObject obj = Json.createReader(reader).readObject();
String username = obtainUsername(obj);
String password = obtainPassword(obj);
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
username, password);
return this.getAuthenticationManager().authenticate(authRequest);
} catch (IOException ex) {
throw new AuthenticationServiceException("Parsing Request failed", ex);
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With