I have a problem very similar to this one: Redirect Post method HTTP -> HTTPS - HTTP Status 405 (Spring boot)
Basically, I'm trying to make Spring Boot serve both HTTP and HTTPS with the redirection from HTTP to HTTPS. It works, but only for GET requests. If I perform PUT request, I get "Request method 'GET' not supported" error, so looks like my PUT request is being converted to GET request somewhere somehow.
I tried both ways of configuring such redirect: define HTTPS connectivity in application.properties
and then add HTTP programmatically and vise versa. Neither is working.
Here's the first approach:
@Bean
public EmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory() {
@Override
protected void postProcessContext(Context context) {
SecurityConstraint securityConstraint = new SecurityConstraint();
securityConstraint.setUserConstraint("CONFIDENTIAL");
SecurityCollection collection = new SecurityCollection();
collection.addPattern("/*");
securityConstraint.addCollection(collection);
context.addConstraint(securityConstraint);
}
};
addHTTPConnector(factory);
return factory;
}
private void addHTTPConnector(TomcatEmbeddedServletContainerFactory factory) {
Connector connector = new Connector(TomcatEmbeddedServletContainerFactory.DEFAULT_PROTOCOL);
connector.setScheme("http");
connector.setPort(8080);
connector.setRedirectPort(8443);
connector.setSecure(false);
Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
protocol.setSSLEnabled(false);
factory.addAdditionalTomcatConnectors(connector);
}
With application.properties
:
server.port=8443
server.ssl.key-store=keystore.p12
server.ssl.key-store-password=password
server.ssl.keyStoreType=PKCS12
server.ssl.keyAlias=alias
Here's the second approach:
@Bean
public EmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory() {
@Override
protected void postProcessContext(Context context) {
SecurityConstraint securityConstraint = new SecurityConstraint();
securityConstraint.setUserConstraint("CONFIDENTIAL");
SecurityCollection collection = new SecurityCollection();
collection.addPattern("/*");
securityConstraint.addCollection(collection);
context.addConstraint(securityConstraint);
}
};
addHTTPSConnector(factory);
factory.addConnectorCustomizers((TomcatConnectorCustomizer) connector -> connector.setRedirectPort(8443));
return factory;
}
private void addHTTPSConnector(TomcatEmbeddedServletContainerFactory factory) {
Connector connector = new Connector(TomcatEmbeddedServletContainerFactory.DEFAULT_PROTOCOL);
connector.setScheme("https");
connector.setPort(8443);
connector.setSecure(true);
Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
protocol.setSSLEnabled(true);
protocol.setKeystoreFile("keystore.p12");
protocol.setKeystorePass("password");
protocol.setKeystoreType("pkcs12");
protocol.setKeystoreProvider("SunJSSE");
protocol.setKeyAlias("alias");
factory.addAdditionalTomcatConnectors(connector);
}
For both I also have
@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requiresChannel().anyRequest().requiresSecure();
}
}
in order to make redirect work.
I have also seen this answer: Spring Boot "Request method 'GET' not supported" while redirecting POST request to https port through Catalina Connector
But I don't know what is "DEFAULT_PROTOCOL" constant. I tried adding all the methods there (POST, PUT, DELETE, GET, etc.), but it didn't help.
If you don't need to use WebDAV, then the easiest and the best way to fix "405 method not allowed" issue is to remove WebDAV from your system. You can easily get this done in "Turn Windows Features On or Off" simply un-ticking the checkbox.
A redirect is specifically to inform the client (e.g. web browser) to do a GET
request using a given URL, so the result of a redirect cannot be a PUT
, POST
, DELETE
, or any other HTTP method.
In this context, the main purpose of redirecting to HTTPS is to secure the connection from snooping, i.e. ensure that no one can see confidential information. This works well for a GET
, since you haven't sent confidential information yet1, assuming it is the response that contains confidential information.
Redirecting a PUT
or a POST
to HTTPS is meaningless, since you already sent the payload (the confidential data) over an unsecure connection.
Your client needs to be told to use HTTPS before it sends the data, i.e. when it builds the PUT
/ POST
request, it needs to be given an HTTPS URL.
Fix the client code, e.g. the JavaScript code that generates the HTTP PUT
, so it uses HTTPS. Redirecting is too late, and entirely wrong.
It is actually a good thing that redirect of PUT
failed, because it forces you to correctly secure your web application. If it hadn't failed, you'd mistakenly have thought that you web application was secured by the redirect, when in fact it wasn't.
1) The GET
can contain confidential information too, e.g. in the query string. If it does, it should never have been sent using HTTP, so rules for securing PUT
/ POST
also applies to GET
in such cases.
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