The AJP Connector is configured with secretRequired="true" but the secret attribute is either null or "" after upgrade to 2.2.5
Asked Answered
E

5

61

Caused by: java.lang.IllegalArgumentException: The AJP Connector is configured with secretRequired="true" but the secret attribute is either null or "". This combination is not valid.
at org.apache.coyote.ajp.AbstractAjpProtocol.start(AbstractAjpProtocol.java:264)
at org.apache.catalina.connector.Connector.startInternal(Connector.java:1035) ... 22 common frames omitted

I am seeing the above errors after upgrading Spring Boot from 2.1.9 to 2.2.5. The upgrade was necessary to overcome a Ghostcat vulnerability by upgrading Tomcat version to 9.0.31, which is being bundled with the latest Spring Boot 2.2.5.

Englert answered 3/3, 2020 at 6:44 Comment(2)
I am aware of the below but is there a another way to fix ? dev.lucee.org/t/tomcat-cve-2020-1938-ghostcat-ajp/6650/2Englert
github.com/spring-projects/spring-boot/issues/20377Englert
B
16

Here is one solution, though probably not the best one, but my focus was not this, just to pass through the error, I was enabling AJP on Spring Boot 2.2.5.RELEASE version. Add this:

((AbstractAjpProtocol) ajpConnector.getProtocolHandler()).setSecretRequired(false);

My full class for AJP configuration:

package com.ssldemo.config;

import org.apache.catalina.connector.Connector;
import org.apache.coyote.ajp.AbstractAjpProtocol;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class TomcatConfiguration {

    @Value("${tomcat.ajp.port}")
    int ajpPort;

    @Value("${tomcat.ajp.remoteauthentication}")
    String remoteAuthentication;

    @Value("${tomcat.ajp.enabled}")
    boolean tomcatAjpEnabled;

    @Bean
    public TomcatServletWebServerFactory servletContainer() {

        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
        if (tomcatAjpEnabled) {
            Connector ajpConnector = new Connector("AJP/1.3");
            ajpConnector.setPort(ajpPort);
            ajpConnector.setSecure(false);
            ajpConnector.setAllowTrace(false);
            ajpConnector.setScheme("http");
            ((AbstractAjpProtocol) ajpConnector.getProtocolHandler()).setSecretRequired(false);
            tomcat.addAdditionalTomcatConnectors(ajpConnector);
        }

        return tomcat;
    }

}

application.properties

server.port=8082
tomcat.ajp.port=9090
tomcat.ajp.remoteauthentication=false
tomcat.ajp.enabled=true
Boysenberry answered 3/3, 2020 at 8:40 Comment(3)
Worked for me with Spring Boot 2.2.6! Nice solution.Schach
It's worth pointing out that above configuration reintroduce Ghostcat vulnerability which has been fixed by configuring AJP connector to secretRequired="true" by default! Secure configuration can be found e.g. access.redhat.com/solutions/4851251Pyre
In case anyone else hits this problem you'll likely also get an error message along the lines of: The Tomcat connector configured to listen on port 11001 failed to start. The port may already be in use or the connector may be misconfigured. This is a lie, the port isn't bound and no amount of looking with netstat or rebooting will find anything.Immunochemistry
D
70

Navigate to the server.xml in tomcat:

Replace AJP with:

<Connector protocol="AJP/1.3" address="::1" port="8009"
           redirectPort="8443" secretRequired="false" />

But make sure that you understand the security implications of that (see Krzysztof Skrzynecki's answer for that).

Dace answered 7/4, 2020 at 13:55 Comment(0)
P
31

Using secretRequired="false" reintroduces Ghostcat breach what has been explained e.g. here:

This is a configuration issue with AJP protocol in Tomcat/Undertow. AJP is a highly trusted protocol and should never be exposed to untrusted clients. It is insecure (clear text transmission) and assumes that your network is safe. The preventive measures should be taken by using the configuration that will not allow AJP to be exposed.

In order of preference, one of the following mitigations should be applied:

  • ...
  • Protect the AJP connection with a secret, as well as carefully reviewing network binding and firewall configuration to ensure incoming connections are only allowed from trusted hosts.
  • ...

And here how secure configuration should look like:

@Configuration
public class TomcatConfig {


  @Bean
  public TomcatServletWebServerFactory servletContainer() {
      TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
      Connector ajpConnector = new Connector("org.apache.coyote.ajp.AjpNioProtocol");
      AjpNioProtocol protocol= (AjpNioProtocol)ajpConnector.getProtocolHandler();
      protocol.setSecret("myapjsecret");
      ajpConnector.setPort(9090);
      ajpConnector.setSecure(true);
      tomcat.addAdditionalTomcatConnectors(ajpConnector);
      return tomcat;
  }
}
Pyre answered 24/4, 2020 at 12:41 Comment(7)
If Tomcat runs behind mod_proxy_ajp, setting a secret might not be supported by Apache HTTP server. See serverfault.com/a/1004617/33719.Enrollee
@Enrollee you're right, but it means that your set up is vulnerable to Ghostcat exploit and an upgrade of Apache HTTP server is requiredPyre
Correct. From what I understand, this is a problem if the AJP Connector is bound to 0.0.0.0 and this is not necessary in a reverse proxy setup. If Apache HTTP and Tomcat are running on the same host, it is best to bind Tomcat to 127.0.0.1 explicitly.Enrollee
@Enrollee you're right! Ghostcat is the problem only if AJP port can be accessed from external network. Checked RedHat solution I posted in the answer and the 3rd solution I didn't include in my answer is "Use only network binding and firewall configuration to ensure incoming connections are only allowed from trusted hosts." - so exactly what you suggest.Pyre
Followed all and still geting "403 The server understood the request but refuses to authorize it." The connector is properly configured. On my virtual host for Apache do I need to put the secret on the two lines below, and be explicit for the IP? ProxyPass / ajp://localhost:9009/ ProxyPassReverse / ajp://localhost.net:9009/ timeout=600Qualified
yes, secret need to be added at the end of a line, e.g. ProxyPass / ajp://localhost:9009/ secret=myapjsecretPyre
Moreover, you need Apache 2.5 or above - here is related documentation httpd.apache.org/docs/trunk/mod/mod_proxy_ajp.htmlPyre
B
16

Here is one solution, though probably not the best one, but my focus was not this, just to pass through the error, I was enabling AJP on Spring Boot 2.2.5.RELEASE version. Add this:

((AbstractAjpProtocol) ajpConnector.getProtocolHandler()).setSecretRequired(false);

My full class for AJP configuration:

package com.ssldemo.config;

import org.apache.catalina.connector.Connector;
import org.apache.coyote.ajp.AbstractAjpProtocol;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class TomcatConfiguration {

    @Value("${tomcat.ajp.port}")
    int ajpPort;

    @Value("${tomcat.ajp.remoteauthentication}")
    String remoteAuthentication;

    @Value("${tomcat.ajp.enabled}")
    boolean tomcatAjpEnabled;

    @Bean
    public TomcatServletWebServerFactory servletContainer() {

        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
        if (tomcatAjpEnabled) {
            Connector ajpConnector = new Connector("AJP/1.3");
            ajpConnector.setPort(ajpPort);
            ajpConnector.setSecure(false);
            ajpConnector.setAllowTrace(false);
            ajpConnector.setScheme("http");
            ((AbstractAjpProtocol) ajpConnector.getProtocolHandler()).setSecretRequired(false);
            tomcat.addAdditionalTomcatConnectors(ajpConnector);
        }

        return tomcat;
    }

}

application.properties

server.port=8082
tomcat.ajp.port=9090
tomcat.ajp.remoteauthentication=false
tomcat.ajp.enabled=true
Boysenberry answered 3/3, 2020 at 8:40 Comment(3)
Worked for me with Spring Boot 2.2.6! Nice solution.Schach
It's worth pointing out that above configuration reintroduce Ghostcat vulnerability which has been fixed by configuring AJP connector to secretRequired="true" by default! Secure configuration can be found e.g. access.redhat.com/solutions/4851251Pyre
In case anyone else hits this problem you'll likely also get an error message along the lines of: The Tomcat connector configured to listen on port 11001 failed to start. The port may already be in use or the connector may be misconfigured. This is a lie, the port isn't bound and no amount of looking with netstat or rebooting will find anything.Immunochemistry
H
2

Old, file conf/server.xml

<Connector protocol="AJP/1.3" address="::1" port="8089" redirectPort="8443">

New, file conf/server.xml

<Connector protocol="AJP/1.3" address="::1" port="8089" redirectPort="8443" secretRequired="false">
Heldentenor answered 30/3, 2022 at 4:57 Comment(0)
C
0

Should be:

redirectPort="8443" />

secretRequired="false" />

Camber answered 21/4, 2022 at 7:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.