curl from pod is successful but restTemplate call is giving connection TimeOut in spring boot app - kubernetes

Hi am doing a API call from restTemplate with is giving me 404 , but after doing sh insside the service pod and doing curl I get proper response .
Here is my code
public String emailServiceCall(NotificationDto notificationDto, String url) {
UriComponentsBuilder uriBuilder = getUriComponentsBuilder(url);
log.info("email service url {}", uriBuilder.build().toUri());
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(MediaType.APPLICATION_JSON);
requestHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
requestHeaders.add(Constants.AUTHORIZATION, requestScopedStorageService.getToken());
restTemplate.setErrorHandler(new ExceptionHandler());
HttpEntity<?> requestEntity = new HttpEntity<>(notificationDto, requestHeaders);
restTemplate.exchange(uriBuilder.build().toUri(), HttpMethod.POST, requestEntity, String.class);
return "email send";
}
public UriComponentsBuilder getUriComponentsBuilder(String url) {
if (null != applicationConfig.emailServiceInstance()) {
return UriComponentsBuilder.fromHttpUrl(applicationConfig.emailServiceInstance() + url);
} else {
throw xxx.internalServerError(ExceptionMessage.EMAIL_SERVICE_NOT_AVAILABLE);
}
}
my error stack is this
org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://email-service:8080/email/sendThroughTemplateUnAuthenticated": Connect to 10.244.0.105:8088 [/10.244.0.105] failed: Connection timed out (Connection timed out); nested exception is org.apache.http.conn.HttpHostConnectException: Connect to 10.244.0.105:8088 [/10.244.0.105] failed: Connection timed out (Connection timed out)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:785)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:711)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:602)
at com.telekom.halo.utils.EmailServiceUtils.emailServiceCall(EmailServiceUtils.java:109)
at com.telekom.halo.service.impl.SupportServiceImpl.saveTicket(SupportServiceImpl.java:89)
at com.telekom.halo.service.impl.SupportServiceImpl$$FastClassBySpringCGLIB$$bf2d3425.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:779)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:692)
at com.telekom.halo.service.impl.SupportServiceImpl$$EnhancerBySpringCGLIB$$2ec2f56.saveTicket(<generated>)
at com.telekom.halo.controller.SupportController.saveTicket(SupportController.java:63)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method
Here is bootstrap.yaml
server:
port: 8088
spring:
application:
name: email-service
cloud:
consul:
host: localhost
port: 8500
discovery:
instance-id: ${spring.application.name}:${random.value}
enabled: true
register: true
health-check-interval: 20s
prefer-ip-address: true
config:
enabled: true
prefix: configuration
format: YAML
data-key: data
watch:
enabled: true
Here is kubectl get svc output
email-service NodePort 10.106.40.110
8080:32015/TCP
Thanks in advance...

Related

ContainerApp Revision Failed when using dapr

I have created containerapp environment with one containerapp using Bicep template and here is a snippet of how I configured the environment
ingress: {
external: true
targetPort: 80
allowInsecure: false
transport:'http2'
traffic:[
{
latestRevision: true
weight: 100
}
]
}
registries: [
{
server: acr_login_server
username: acr_name
passwordSecretRef: 'myregistrypassword'
}
]
dapr: {
appId: containerapp_name
appPort: 80
appProtocol: 'http'
enabled: true
}
}
I am using http2 transport cause we expose grpc service as well, then when checking the revision, it shows failed and the logs shows that there is issue with dapr
time="2022-10-19T10:35:35.391746798Z" level=fatal msg="error loading configuration: rpc error: code = Unavailable desc = connection error: desc = \"transport: authentication handshake failed: x509: certificate signed by unknown authority (possibly because of \\\"x509: ECDSA verification failure\\\" while trying to verify candidate authority certificate \\\"cluster.local\\\")\"" app_id=containerapp-a instance=containerapp-a--t1gheb2-77c44cf6c6-rxjwx scope=dapr.runtime type=log ver=1.8.4-msft-2

Failed to declare queue: springCloudBus.anonymous

I used RabbitMq in my project .In my point of view I declare all the
things required for this project. But I don't know where I miss the
thing that create error here I provide all the details that I used in
my project.
Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no queue 'springCloudBus.anonymous.9XKB94ZlSFatq7c5KyTIxw' in vhost '/', class-id=50, method-id=10)
at com.rabbitmq.client.impl.ChannelN.asyncShutdown(ChannelN.java:517) ~[amqp-client-5.12.0.jar:5.12.0]
at com.rabbitmq.client.impl.ChannelN.processAsync(ChannelN.java:341) ~[amqp-client-5.12.0.jar:5.12.0]
at com.rabbitmq.client.impl.AMQChannel.handleCompleteInboundCommand(AMQChannel.java:182) ~[amqp-client-5.12.0.jar:5.12.0]
at com.rabbitmq.client.impl.AMQChannel.handleFrame(AMQChannel.java:114) ~[amqp-client-5.12.0.jar:5.12.0]
at com.rabbitmq.client.impl.AMQConnection.readFrame(AMQConnection.java:739) ~[amqp-client-5.12.0.jar:5.12.0]
at com.rabbitmq.client.impl.AMQConnection.access$300(AMQConnection.java:47) ~[amqp-client-5.12.0.jar:5.12.0]
at com.rabbitmq.client.impl.AMQConnection$MainLoop.run(AMQConnection.java:666) ~[amqp-client-5.12.0.jar:5.12.0]
... 1 common frames omitted
bootstrap.yml
spring:
cloud:
config:
uri: http://localhost:8888
vault:
host: localhost
port: 8288
scheme: http
authentication: TOKEN
token: s.atm1jyRmex8zm7HgGjyKRB7H
application-name: product-service
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://localhost:8280/auth/realms/microservice-realm
data:
mongodb:
uri: mongodb://localhost:27017/product-service
application:
name: PRODUCT-SERVICE
management:
endpoints:
web:
exposure:
include: '*'
application.yml
spring:
data:
mongodb:
uri: mongodb://localhost:27017/product-service
application:
name: PRODUCT-SERVICE
eureka:
instance:
instance-id: ${spring.application.name}:${random.uuid}
server:
port: 0
gradlke.kt
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("org.springframework.boot") version "2.5.2"
id("io.spring.dependency-management") version "1.0.11.RELEASE"
kotlin("jvm") version "1.5.20"
kotlin("plugin.spring") version "1.5.20"
}
group = "com.main"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_11
repositories {
mavenCentral()
}
extra["springCloudVersion"] = "2020.0.3"
dependencies {
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")
implementation("org.springframework.cloud:spring-cloud-starter-vault-config:3.0.0")
implementation("org.springframework.security:spring-security-oauth2-jose:5.4.6")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.cloud:spring-cloud-starter-bus-amqp:3.0.1")
implementation("org.springframework.boot:spring-boot-starter-data-mongodb")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.springframework.cloud:spring-cloud-starter-netflix-eureka-client")
implementation("org.springframework.cloud:spring-cloud-config-client:3.0.1")
implementation("org.springframework.cloud:spring-cloud-starter-bootstrap:3.0.2")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
dependencyManagement {
imports {
mavenBom("org.springframework.cloud:spring-cloud-dependencies:${property("springCloudVersion")}")
}
}
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "11"
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
I get this type of error : Failed to declare queue:
springCloudBus.anonymous.9XKB94ZlSFatq7c5KyTIxw

Using jhipster framework to configure mongodb prompt not authorized

I used scaffolding to generate a new microservice,then I made the following configuration for mongodb:
logging:
level:
ROOT: DEBUG
io.github.jhipster: DEBUG
com.fzai.fileservice: DEBUG
eureka:
instance:
prefer-ip-address: true
client:
service-url:
defaultZone: http://admin:${jhipster.registry.password}#localhost:8761/eureka/
spring:
profiles:
active: dev
include:
- swagger
# Uncomment to activate TLS for the dev profile
#- tls
devtools:
restart:
enabled: true
additional-exclude: static/**
livereload:
enabled: false # we use Webpack dev server + BrowserSync for livereload
jackson:
serialization:
indent-output: true
data:
mongodb:
host: 42.193.124.204
port: 27017
username: admin
password: admin123
authentication-database: fileService
database: fileService
mail:
host: localhost
port: 25
username:
password:
messages:
cache-duration: PT1S # 1 second, see the ISO 8601 standard
thymeleaf:
cache: false
sleuth:
sampler:
probability: 1 # report 100% of traces
zipkin: # Use the "zipkin" Maven profile to have the Spring Cloud Zipkin dependencies
base-url: http://localhost:9411
enabled: false
locator:
discovery:
enabled: true
server:
port: 8081
# ===================================================================
# JHipster specific properties
#
# Full reference is available at: https://www.jhipster.tech/common-application-properties/
# ===================================================================
jhipster:
cache: # Cache configuration
hazelcast: # Hazelcast distributed cache
time-to-live-seconds: 3600
backup-count: 1
management-center: # Full reference is available at: http://docs.hazelcast.org/docs/management-center/3.9/manual/html/Deploying_and_Starting.html
enabled: false
update-interval: 3
url: http://localhost:8180/mancenter
# CORS is disabled by default on microservices, as you should access them through a gateway.
# If you want to enable it, please uncomment the configuration below.
cors:
allowed-origins: "*"
allowed-methods: "*"
allowed-headers: "*"
exposed-headers: "Authorization,Link,X-Total-Count"
allow-credentials: true
max-age: 1800
security:
client-authorization:
access-token-uri: http://uaa/oauth/token
token-service-id: uaa
client-id: internal
client-secret: internal
mail: # specific JHipster mail property, for standard properties see MailProperties
base-url: http://127.0.0.1:8081
metrics:
logs: # Reports metrics in the logs
enabled: false
report-frequency: 60 # in seconds
logging:
use-json-format: false # By default, logs are not in Json format
logstash: # Forward logs to logstash over a socket, used by LoggingConfiguration
enabled: false
host: localhost
port: 5000
queue-size: 512
audit-events:
retention-period: 30 # Number of days before audit events are deleted.
oauth2:
signature-verification:
public-key-endpoint-uri: http://uaa/oauth/token_key
#ttl for public keys to verify JWT tokens (in ms)
ttl: 3600000
#max. rate at which public keys will be fetched (in ms)
public-key-refresh-rate-limit: 10000
web-client-configuration:
#keep in sync with UAA configuration
client-id: web_app
secret: changeit
An error occurred while I was running the project:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mongobee' defined in class path resource [com/fzai/fileservice/config/DatabaseConfiguration.class]: Invocation of init method failed; nested exception is com.mongodb.MongoQueryException: Query failed with error code 13 and error message 'not authorized on fileService to execute command { find: "system.indexes", filter: { ns: "fileService.dbchangelog", key: { changeId: 1, author: 1 } }, limit: 1, singleBatch: true, $db: "fileService" }' on server 42.193.124.204:27017
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:847)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:744)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:391)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:312)
at com.fzai.fileservice.FileServiceApp.main(FileServiceApp.java:70)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: com.mongodb.MongoQueryException: Query failed with error code 13 and error message 'not authorized on fileService to execute command { find: "system.indexes", filter: { ns: "fileService.dbchangelog", key: { changeId: 1, author: 1 } }, limit: 1, singleBatch: true, $db: "fileService" }' on server 42.193.124.204:27017
at com.mongodb.operation.FindOperation$1.call(FindOperation.java:706)
at com.mongodb.operation.FindOperation$1.call(FindOperation.java:695)
at com.mongodb.operation.OperationHelper.withConnectionSource(OperationHelper.java:462)
at com.mongodb.operation.OperationHelper.withConnection(OperationHelper.java:406)
at com.mongodb.operation.FindOperation.execute(FindOperation.java:695)
at com.mongodb.operation.FindOperation.execute(FindOperation.java:83)
at com.mongodb.client.internal.MongoClientDelegate$DelegateOperationExecutor.execute(MongoClientDelegate.java:179)
at com.mongodb.client.internal.FindIterableImpl.first(FindIterableImpl.java:198)
at com.github.mongobee.dao.ChangeEntryIndexDao.findRequiredChangeAndAuthorIndex(ChangeEntryIndexDao.java:35)
at com.github.mongobee.dao.ChangeEntryDao.ensureChangeLogCollectionIndex(ChangeEntryDao.java:121)
at com.github.mongobee.dao.ChangeEntryDao.connectMongoDb(ChangeEntryDao.java:61)
at com.github.mongobee.Mongobee.execute(Mongobee.java:143)
at com.github.mongobee.Mongobee.afterPropertiesSet(Mongobee.java:126)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1830)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1767)
... 19 common frames omitted
But in my other simple springboot project, I used the same configuration, which can run and use successfully:
spring:
application:
name: springboot1
data:
mongodb:
host: 42.193.124.204
port: 27017
username: admin
password: admin123
authentication-database: fileService
database: fileService
This is the user and role I created:
{
"_id" : "fileService.admin",
"userId" : UUID("03f75395-f129-4273-b6a6-b2dc3d1f7974"),
"user" : "admin",
"db" : "fileService",
"roles" : [
{
"role" : "dbOwner",
"db" : "fileService"
},
{
"role" : "readWrite",
"db" : "fileService"
}
],
"mechanisms" : [
"SCRAM-SHA-1",
"SCRAM-SHA-256"
]
}
I want to know what's wrong.

TLS encrypted PostgreSQL connection not possible

I would like to establish a TLS encrypted connection to a PostgreSQL 11 database using Tokio as the framework, Deadpool as the connection pooler and rustls as TLS library.
I developed/modified the following code:
let pool = if let Some(ca_cert) = settings.db_ca_cert {
let mut tls_config = ClientConfig::new();
let cert_file = File::open(&ca_cert)?;
let mut buf = BufReader::new(cert_file);
tls_config.root_store.add_pem_file(&mut buf).map_err(|_| {
anyhow::anyhow!("failed to read database root certificate: {}", ca_cert)
})?;
let tls = MakeRustlsConnect::new(tls_config);
settings.pg.create_pool(tls)?
} else {
settings.pg.create_pool(NoTls)?
};
My test scenario is taken from here:
PostgreSQL 11 docker container (including TLS turned on)
TLS was already tested successfully with the psql client
I now get the following error message and can't explain the problem. I already checked the access rights and other parameters.
/usr/local/bin/cargo run --color=always
Finished dev [unoptimized + debuginfo] target(s) in 0.20s
Running `target/debug/tokio-postgres-rustls-connection-pool-demo`
DEBUG tokio_postgres_rustls_connection_pool_demo > settings: Settings { pg: Config { user: Some("postgres"), password: Some("postgres"), dbname: Some("postgres"), options: Some("sslrootcert=/xxx/tokio-postgres-rustls-connection-pool-demo/docker/files/cert/ca.pem"), application_name: None, ssl_mode: None, host: Some("127.0.0.1"), hosts: None, port: Some(6432), ports: None, connect_timeout: None, keepalives: None, keepalives_idle: None, target_session_attrs: None, channel_binding: None, manager: None, pool: None }, db_ca_cert: None }
Error: Backend(Error { kind: Connect, cause: Some(Os { code: 2, kind: NotFound, message: "No such file or directory" }) })
I looked at the logs of the database and could identify the following error:
[86] LOG: XX000: could not accept SSL connection: Success
[86] LOCATION: be_tls_open_server, be-secure-openssl.c:408
How can I solve the problem?

Spring OAuth2 Keycloak Kubernetes internal/external access

I have Keycloak (10.0.3) server configured inside a Kubernetes Cluster.
The keycloak server has to handle authentification for external user (using an external url) and also handle oauth2 token for Spring microservices communications.
Then web application spring services uses oidc providers :
spring:
security:
oauth2:
client:
provider:
oidc:
issuer-uri: http://keycloak-cluster-http.keycloak-cluster.svc.cluster.local/auth/realms/myrealm
authorization-uri: http://keycloak-cluster-http.keycloak-cluster.svc.cluster.local/auth/realms/myrealm/protocol/openid-connect/auth
jwk-set-uri: http://keycloak-cluster-http.keycloak-cluster.svc.cluster.local/auth/realms/myrealm/protocol/openid-connect/certs
token-uri: http://keycloak-cluster-http.keycloak-cluster.svc.cluster.local/auth/realms/myrealm/protocol/openid-connect/token
user-name-attribute: preferred_username
The external URL of keycloak is https://keycloak.localhost, managed by ingress redirection handled by Traefik v2
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: keycloak-https
namespace: keycloak-cluster
annotations:
traefik.frontend.passHostHeader: "true"
spec:
entryPoints:
- websecure
routes:
- match: Host(`keycloak.localhost`)
kind: Rule
services:
- name: keycloak-cluster-http
port: 80
tls:
options:
name: mytlsoption
namespace: traefik
store:
name: default
I can access Keycloak using https://keycloak.localhost, no problem, it works.
The problem is that when I try to access my web application, it will always redirect to 'http://keycloak-cluster-http.keycloak-cluster.svc.cluster.local/auth/realms/myrealm', which is not resolved outside k8s.
If I change issuer-uri to http://keycloak.localhost then it doesn't work as keycloak.locahost is not resolved inside k8s.
I tried to set the KEYCLOAK_FRONTEND_URL to https://keycloak.localhost/auth, but no change.
Please, does someone has the same kind of settings and managed to make it working ?
Best regards
Managed to fix it using coredns and adding a rewrite rule... :
rewrite name keycloak.localhost keycloak-cluster-http.keycloak-cluster.svc.cluster.local
apiVersion: v1
data:
Corefile: |
.:53 {
errors
health
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
rewrite name keycloak.localhost keycloak-cluster-http.keycloak-cluster.svc.cluster.local
prometheus :9153
forward . /etc/resolv.conf
cache 30
loop
reload
loadbalance
}
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
The authorization_uri needs to be understood by the browser since that URI is processed in the front channel. The rest of the URIs are processed in the back channel.
Because of that, the authorization_uri should use the front channel way of addressing the authorization server:
authorization_uri: https://keycloak.localhost/auth/realms/myrealm/protocol/openid-connect/auth
EDIT Based on Joe Grandja's input below, it appears that it's also necessary to not specify the issuer-uri property. The issuer-uri property is a shortcut for specifying the other URIs, and since you are specifying those, you don't need it anyway.
Here A POC that helped me with the issue.
Similar configuration ,keycloak and spring gateway are in kubernetes
The external user uses keycloak external host with https protocol
https://external-https/auth/realms/myrealm/protocol/openid-connect/auth?...
The ingress break the https and moves it to http + change the host to internal-http
gateway uses internal-http to connect to keycloakon port 8080
In order for the issuer to be the same protocol as the external the configuration uses https in user-info-uri and authorization-uri but the rest are http
make sure that the keycloak pod is open for https connection (8443)
authorization-uri: https://internal-http:8443/auth/realms/myrealm/protocol/openid-connect/auth
user-info-uri: https://internal-http:8443/auth/realms/myrealm/protocol/openid-connect/userinfo
issuer-uri: http://internal-http:8080/auth/realms/myrealm
To fix the host part of the issuer
In the gateway code I updated the following based on https://github.com/spring-projects/spring-security/issues/8882#user-content-oauth2-client
#SneakyThrows
private WebClient webClient() {
SslContext sslContext = SslContextBuilder
.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.build();
HttpClient httpClient = HttpClient.create()
.secure(t -> t.sslContext(sslContext))
.wiretap(true)
;
ReactorClientHttpConnector conn = new ReactorClientHttpConnector(httpClient);
return WebClient.builder()
.defaultHeader("HOST", "external-https")
.clientConnector(conn)
.build();
}
#Bean
WebClientReactiveAuthorizationCodeTokenResponseClient webClientReactiveAuthorizationCodeTokenResponseClient() {
final WebClientReactiveAuthorizationCodeTokenResponseClient webClientReactiveAuthorizationCodeTokenResponseClient = new WebClientReactiveAuthorizationCodeTokenResponseClient();
final WebClient webClient = webClient();
webClientReactiveAuthorizationCodeTokenResponseClient.setWebClient(webClient);
return webClientReactiveAuthorizationCodeTokenResponseClient;
}
#Bean
WebClientReactiveClientCredentialsTokenResponseClient webClientReactiveClientCredentialsTokenResponseClient() {
final WebClientReactiveClientCredentialsTokenResponseClient webClientReactiveClientCredentialsTokenResponseClient = new WebClientReactiveClientCredentialsTokenResponseClient();
final WebClient webClient = webClient();
webClientReactiveClientCredentialsTokenResponseClient.setWebClient(webClient);
return webClientReactiveClientCredentialsTokenResponseClient;
}
#Bean
WebClientReactiveRefreshTokenTokenResponseClient webClientReactiveRefreshTokenTokenResponseClient() {
final WebClientReactiveRefreshTokenTokenResponseClient webClientReactiveRefreshTokenTokenResponseClient = new WebClientReactiveRefreshTokenTokenResponseClient();
final WebClient webClient = webClient();
webClientReactiveRefreshTokenTokenResponseClient.setWebClient(webClient);
return webClientReactiveRefreshTokenTokenResponseClient;
}
#Bean
WebClientReactivePasswordTokenResponseClient webClientReactivePasswordTokenResponseClient() {
final var client = new WebClientReactivePasswordTokenResponseClient();
final WebClient webClient = webClient();
client.setWebClient(webClient);
return client;
}
#Bean
DefaultReactiveOAuth2UserService reactiveOAuth2UserService() {
final DefaultReactiveOAuth2UserService userService = new DefaultReactiveOAuth2UserService();
final WebClient webClient = webClient();
userService.setWebClient(webClient);
return userService;
}
Disabled the certificate validation - the connection is only between keycloak and gateway , both are in the kubernetes and otherwise would have used http connection, if not for this issue
The host part tells the keyclock what is the host to use for the issuer
Another issue encountered is that the location return when redirecting to authentication contains the internal url and not the external which the outside world doesn't know of
For that ,update the location that returns from the gateway
#Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http)
...
oauth2Login(oAuth2LoginSpec -> oAuth2LoginSpec
...
.addFilterAfter(new LoginLocationFilter("external-https"), SecurityWebFiltersOrder.LAST)
...
public class LoginLocationFilter implements WebFilter {
private final String externalUrl;
public LoginLocationFilter(String externalUrl) {
this.externalUrl = externalUrl;
}
#Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
//before commit ,otherwise the headers will be read only
exchange.getResponse().beforeCommit(() -> {
fixLocation(exchange);
return Mono.empty();
});
return chain.filter(exchange);
}
...