How to configure Spring OpenAPI UI behind Kong - spring-boot

I have a Spring Boot application and I'm using Kong as an API Gateway.
I would like to document my app's REST API with SpringDoc OpenAPI.
Everything works great locally, when I run my Spring Boot app as a standalone, but I'm facing a problem when accessing the Swagger/OpenAPI UI behind Kong.
This is my kong.yml:
services:
- name: foo
url: http://localhost:9000/foo
routes:
- name: foo-route
paths:
- /local/api/foo
methods:
- GET
- POST
- PUT
- OPTIONS
- DELETE
- PATCH
- HEAD
Assume that kong is on port 8000, and my Spring App is on port 9000.
When I hit Kong at http://localhost:8000/local/api/foo/swagger-ui.html, I get redirected to http://localhost:8000/foo/swagger-ui/index.html?configUrl=/foo/v3/api-docs/swagger-config, which is the wrong path.
How can I fix this issue?

Found a solution!
On the Spring Boot side, since I'm using a version higher than 2.2, all is needed is the following bean:
#Bean
ForwardedHeaderFilter forwardedHeaderFilter() {
return new ForwardedHeaderFilter();
}
and this configuration:
server:
forward-headers-strategy: framework
On the Kong side, since I'm using an outdated version (2.0.3), I need to add the following plugin to my kong.yml configuration file:
plugins:
- name: request-transformer
service: foo
config:
add:
headers:
- x-forwarded-prefix:/local/api/foo
from my understanding, this is not needed in newer Kong versions: as long as the host has a trusted ip, the header x-forwarded-prefix will be added automatically.

Related

How to use SetPath with query strings in Spring Cloud Gateway

I am using Spring Cloud Gateway and I am trying to remap a url to another one (using the SetPath filter) that uses a query string (involves a ?).
Consider the Spring Cloud Gateway config YAML below:
spring:
cloud:
gateway:
routes:
- id: demoEndpoint
uri: lb://demo-service
predicates:
- Path=/api/v1/user/{userId}/items
filters:
- SetPath=/items?searchUser={userId}
When I do a GET request on the endpoint (/api/v1/user/testUserId/items), Spring Cloud Gateway maps the request to: lb://demo-service/items but what I expected to get is lb://demo-service/items?searchUser=testUserId
It appears that Gateway has some issue when a question mark is involved in the path.
Question
How do I use query string in SetPath? Do I need to escape the ? character? Or is this a bug in Spring Cloud Gateway?
Other Info
I have tried this other config:
spring:
cloud:
gateway:
routes:
- id: demoEndpoint
uri: lb://demo-service
predicates:
- Path=/api/v1/user/{userId}/items
filters:
- SetPath=/items/searchUser={userId}
When I do a GET request on the endpoint (/api/v1/user/testUserId/items), Spring Cloud Gateway maps the request to: lb://demo-service/items/searchUser=testUserId
This helps me confirm that setPath is finding the uri segments properly (userId) and that only usage of the question mark might be causing issues.
Spring Cloud version: 2021.0.1
Spring Cloud Gateway version: 3.1.1

Equivalent of mod_proxy_html for Spring Cloud Gateway

I'm using Spring Cloud Gateway as a reverse proxy. Behind that proxy I have an Angular Web App the code of which I can't modify.
The problem is that the webapp uses relative hyperlinks so when accessing the proxied web app by URL http://localhost:8080/webapp/ the app omits the webapp part in it's hyperlinks and the hyperlinks look like http://localhost:8080/destination/ instead of http://localhost:8080/webapp/destination.Apache Httpd has module for it called mod_proxy_html that rewrites the paths in HTML content served by the proxy. Is there something similar in Spring Cloud Gateway or maybe one should use reverse proxy functionality only for REST APIs?
try:
application.yml
spring:
cloud:
gateway:
routes:
- id: rewritepath_route
uri: http://localhost:8080
predicates:
- Path=/destination
filters:
- RewritePath=/(?<segment>/?.*), /webapp/$\{segment}
https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-rewritepath-gatewayfilter-factory

How to register non Spring Boot MicroService in Eureka discovery server

I have recently installed a micro service infrastraucture based on Spring Boot + Spring Cloud.
My Spring Boot microservices register in my Eureka server and Zuul automaticaly redirects requests to them.
I have a Drupal content manager that exposes content through REST interface and I'd like it to take part in the discovery rave party. How can I have my drupal register it self in the Eureka server so Zuul redirects the corresponding calls to it?
As an ugly workaround I wonder if I can have automatic discovery and routing running in Zuul while manually configuring some REST paths to be redirected to the drupal server? (Using zuul.routes... property files)
I found that I can add manual zuul routes in bootstrap.yaml
I have tried adding it in the application yaml property files in configuration server but for some reason they are ignored when the Eureka discovery server is working.
Anyway, bootstrap.yaml works. Example:
zuul:
routes:
mta_api:
path: /mta_api/**
url: http://my-non-springboot-rest-service.com/
stripPrefix: false
You could add sidecar to your non-springboot application. This would allow Eureka support.
Source: Dead- http://cloud.spring.io/spring-cloud-static/Edgware.SR4/single/spring-cloud.html#_polyglot_support_with_sidecar
Current: https://cloud.spring.io/spring-cloud-static/Dalston.SR5/multi/multi__polyglot_support_with_sidecar.html

Spring Cloud Gateway in CloudFoundry

I've been trying to get my apps to run after deploing them to a CloudFoundry instance. The instance I'm using will not allow to perform requests using http (they will simply timeout) so I have to route all requests to https.
The components/versions I am using are:
Java 10
Spring Boot 2.0.4.RELEASE/Spring Cloud Finchley.SR1
spring-cloud-gateway
spring-cloud-config-server
spring-cloud-starter-netflix-eureka
The failing config
EurekaClient Config (in gateway and the backend where the gw should route to)
eureka:
client:
serviceUrl:
defaultZone: ${DISCOVERY_SERVICE_URL:http://localhost:8061}/eureka/
instance:
hostname: ${vcap.application.uris[0]:localhost}
nonSecurePortEnabled: false
securePortEnabled: true
securePort: ${server.port}
statusPageUrl: https://${eureka.instance.hostname}/actuator/info
healthCheckUrl: https://${eureka.instance.hostname}/actuator/health
homePageUrl: https://${eureka.instance.hostname}/
secure-virtual-host-name: https://${vcap.application.application_uris[0]}
Gateway Config
spring:
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/user/**
filters:
- RewritePath=/user/(?<segment>.*), /$\{segment}
Things I have already tried:
Using lb:https://user-service like described in docs -> Will have no effect as far as I can see
Use real urls to the apps (uri: https://user-service.cf-instance.io) -> Routing works as expected.
But I do not want to define the urls in my config, they should returned by eureka and build up correctly by the gateway.
Thanks in advance
Edit:
Here is the output of /eureka/apps
https://pastebin.com/WP3b6PQG
I am currently working to get the current code into GitHub I will edit this post when I've found the time to get a clear state.
Edit 2:
You can find the full example (With SpringCloudGateway, Eureka, ...) at my GitHub
This is an running example, the applied config will not use the Eureka. To use Eureka the gateway-service-cloud.yml in config service has to be adopted.
- id: user-service
uri: lb://user-service
Please ignore the documentation service, this will not work yet, I first need to rewrite the path.
Ok, I found out the solution during fixing the "routing" problem with my documentation-service.
My problem was setting the property eureka.instance.securePort to ${server.port}. This property has to be set to 443 (the default 443 is not applied when nothing is set). When adding this to my configurations everything works as expected after pushing my application.

How do I configure the spring boot quickstart for keycloak?

I am trying to set up a basic example spring boot site which uses keycloak for security. I have done the following
cloned and ran (gradlew bootRun) the 'complete' example from https://spring.io/guides/gs/serving-web-content/ (https://github.com/spring-guides/gs-serving-web-content.git) to verify that it works
added the following to the project's gradle dependencies:
compile("org.keycloak:keycloak-spring-boot-adapter:2.2.1.Final")
compile("org.keycloak:keycloak-tomcat8-adapter:2.2.1.Final")
put the following in config/application.yml:
spring:
profiles: default
server.port: 8090
keycloak:
securityConstraints:
- securityCollections:
- name: application section
authRoles:
- user
patterns:
- /
realm: stl
realmKey: MIIBIjANBgkqh[etc...]
auth-server-url: http://localhost:8280/auth
ssl-required: none
resource: example-ui
credentials:
secret: a117[etc...]
With these steps, I believe I've followed all the directions in https://keycloak.gitbooks.io/securing-client-applications-guide/content/v/2.2/topics/oidc/java/spring-boot-adapter.html. But now when I attempt to browse to the application, I get an error. This is what's logged to the console: No login page was defined for FORM authentication in context []
What am I missing to complete configuration of this app? From prior experience with earlier versions of other keycloak adapters, I would expect to have to specify an auth method of KEYCLOAK somewhere, but I don't know where that would go in spring boot, if indeed it goes anywhere.
Same problem here but it's only when I upgraded from Spring boot 1.4.0 to 1.4.1.
They have passed version of tomcat to 8.5.4 to 8.5.5. And every request except GET are working, only GET don't work with the message "No login page was defined for FORM authentication in context []" like you said.
Downgrading the version of tomcat did the trick for me :
<tomcat.version>8.5.4</tomcat.version>
Can someone know what's going on ?

Resources