Search code examples
javageoserver

Configuring Geoserver to work on an Azure app service


I have an Azure app service (Tomcat 9.0 & Java 11) configured with AD authentication and I have deployed the Geoserver 2.18 WAR onto it.

When I try to access geoserver I get the home page ok but when I try to login with the default geoserver credentials I get a stacktrace:

java.lang.IllegalArgumentException: Failed to parse address1.2.3.4, 5.6.7.8, 9.10.11.12
    org.springframework.security.web.util.matcher.IpAddressMatcher.parseAddress(IpAddressMatcher.java:107)
    org.springframework.security.web.util.matcher.IpAddressMatcher.matches(IpAddressMatcher.java:66)
    org.springframework.security.web.util.matcher.IpAddressMatcher.matches(IpAddressMatcher.java:62)
    org.geoserver.security.BruteForceListener.lambda$requestAddressInWhiteList$0(BruteForceListener.java:126)
    java.base/java.util.stream.MatchOps$1MatchSink.accept(Unknown Source)
    java.base/java.util.ArrayList$ArrayListSpliterator.tryAdvance(Unknown Source)
    java.base/java.util.stream.ReferencePipeline.forEachWithCancel(Unknown Source)
    java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(Unknown Source)
    java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source)
    java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
    java.base/java.util.stream.MatchOps$MatchOp.evaluateSequential(Unknown Source)
    java.base/java.util.stream.MatchOps$MatchOp.evaluateSequential(Unknown Source)
    java.base/java.util.stream.AbstractPipeline.evaluate(Unknown Source)
    java.base/java.util.stream.ReferencePipeline.anyMatch(Unknown Source)
    org.geoserver.security.BruteForceListener.requestAddressInWhiteList(BruteForceListener.java:126)
    org.geoserver.security.BruteForceListener.onApplicationEvent(BruteForceListener.java:65)
    org.geoserver.security.BruteForceListener.onApplicationEvent(BruteForceListener.java:28)
org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
    org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
    org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
    org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:403)
    org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:360)
    org.springframework.security.authentication.DefaultAuthenticationEventPublisher.publishAuthenticationSuccess(DefaultAuthenticationEventPublisher.java:99)
    org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:224)
    org.geoserver.security.GeoServerSecurityManager$1.authenticate(GeoServerSecurityManager.java:315)
    org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94)
    org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
    org.geoserver.security.filter.GeoServerCompositeFilter$NestedFilterChain.doFilter(GeoServerCompositeFilter.java:74)
    org.geoserver.security.filter.GeoServerCompositeFilter.doFilter(GeoServerCompositeFilter.java:91)
    org.geoserver.security.filter.GeoServerUserNamePasswordAuthenticationFilter.doFilter(GeoServerUserNamePasswordAuthenticationFilter.java:122)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    org.geoserver.security.filter.GeoServerCompositeFilter$NestedFilterChain.doFilter(GeoServerCompositeFilter.java:70)
    org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
    org.geoserver.security.filter.GeoServerSecurityContextPersistenceFilter$1.doFilter(GeoServerSecurityContextPersistenceFilter.java:52)
    org.geoserver.security.filter.GeoServerCompositeFilter$NestedFilterChain.doFilter(GeoServerCompositeFilter.java:74)
    org.geoserver.security.filter.GeoServerCompositeFilter.doFilter(GeoServerCompositeFilter.java:91)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
    org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
    org.geoserver.security.GeoServerSecurityFilterChainProxy.doFilter(GeoServerSecurityFilterChainProxy.java:142)
    org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)
    org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)
    org.geoserver.filters.LoggingFilter.doFilter(LoggingFilter.java:101)
    org.geoserver.filters.XFrameOptionsFilter.doFilter(XFrameOptionsFilter.java:77)
    org.geoserver.filters.GZIPFilter.doFilter(GZIPFilter.java:47)
    org.geoserver.filters.SessionDebugFilter.doFilter(SessionDebugFilter.java:46)
    org.geoserver.filters.FlushSafeFilter.doFilter(FlushSafeFilter.java:42)
    org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    com.microsoft.azure.appservice.filters.AppServiceFilter.doFilter(AppServiceFilter.java:53)
    com.microsoft.azure.appservice.EasyAuthFilter.doFilter(EasyAuthFilter.java:42)

(I have replaced the 3 IP's in the stack trace with dummy IP's for privacy reasons)

Checking the HTTP headers that Azure's authentication proxy is sending to geoserver and the string of 3 IP's in the x-forwarded-for HTTP header matches ok.

Have I failed to configure something? Its a bit difficult to get at the geoserver security settings since I can't login!


Solution

  • OK after some deeper digging think I've found a solution. Geoserver uses IpAddressMatcher in its brute force login prevention. IpAddressMatcher expects a single IP address in the HTTP headers. Azure has multiple so this causes the issue.

    The brute force login detection can be disabled by editing $GEOSERVER_DATA_DIR/security/config.xml and near the bottom change bruteForcePrevention to false like so:

      <bruteForcePrevention>
        <enabled>false</enabled>
        <minDelaySeconds>1</minDelaySeconds>
        <maxDelaySeconds>5</maxDelaySeconds>
        <maxBlockedThreads>100</maxBlockedThreads>
        <whitelistedMasks>
          <string>127.0.0.1</string>
        </whitelistedMasks>
      </bruteForcePrevention>
    

    Restart tomcat and now geoserver works and I can login.