简体   繁体   中英

Authenticating on each API call

I currently have a Spring service that is authenticated through a login page. The desire now is to have a way to authenticate the user for each API request using a client certificate and private key. I created a POST request to an external endpoint that I am using to authenticate the user. I was able to authenticate a user in an authentication filter, but then it displays a 405 error.

public class AuthenticationFilter extends GenericFilterBean {

    private AuthenticationManager authenticationManager;

    public AuthenticationFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest http_request = (HttpServletRequest) request;
        HttpServletResponse http_response = (HttpServletResponse) response;

        String cert_filename = "certificate.pem";
        File cert_file = new File(cert_filename);

        if(cert_file.createNewFile())
            System.out.println("Successfully created private cert file");
        else
            System.out.println("Cert file could not be created");

        BufferedWriter cert_writer = new BufferedWriter(new FileWriter(cert_filename));
        cert_writer.write(cert);
        cert_writer.close();

        String key_filename = "private_key.key";
        File key_file = new File(key_filename);

        if(key_file.createNewFile())
            System.out.println("Successfully created private key file");
        else
            System.out.println("Key file could not be created");

        BufferedWriter key_writer = new BufferedWriter(new FileWriter(key_filename));
        key_writer.write(key);
        key_writer.close();

        ProcessBuilder processBuilder = new ProcessBuilder();
        processBuilder.redirectErrorStream(true);
        processBuilder.command("curl", ..., ...);
        Process process = processBuilder.start();
        BufferedReader reader =
                new BufferedReader(new InputStreamReader(process.getInputStream()));
        StringBuilder builder = new StringBuilder();
        String line;
        while ( (line = reader.readLine()) != null) {
            builder.append(line);
            builder.append(System.getProperty("line.separator"));
        }
        String result = builder.toString();

        System.out.println(result);
        if(result.contains("\"successful\": true")) {
            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("user", "password");
            Authentication auth = authenticationManager.authenticate(token);
            SecurityContextHolder.getContext().setAuthentication(auth);
//            TokenResponse tokenResponse = new TokenResponse(auth.getDetails().toString());
//            String tokenJsonResponse = new ObjectMapper().writeValueAsString(tokenResponse);
            http_response.setStatus(HttpServletResponse.SC_OK);
            //http_response.sendError(HttpServletResponse.SC_OK);
//            http_response.addHeader("Content-Type", "application/json");
//            http_response.getWriter().print(tokenJsonResponse);
            chain.doFilter(request, response);
        }
        else{
            http_response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            http_response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
        }

    }
}


@EnableWebSecurity
@Order(1000)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    RestAuthenticationEntryPoint restAuthenticationEntryPoint;

    String[] permitted  =  {
            "/login",
            ...
    };

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("user")
                .password("{noop}password")
                .roles("USER");

    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint)
                .and()
                .authorizeRequests()
                .antMatchers(permitted).permitAll()
                .anyRequest().authenticated()
                .and()
                .oauth2Login()
                .loginPage("/login")
                .defaultSuccessUrl("/swagger-ui.html", true)
                .and()
                .logout()
                .clearAuthentication(true)
                .logoutUrl("/logout")
                .logoutSuccessUrl("/login").permitAll()
                .deleteCookies("JSESSIONID")
                .invalidateHttpSession(true);
        http.addFilterAfter(new AuthenticationFilter(authenticationManager()), BasicAuthenticationFilter.class);
    }


}

The desire now is to have a way to authenticate the user for each API request using a client certificate and private key

Apparently you are missing some very basic principles how client authentication over ssl works. The idea is that the client has its keypair (private and public key) and a certificate which need to be signed by a trusted certificate authority .

For the testing purpose you may use a self-signed certificate, just it needs to be trusted (in a truststore), see a blog link bellow.

The authentication will take place on the channel (https) level and the client information (certificate dn,..) are passed by the engine as headers or request context

You may have a look at following blog: X.509 Authentication in Spring Security

I would normally copy the relevant information from an external resource into the answer, but in this case, I would be copying the entire post.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM