I have a web application which has 5 REST APIs. All the APIs are HTTPS with SSL enabled. This is connector tag in server.xml:
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
keystoreFile="conf/jks/ketStore.jks" keystorePass="keystore" keystoreType="jks"
truststoreFile="conf/jks/trustStore.jks" truststorePass="truststore" truststoreType="jks"
clientAuth="true" sslProtocol="TLSv1.2"/>
Now I have to make only one of the APIs to be exposed over HTTPs with onw-way SSL. The other 4 APIs should be accessible only over HTTPS with 2-way SSL certificates.
What is the best way in approaching this problem with Spring boot and Spring 4 Security.
Update
I have progressed a bit on this. I have set clientAuth="want"
and able to access the required API without presenting a certificate at client side. But I am not sure on the way to enforce 2-way for other APIs and write a custom filter to check SSL handshake. Is there a way to do this in Spring Security.
I have the below MultiHttpSecurityConfig
class:
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MultiHttpSecurityConfig {
private static final Logger LOG = LoggerFactory
.getLogger(MultiHttpSecurityConfig.class);
@Configuration
@Order(1)
public static class SecureApiConfigurationAdapter extends
WebSecurityConfigurerAdapter {
@Autowired
private HttpAuthEntryPoint httpAuthEntryPoint;
@Autowired
private X509UserDetSer x509UserUserDetSer;
protected void configure(
final HttpSecurity http)
throws Exception {
LOG.debug("/SSL2waysecureAPI/");
http.csrf().disable()
.antMatcher("/SSL2waysecureAPI/**")
.x509()
.subjectPrincipalRegex("CN=(.*?),")
// .subjectPrincipalRegex(".*")
.authenticationUserDetailsService(x509UserUserDetSer)
.and().exceptionHandling()
.authenticationEntryPoint(httpAuthEntryPoint)
.and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
The new connector tag in Tomcat is like below:
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
keystoreFile="conf/jks/ketStore.jks" keystorePass="keystore" keystoreType="jks"
truststoreFile="conf/jks/trustStore.jks" truststorePass="truststore" truststoreType="jks"
clientAuth="want" sslProtocol="TLSv1.2"/>
So if someone needs it - I did something like this in this way
First of all - server.xml config file
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
keystoreFile="conf/jks/ketStore.jks" keystorePass="keystore" keystoreType="jks"
truststoreFile="conf/jks/trustStore.jks" truststorePass="truststore" truststoreType="jks"
clientAuth="want" sslProtocol="TLSv1.2"/>
Then web.xml :
<filter>
<filter-name>ServletFilter</filter-name>
<filter-class>securechat.filter.ServletFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>ServletFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
After that, any request to any endpoint will be hooked to this filter. Inside of it you can manually check any request.something like
@Component
public class ServletFilter implements Filter {
public static final String X_CLACKS_OVERHEAD = "X-Clacks-Overhead";
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
X509Certificate[] certificates = (X509Certificate[]) req
.getAttribute("javax.servlet.request.X509Certificate");
String servletPath = null;
int port = -1;
if (req instanceof HttpServletRequest) {
servletPath = ((HttpServletRequest)req).getServletPath();
port = ((HttpServletRequest)req).getServerPort();
System.out.println("getServletPath = " + ((HttpServletRequest)req).getServletPath() );
System.out.println(" ((HttpServletRequest)req).getServerPort() = " + ((HttpServletRequest)req).getServerPort());
//Just in memory of....
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader(X_CLACKS_OVERHEAD, "GNU Terry Pratchett");
//Here you can do checking for port and destination.
if(port == 8080 && !servletPath.equals("/notSecureDest/something")
//log error - we try to enter secured enpoint bu non-secured port and url
return; // we decline request
}else if(port == ??? && ???? ) {
//if all checkings age good - we do
chain.doFilter(req, res);
}
}
Hope that helps.
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