Intermediate authorization_request_not_found error with Spring Cloud Gateway and Keycloak - session-cookies

I am working on a microservice architecture developed in Spring boot with an API gateway service using Spring Cloud Gateway. I am using Keycloak as an identity provider. Everything is working fine normally, but I am getting intermediate authorization_request_not_found exception on user login and a whitelable error page occurs. If we try again, it works.
Below is the exception I received on Keycloak server:
[org.keycloak.broker.oidc.AbstractOAuth2IdentityProvider] (default task-264) Failed to make identity provider oauth callback: org.keycloak.broker.provider.IdentityBrokerException: No access_token from server.
at org.keycloak.keycloak-services#9.0.3//org.keycloak.broker.oidc.OIDCIdentityProvider.verifyAccessToken(OIDCIdentityProvider.java:495)
at org.keycloak.keycloak-services#9.0.3//org.keycloak.broker.oidc.OIDCIdentityProvider.getFederatedIdentity(OIDCIdentityProvider.java:360)
at org.keycloak.keycloak-services#9.0.3//org.keycloak.broker.oidc.AbstractOAuth2IdentityProvider$Endpoint.authResponse(AbstractOAuth2IdentityProvider.java:472)
at jdk.internal.reflect.GeneratedMethodAccessor938.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.jboss.resteasy.resteasy-jaxrs#3.9.1.Final//org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:138)
at org.jboss.resteasy.resteasy-jaxrs#3.9.1.Final//org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:517)
at org.jboss.resteasy.resteasy-jaxrs#3.9.1.Final//org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:406)
at org.jboss.resteasy.resteasy-jaxrs#3.9.1.Final//org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$0(ResourceMethodInvoker.java:370)
at org.jboss.resteasy.resteasy-jaxrs#3.9.1.Final//org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:356)
at org.jboss.resteasy.resteasy-jaxrs#3.9.1.Final//org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:372)
at org.jboss.resteasy.resteasy-jaxrs#3.9.1.Final//org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:344)
... more stack trace
Below is the configuration code:
spring:
mvc:
favicon:
enabled: false
autoconfigure:
exclude: org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration
thymeleaf:
cache: false
security:
oauth2:
resourceserver:
jwt:
jwk-set-uri : http://localhost:8080/auth/realms/<realm-name>/protocol/openid-connect/certs
client:
registration:
keycloak:
client-id: <client-id>
client-secret: <client-secret>
clientName: <client-name>
authorization-grant-type: authorization_code
provider: keycloak
redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}'
scope:
- openid
- profile
- email
provider:
keycloak:
issuer-uri: http://localhost:8080/auth/realms/<realm-name>
user-name-attribute: preferred_username
cloud:
gateway:
httpclient:
connect-timeout: 6000000
response-timeout: 600s
ssl:
close-notify-read-timeout: 600s
close-notify-flush-timeout: 600s
handshake-timeout: 600s
pool:
acquire-timeout: 6000000
type: fixed
max-connections: 5000
servlet:
multipart:
max-file-size: 100MB
max-request-size: 100MB
Below is some part of my pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.9.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR5</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>1.0.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Below is the stack trace of exception on Gateway server:
2020-06-13 08:04:17.237 ERROR 1 --- [or-http-epoll-3] a.w.r.e.AbstractErrorWebExceptionHandler : [47e02fef] 500 Server Error for HTTP GET "/login/oauth2/code/keycloak?state=YpBEDGlrHg1-podfMyIrKp02WYVPDIMRu_59vuRqado%3D&session_state=e8f4736b-1985-4730-af00-f55b38edf44a&code=1050f391-8438-4c18-ba52-d343ed25aa1c.e8f4736b-1985-4730-af00-f55b38edf44a.5b3ba9ec-3da5-4549-aaa8-79cf360f1d6d"
org.springframework.security.oauth2.core.OAuth2AuthorizationException: [authorization_request_not_found]
at org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizationCodeAuthenticationTokenConverter.lambda$oauth2AuthorizationException$1(ServerOAuth2AuthorizationCodeAuthenticationTokenConverter.java:82) ~[spring-security-oauth2-client-5.1.6.RELEASE.jar!/:5.1.6.RELEASE]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:44) [reactor-core-3.2.12.RELEASE.jar!/:3.2.12.RELEASE]
at reactor.core.publisher.Mono.subscribe(Mono.java:3858) ~[reactor-core-3.2.12.RELEASE.jar!/:3.2.12.RELEASE]
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onComplete(FluxSwitchIfEmpty.java:75) ~[reactor-core-3.2.12.RELEASE.jar!/:3.2.12.RELEASE]
at reactor.core.publisher.FluxHandle$HandleSubscriber.onComplete(FluxHandle.java:207) ~[reactor-core-3.2.12.RELEASE.jar!/:3.2.12.RELEASE]
at reactor.core.publisher.FluxHandle$HandleSubscriber.onNext(FluxHandle.java:128) ~[reactor-core-3.2.12.RELEASE.jar!/:3.2.12.RELEASE]
at reactor.core.publisher.FluxMap$MapConditionalSubscriber.onNext(FluxMap.java:213) ~[reactor-core-3.2.12.RELEASE.jar!/:3.2.12.RELEASE]
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1515) ~[reactor-core-3.2.12.RELEASE.jar!/:3.2.12.RELEASE]
at reactor.core.publisher.MonoProcessor.onNext(MonoProcessor.java:389) ~[reactor-core-3.2.12.RELEASE.jar!/:3.2.12.RELEASE]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:192) ~[reactor-core-3.2.12.RELEASE.jar!/:3.2.12.RELEASE]
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:67) ~[reactor-core-3.2.12.RELEASE.jar!/:3.2.12.RELEASE]
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1515) ~[reactor-core-3.2.12.RELEASE.jar!/:3.2.12.RELEASE]
at reactor.core.publisher.MonoSupplier.subscribe(MonoSupplier.java:61) ~[reactor-core-3.2.12.RELEASE.jar!/:3.2.12.RELEASE]
at reactor.core.publisher.Mono.subscribe(Mono.java:3858) ~[reactor-core-3.2.12.RELEASE.jar!/:3.2.12.RELEASE]
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onComplete(FluxSwitchIfEmpty.java:75) ~[reactor-core-3.2.12.RELEASE.jar!/:3.2.12.RELEASE]
at reactor.core.publisher.MonoNext$NextSubscriber.onComplete(MonoNext.java:96) ~[reactor-core-3.2.12.RELEASE.jar!/:3.2.12.RELEASE]
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:360) ~[reactor-core-3.2.12.RELEASE.jar!/:3.2.12.RELEASE]
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onComplete(FluxConcatMap.java:269) ~[reactor-core-3.2.12.RELEASE.jar!/:3.2.12.RELEASE]
at reactor.core.publisher.Operators.complete(Operators.java:131) ~[reactor-core-3.2.12.RELEASE.jar!/:3.2.12.RELEASE]
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:122) ~[reactor-core-3.2.12.RELEASE.jar!/:3.2.12.RELEASE]
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:63) ~[reactor-core-3.2.12.RELEASE.jar!/:3.2.12.RELEASE]
at reactor.core.publisher.FluxConcatMap.subscribe(FluxConcatMap.java:121) ~[reactor-core-3.2.12.RELEASE.jar!/:3.2.12.RELEASE]
... more stack trace.
As far as I have seen, this error occurs when user session timeouts.
I think the cookie is not getting deleted once the session is timeout. This issue never happens when the user logouts from the application.
Is there any way I can auto delete the cookie when the session timeouts? Or can I redirect the to logout API when I receive I receive timeout error before the user routes to the login screen?
I have visited several blogs and other stack overflow issues but I can't figure it out what's wrong in my configs.
Is there any way I can find out what is wrong ?
Any help is much appreciated. Thanks in advance!

Related

Named Destination for Spring Cloud Stream Source Extension

We are in process of extending the rabbit mq source connector in SCDF running on a kafka binder and add additional functionalities that coule be extended using functions to add additional processing before message is delivered to final destination.
The question I have is, currently the output gets delivered by default to topic output when running as spring boot. Is there a way to give a named queue instead of the default output topic?
is this a known limitation as the rabbit source is based on boot 2.1.x? If so, are there alternatives to achieve a similar functionality using the latest Supplier function for rabbit mq listener.
Simple App
#SpringBootApplication
#Import(org.springframework.cloud.stream.app.rabbit.source.RabbitSourceConfiguration.class)
public class RabbitSourceApp {
public static void main(String[] args) {
SpringApplication.run(RabbitSourceApp.class, args);
}
#Bean
public Function<String, String> upper() {
return value -> value.toUpperCase();
}
}
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.source</groupId>
<artifactId>source.sample</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
<relativePath></relativePath>
</parent>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-cloud.version>Hoxton.SR1</spring-cloud.version>
<spring-cloud.schema.version>2.2.1.RELEASE</spring-cloud.schema.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud.stream.app</groupId>
<artifactId>spring-cloud-starter-stream-source-rabbit</artifactId>
<version>2.1.3.RELEASE</version>
<exclusions>
<exclusion> <!-- declare the exclusion here -->
<groupId>io.pivotal.spring.cloud</groupId>
<artifactId>spring-cloud-services-starter-config-client</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-schema</artifactId>
<version>${spring-cloud.schema.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
application yaml
spring:
cloud:
stream:
kafka:
binder:
brokers: localhost:29092
bindings:
upper-out-0:
destination: upperQ
function:
definition: upper
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
rabbit.queues: TestQ
This is what worked for me, but not sure if this is the correct solution.
bindings:
output:
destination: upperQ

Monitoring custom Stream apps in Spring Cloud data flow

I am trying scdf and its monitoring with prometheus and grafana. I followed the documentation available and able to deploy the sample stream and able to see the metrics in the grafana.
I have created a stream with some custom stream app (other than the supplied rabbit mq starter apps).
Stream:
htt | participant | log
But am not able see the "participant" application metrics in gafana. But able to see the metrics of http and log apps.
Added below properties in application.properties.
management.endpoint.metrics.enabled=true
management.endpoints.web.exposure.include=*
management.endpoint.prometheus.enabled=true
management.metrics.export.prometheus.enabled=true
spring.cloud.streamapp.security.enabled=false
Added below dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--<!– https://mvnrepository.com/artifact/org.springframework.cloud.stream.app/app-starters-common –>-->
<!--<dependency>-->
<!--<groupId>org.springframework.cloud.stream.app</groupId>-->
<!--<artifactId>app-starters-common</artifactId>-->
<!--<version>2.1.1.RELEASE</version>-->
<!--<type>pom</type>-->
<!--</dependency>-->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
After adding app-starters-common:org.springframework.cloud.stream.app dependency localhost:< port >/ opens a login page.
I think you need app-starters-micrometer-common dependency which adds some of the micrometer tags to your app. This dependency is intended to be used by the Spring cloud stream app starters and I believe you can use it in your custom application as well.
I came across this question while looking answers for the same.
Here is my working code snippet:-
Pom.xml
<dependency>
<groupId>org.springframework.cloud.stream.app</groupId>
<artifactId>app-starters-micrometer-common</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-jmx</artifactId>
</dependency>
application property change to enable prometheus and disable security(login page)
management.endpoints.web.exposure.include=*
management.metrics.export.prometheus.enabled=true
-- this one to remove security (login page), which was automatically added by app-starter-micrometre-common dependency.
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration, org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration
or
exclude the dependency, I excluded config-client and few other since I don't need them in my application.
<dependency>
<groupId>org.springframework.cloud.stream.app</groupId>
<artifactId>app-starters-micrometer-common</artifactId>
<version>2.1.2.RELEASE</version>
<exclusions>
<exclusion>
<artifactId>spring-security-config</artifactId>
<groupId>org.springframework.security</groupId>
</exclusion>
<exclusion>
<artifactId>spring-cloud-services-starter-config-client</artifactId>
<groupId>io.pivotal.spring.cloud</groupId>
</exclusion>
<exclusion>
<artifactId>*</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
With later Data Flow 2.3.x, you need to add the following dependencies to your processor:
<dependency>
<groupId>org.springframework.cloud.stream.app</groupId>
<artifactId>app-starters-micrometer-common</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer.prometheus</groupId>
<artifactId>prometheus-rsocket-spring</artifactId>
<version>0.9.0</version>
</dependency>
The app-starters-micrometer-common injects DataFlow specific tags, such as stream.name, application.name, application.type all used by the dashboard to aggregate the required metrics.
In addition you can follow instructions in the sample projects, showing how to build custom Source, Processor and Sink apps with enabled prometheus monitoring:
https://github.com/spring-cloud/spring-cloud-dataflow-samples/tree/master/monitoring-samples/stream-apps

Error in Launching application with different DB profile defined in the spring config server into client spring boot project

I am trying to develop a microservice and deployment for two different regions. Two different region using two different database. So for using that, I created one spring cloud config server and defined database property for two different profiles,
Here Is my spring cloud config server project details, Created config folder in src/main/resources and add two files,
bootstrap-vcu.properties file containing,
spring.datasource.driverClassName=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost/milleTech_users
spring.datasource.username=postgres
spring.datasource.password=postgresql
bootstrap-sp.properties file containing,
spring.datasource.driverClassName=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost/espace
spring.datasource.username=postgres
spring.datasource.password=postgresql
Application.properties containing,
server.port=8888
spring.profiles.active=native
Bootstrap.properties
spring.cloud.config.uri=localhost:8888
Folder structure for config server is as following,
And my pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
And created separate project for spring cloud config client,
Config client project application.properties file is like,
server.port=8080
spring.cloud.config.uri=localhost:8888
And launching client application like ,
java -jar -Dsping.profiles.active=vcu ConfigClient-0.0.1-SNAPSHOT.war
But getting error as
"Failed to auto-configure a DataSource: 'spring.datasource.url' is not
specified and no embedded datasource could be auto-configured"
Reason: Failed to determine a suitable driver class
Try to rename DbVcu.properties into application-DbVcu.properties and move it to src/main/ressources folder.

Accessing Hive using JdbcIO in apache beam throws java.lang.NoClassDefFoundError: org/apache/avro/reflect/AvroSchema

I could access my mysql table using JDBCIO and Avro Coder. Now I am trying to load my hive database using JdbcIO.
Below exception has thrown while connecting to hive from dataflow. Any help from the beam geeks would be really helpful.
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/avro/reflect/AvroSchema
at org.apache.beam.sdk.coders.AvroCoder$AvroDeterminismChecker.recurse(AvroCoder.java:426)
at org.apache.beam.sdk.coders.AvroCoder$AvroDeterminismChecker.check(AvroCoder.java:419)
at org.apache.beam.sdk.coders.AvroCoder.<init>(AvroCoder.java:259)
at org.apache.beam.sdk.coders.AvroCoder.of(AvroCoder.java:120)
at com.google.cloud.bigquery.csv.loader.GoogleSQLPipeline.main(GoogleSQLPipeline.java:101)
Caused by: java.lang.ClassNotFoundException: org.apache.avro.reflect.AvroSchema
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 5 more
Below code snippet is trying to access hive :
dataflowPipeline
.apply(JdbcIO.<Customer>read()
.withDataSourceConfiguration(JdbcIO.DataSourceConfiguration
.create("org.apache.hive.jdbc.HiveDriver", "jdbc:hive2://<ip>/mydb")
.withUsername("username").withPassword("password"))
.withQuery(
"select c_customer_id,c_first_name,c_last_name,c_preferred_cust_flag,c_birth_day,c_birth_month,c_birth_year,c_birth_country,c_customer_sk,c_current_cdemo_sk,c_current_hdemo_sk from customer")
.withRowMapper(new JdbcIO.RowMapper<Customer>() {
#Override
public Customer mapRow(ResultSet resultSet) throws Exception
POM Dependecies :
<dependencies>
<dependency>
<groupId>com.google.cloud.dataflow</groupId>
<artifactId>google-cloud-dataflow-java-sdk-all</artifactId>
<version>2.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.beam/beam-sdks-java-io-jdbc -->
<dependency>
<groupId>org.apache.beam</groupId>
<artifactId>beam-sdks-java-io-jdbc</artifactId>
<version>2.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.hive/hive-jdbc -->
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-jdbc</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>jdk.tools</groupId>
<artifactId>jdk.tools</artifactId>
<version>1.8.0_131</version>
<scope>system</scope>
<systemPath>${JAVA_HOME}/lib/tools.jar</systemPath>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-common -->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
<!-- slf4j API frontend binding with JUL backend -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.14</version>
</dependency>
</dependencies>
Added dependency for Avro 1.8.1 and manually imported import org.apache.avro.reflect.AvroSchema; Now that issue is solved. Again, issues related to com.google.protobuf.GeneratedMessageV3 is solved by manually importing this class.

Issues creating OAuth secured Microservices using Spring boot, Eureka, Zuul, Spring Oauth

I'm trying to get a Zuul reverse proxy setup with Spring Boot, Eureka, Zuul and Spring OAuth. Specifically, I'm trying to obtain an OAuth bearer token from our OAuth server that is behind Zuul. To do this, i need to make a POST request to the proxy endpoint that redirects to our OAuth server. This request is using the client_credentials grant type and thus am using BasicAuth to obtain the bearer token. I've verified that I can obtain the token by bypassing Zuul.
I been having trouble getting my expected results which are a reverse proxy that is OAuth aware but has no required security itself. I've tried a few different variations on configuration and cannot find the golden ticket.
Here is my Maven:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.mycompany.cloud</groupId>
<artifactId>mycompany-cloud</artifactId>
<version>0.0.2-SNAPSHOT</version>
</parent>
<artifactId>mycompany-cloud-zuul-proxy</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Brixton.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.3.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
I initially created a configuration that was just
#SpringBootApplication
#EnableZuulProxy
#EnableEurekaClient
#EnableOAuth2Sso
public class ZuulProxyApplication {
public static void main(final String[] args) {
SpringApplication.run(ZuulProxyApplication.class, args);
}
}
but this by default enabled basic auth security. I knew this because i would get CSRF erros on any POST request made. Setting security.enable-csrf=false did not disable this (i found this odd). Setting security.basic.enabled=false also did not disable any security also odd. I finally noticed the JavaDoc on #EnableOAuth2Sso said that if no WebSecurityConfigurerAdapter was provided then it would use a default. I tried adding the #EnableWebSecurity to my configuration which should have added a WebSecurityConfigurerAdapter but I was still getting CSRF errors on my POST requests. Maybe the default its using isnlt aware of SecurityProperties. So I ended up with this configuration:
#SpringBootApplication
#EnableZuulProxy
#EnableEurekaClient
public class ZuulProxyApplication {
public static void main(final String[] args) {
SpringApplication.run(ZuulProxyApplication.class, args);
}
#Configuration
#EnableOAuth2Sso
#EnableWebSecurity
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
protected static class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
public void globalUserDetails(final AuthenticationManagerBuilder auth) throws Exception {
// add no users
auth.inMemoryAuthentication();
}
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.csrf().disable();
}
}
}
and the following properties:
spring:
application:
name: mycompany-cloud-zuul-proxy
index: 0
security:
oauth2:
client:
access-token-uri: http://mycompany-cloud-authorization-server/oauth/token
user-authorization-uri: http://mycompany-cloud-authorization-server/oauth/authorize
basic:
enabled: false
enable-csrf: false
sessions: stateless
server:
port: 9200
eureka:
client:
service-url:
defaultZone: http://localhost:9100/eureka/
And this was successful, it disabled the CSRF configuration and I was able to make POST requests to my services without receiving the CSRF error. However, now my OAuth server is rejecting the requests because the BasicAuth header is no longer on the request. It appears that Zuul is stripping the header. Am I misunderstanding that adding the #EnableOAuth2Sso annotation makes the application OAuth aware and that it would allow means of accessing the configured OAuth server or does it simply apply to Bearer tokens? Is it normal to place your OAuth server behind the proxy or is that not an expected thing to do? I'm guessing that I'm missing some important knowledge and/or configuration that I have yet to comprehend from the documentation.
Any help here would be appreciated.
However, now my OAuth server is rejecting the requests because the BasicAuth header is no longer on the request
By default Spring cloud Zuul implementation strips some headers for security purpose (see Cookies and sensitive headers documentation)
Thus since Spring cloud netflix 1.1 following headers Cookie, Set-Cookie, Authorization are considered as sensible headers
Is it normal to place your OAuth server behind the proxy or is that not an expected thing to do?
Spring cloud is basically not designed by default to have Authorization server (or OAuth server) behind proxy (Zuul). In most example and documention Authorization server is outside proxy.
I personally created a POC for Authorization behind Proxy https://github.com/kakawait/uaa-behind-zuul-sample that may (or not) help you.

Resources