Jacuo
Jacuo

Reputation: 21

Spring cloud, Zuul https

I have problem with https services in my Gateway application ( which uses zuul ) it works great when proxying http services, but i have problems with proxying https services I have exception

java.lang.IllegalStateException: Could not create URI object: Expected scheme-specific part at index 6: https:
           at org.springframework.web.util.HierarchicalUriComponents.toUri(HierarchicalUriComponents.java:430) ~[spring-web-4.2.6.RELEASE.jar:4.2.6.RELEASE]
           at org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration$OverrideRestClient.reconstructURIWithServer(RibbonClientConfiguration.java:184) ~[spring-cloud-netflix-core-1
           at com.netflix.client.AbstractLoadBalancerAwareClient$1.call(AbstractLoadBalancerAwareClient.java:106) ~[ribbon-loadbalancer-2.1.5.jar:2.1.5]
           at com.netflix.loadbalancer.reactive.LoadBalancerCommand$3$1.call(LoadBalancerCommand.java:303) ~[ribbon-loadbalancer-2.1.5.jar:2.1.5]
           at com.netflix.loadbalancer.reactive.LoadBalancerCommand$3$1.call(LoadBalancerCommand.java:287) ~[ribbon-loadbalancer-2.1.5.jar:2.1.5]
           at rx.internal.util.ScalarSynchronousObservable$4.call(ScalarSynchronousObservable.java:223) ~[rxjava-1.1.5.jar:1.1.5]
           at rx.internal.util.ScalarSynchronousObservable$4.call(ScalarSynchronousObservable.java:220) ~[rxjava-1.1.5.jar:1.1.5]
           at rx.Observable.unsafeSubscribe(Observable.java:8460) ~[rxjava-1.1.5.jar:1.1.5]
           ... 150 common frames omitted
    aused by: java.net.URISyntaxException: Expected scheme-specific part at index 6: https:
           at java.net.URI$Parser.fail(URI.java:2848) ~[na:1.8.0_92]
           at java.net.URI$Parser.failExpecting(URI.java:2854) ~[na:1.8.0_92]
           at java.net.URI$Parser.parse(URI.java:3057) ~[na:1.8.0_92]
           at java.net.URI.<init>(URI.java:673) ~[na:1.8.0_92]

My Gateway config

server:
  ssl:
    key-store: classpath:my.jks
    key-store-password: secret
    key-password: secret 
spring:
  application:
    name: mille-gateway
  cloud:
    config:
      discovery:
        enabled: true
        serviceId: mille-config-server
eureka:
  client:
    healthcheck:
      enabled: true
ribbon:
  IsSecure: true
zuul:
  ignoredServices: '*'
  routes:
     test:
      path: /test/**
      serviceId: mille-test2

test:
  ribbon:      
    ReadTimeout: 5000
    MaxAutoRetries: 2
    IsSecure: true
My Registry ( Eureka ) server
server:
port: 8761

eureka:

 instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
  server:
    enableSelfPreservation: false

My client configuration

spring:
  application:
    name: mille-test2
  cloud:
    config:
      discovery:
        enabled: true
        serviceId: mille-config-server
eureka:
  client:
    healthcheck:
      enabled: true  
server:
  port: 50000
  ssl:
    key-store: classpath:my.jks
    key-store-password: secret
    key-password: secret 

eureka:
  client:
    enabled: true
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
  instance:
    nonSecurePortEnabled: false
    securePortEnabled: true
    securePort: ${server.port}    
    instanceId: ${spring.application.name}:${spring.application.instance_id:${random.value}}
    statusPageUrl: https://${eureka.hostname}:${server.port}/info
    healthCheckUrl: https://${eureka.hostname}:${server.port}/health
    homePageUrl: https://${eureka.instance.hostname}:${server.port}/
    secureVirtualHostName: ${spring.application.name}
    metadataMap:
       hostname: ${eureka.instance.hostname}
       securePort: ${server.port}  

What could be a problem ?

Upvotes: 2

Views: 4381

Answers (2)

Bryan
Bryan

Reputation: 11

I have traced this problem in the debugger in Brixton.SR6.

  • The FeignLoadBalancer.reconstructURIWithServer(...) calls RibbonUtils.updateToHttpsIfNeeded(...) before calling the superclass method that actually adds the server to the uri.
  • The uri passed in is "", which is the normal case when the incoming url matches the zuul mapping exactly and using service discovery to get the server/port.
  • updateToHttpsIfNeeded() adds "https" and calls UriComponentsBuilder via build(true) to create an instance of HierarchicalUriComponents.
  • It then calls toUri() on that instance, which, because of the true passed in to build(), follows the encode == true path and calls new URI(toString()) (line 415). That toString() returns "https:" since we have set the scheme, but not the server or port.
  • The URI does not like that at all and throws java.net.URISyntaxException: Expected scheme-specific part at index 6: https:.

As to solving the problem, perhaps FeignLoadBalancer should not ensure https until after the server and port are set in the URI? Or perhaps RibbonUtils.updateToHttpsIfNeeded should set the server and port in the UriComponentsBuilder before calling toUri() - it has the Server instance.

This accounts for why it only happens for secure connections. I have not yet found any workaround when using exact url matches in the mapping, other than reverting to Brixton.SR5, which works fine, because the call to build() does not pass the true flag, so new URI() is not called. HTH

Edit: see also spring-cloud-netflix issue 1099.

Upvotes: 1

mrmarbles
mrmarbles

Reputation: 49

Not sure if you were able to resolve this but I just ran into the same thing. It appears to only occur though when Zuul attempts to proxy a request via https (as you've indicated) to a service endpoint "root".

For instance, taking your Zuul config above - hitting the endpoint /test will likely cause that exception, however hitting any other endpoint proxied to the mille-test2 service (that isn't mapped to the root) will probably work test/something. At least it has for me. So as a temporary work around I've simply created different endpoints that extend the root such as /test/new. Kludgy, yes - but workable.

I'm curently using spring cloud Brixton.SR4.

Upvotes: 0

Related Questions