How do I configure spring boot aplication and consul? I read a oficial documentation but i cant do it...
pom
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2021.0.0</spring-cloud.version>
</properties>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-vault-config</artifactId>
</dependency>
application.yml
spring:
application:
name: gateway
config:
import:
- "vault://secret"
- "consul:127.0.0.1:8500"
cloud:
vault:
scheme: http
authentication: TOKEN
host: 127.0.0.1
port: 8200
token: myroot
connection-timeout: 5000
read-timeout: 15000
consul:
config:
enabled: true
prefix: config
format: yaml
profile-separator: ","
watch:
enabled: true
Test property
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class MyController {
#Value("${test}")
String myConsule1;
#GetMapping("/mycontroller")
public String getValues() {
return "{v1: '" + myConsule1 + "', v2: '" + "" + "'}";
}
}
Consul
ERROR:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'test' in value "${test}"
Can you help me? please...
Related
I'm trying to request from a Quarkus's api to Jersey's api, but Jersey API returns a 404 error:
javax.ws.rs.WebApplicationException: Unknown error, status code 404
It looks like quarkus rest client doesn't recognize or can't parse the payload json.
Did you already get something like that?
the payload should be something like that:
{
"code": 404,
"description": "some description....",
"label": "API_ERROR_OBJECT_NOT_FOUND",
"message": "Requested Object not found"
}
The code:
#ApplicationScoped
public class MachineService {
#Inject
#RestClient
ICoreSummaryRest iCoreSummaryRest;
public Boolean transferDatacollector(ObjectNode transferDatacollector) {
try {
String resp = iCoreSummaryRest.updateDataCollectosTransfer
(transferDatacollector.toString());
return Boolean.valueOf(resp);
}catch (Exception e){
return null;
}
}
interface
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders;
import org.eclipse.microprofile.rest.client.annotation.RegisterProvider;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
#Path("/")
#RegisterRestClient(configKey="country-api")
#RegisterClientHeaders(CustomHeadersRest.class)
public interface ICoreSummaryRest {
#PUT
#Produces(MediaType.APPLICATION_JSON)
#Path("datacollectors/transfer/")
public String updateDataCollectosTransfer(String transferDatacollectorJSON);
}
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>
<!-- The Basics -->
<parent>
<groupId>com.mycompany</groupId>
<artifactId>my-project</artifactId>
<version>1.0.0</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>my-project-resource</artifactId>
<version>1.0.0</version>
<dependencies>
<!-- Dependências Gerais Quarkus BOM -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jsonb</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.spec.javax.ws.rs</groupId>
<artifactId>jboss-jaxrs-api_2.1_spec</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-openapi</artifactId>
<scope>provided</scope>
</dependency>
<!-- <dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-graphql</artifactId>
</dependency> -->
<dependency>
<groupId>org.eclipse.microprofile.rest.client</groupId>
<artifactId>microprofile-rest-client-api</artifactId>
</dependency>
<!-- Dependências do Projeto -->
<dependency>
<groupId>com.mycompany</groupId>
<artifactId>my-project-service</artifactId>
<scope>provided</scope>
</dependency>
<!-- Dependência JTS -->
<dependency>
<groupId>org.locationtech.jts</groupId>
<artifactId>jts-core</artifactId>
</dependency>
<!-- Dependência mycompany -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
</dependencies>
<!-- Build Settings -->
<build>
<plugins>
<plugin>
<groupId>org.jboss.jandex</groupId>
<artifactId>jandex-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
If you want to read the body you can catch the error like this:
try {
String resourceResponse = errorRestClient.getResource();
} catch (WebApplicationException e) {
String respStr = e.getResponse().readEntity(String.class);
LOGGER.error(respStr);
}
Which will print this for the following mockbin at http://mockbin.org/bin/3144eda0-9fa7-4893-90ee-5d624d51bcd2
2022-01-30 17:59:45,851 ERROR [org.acm.arc.ErrorHTTPrestAPI]
(vert.x-eventloop-thread-11) { "description": "some
description....",
"label": "API_ERROR_OBJECT_NOT_FOUND",
"message": "Requested Object not found" }
My interface looks like this
#ApplicationScoped
#Path("/")
#RegisterRestClient(baseUri="http://mockbin.org/bin/3144eda0-9fa7-4893-90ee-5d624d51bcd2")
public interface ErrorRestClient {
#GET
#Path("")
String getResource();
}
If I understood correctly this issue,
when RestClient receives one response different from 2xx it automatically throws this exception.
Perhaps you can disable the ResponseExceptionMapper or create one interceptor to handle this exception.
Below I just quote the answer from this issue
This exception is thrown by the default rest client ResponseExceptionMapper.
You should be able to disable it by adding the following property to application.properties:
microprofile.rest.client.disable.default.mapper=false
See the Default ResponxeExceptionMapper and ResponseExceptionMapper sections of the MicroProfile Rest Client specification.
I'm trying to bring up simple pub-sub application using spring cloud kafka binder. However I'm unable to set Serializer, DeSerialzer property and other producer and consumer properties in application.yml. I consistently get serialization/deserialization error. Even kafka logs in spring boot project shows producer and consumer config still users ByteArraySerializer. Below is the code sameple.
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>io.github.kprasad99.kafka</groupId>
<artifactId>kp-kafka-streams-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>kp-kafka-streams-example</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
<spring-cloud.version>Hoxton.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- <dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-streams</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-kafka-streams</artifactId>
</dependency> -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-kafka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-test-support</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Processor.java
public interface Processor {
String INPUT="k-msg-source";
String OUTPUT="k-msg-sink";
#Input(INPUT)
SubscribableChannel input();
#Output(OUTPUT)
MessageChannel output();
}
KRest.java
#RestController
public class KRest {
#Autowired
private Processor processor;
#GetMapping("/send")
public ResponseEntity<Void> send(#RequestParam("key")String key, #RequestParam("msg") String text){
processor.input().send(MessageBuilder.withPayload(Message.builder().text(text).build()).setHeader(KafkaHeaders.MESSAGE_KEY, key).build());
return ResponseEntity.ok().build();
}
}
Message.java
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
public class Message {
private String text;
}
And finally application.yml
spring:
cloud:
stream:
bindings:
k-msg-source:
binder: kafka
content-type: application/json
destination: topic.kp.msg
group: kp.msg.source
k-msg-sink:
binder: kafka
content-type: application/json
destination: topic.kp.msg
group: kp.msg.sink
producer:
partition-count: 10
binders:
kafka:
type: kafka
environment:
spring.cloud.stream.kafka.binder:
brokers: localhost:9092
configuration:
value.serde: JsonSerde
key.serde: StringSerde
producer:
value.serde: JsonSerde
key.serde: StringSerde
replication-factor: 1
Versions
spring-boot: 2.2.4
spring-cloud: Hoxton.SR1
spring-cloud-stream-kafka-binder: 3.0.1
Serdes are used by the Kafka Streams binder.
With the MessageChannel binder, the properties are value.serializer and value.deserializer (and key...), and key/value.deserializer.
You also have to specify the fully qualified named of the classes.
Final application.yml
spring.cloud.stream:
bindings:
k-msg-source:
binder: kafka
destination: topic.kp.msg
content-type: application/json
producer:
partition-count: 10
use-native-encoding: true
k-msg-sink:
binder: kafka
destination: topic.kp.msg
group: ne-publisher
content-type: application/json
consumer:
use-native-decoding: true
binders:
kafka:
type: kafka
environment:
spring.cloud.stream.kafka.binder:
brokers: PLAINTEXT://localhost:19092,PLAINTEXT://localhost:29092,PLAINTEXT://localhost:39092
configuration:
key.serializer: org.apache.kafka.common.serialization.StringSerializer
value.serializer: org.springframework.kafka.support.serializer.JsonSerializer
key.deserializer: org.apache.kafka.common.serialization.StringDeserializer
value.deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
consumer-properties:
spring.json.trusted.packages: "*"
I have a Spring Authorization/Resource server managing the authorization of a Webflux Oauth2 client. On it's own this is working OK. When I add Spring Cloud Gateway and access the Webflux via the Gateway I see that the Authorization Server validates the user and the Webflux returns 302, but on the Gateway I get 400 "Invalid client registration id".
The Authorization/Resource server is;
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.9.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
The starter;
#SpringBootApplication
#EnableAuthorizationServer
#EnableResourceServer
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Properties;
server:
port: 8889
Server configuration;
#Configuration
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private BCryptPasswordEncoder passwordEncoder;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore());
}
#Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("myClientId2")
.secret(passwordEncoder.encode("mySecret2"))
.authorizedGrantTypes("authorization_code")
.scopes("all")
.autoApprove(true)
.redirectUris("http://localhost:8083/login/oauth2/code/myAppTwo")
.and()
.withClient("myGatewayId")
.secret(passwordEncoder.encode("myGatewaySecret"))
.authorizedGrantTypes("authorization_code")
.scopes("all")
.autoApprove(true)
.redirectUris("http://localhost:8888/login/oauth2/code/gateway")
;
}
}
Security;
#Configuration
#Order(1)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.requestMatchers()
.antMatchers("/login", "/oauth/authorize")
.and().authorizeRequests().anyRequest().authenticated()
.and().formLogin().permitAll();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("x").password(passwordEncoder().encode("123"))
.roles("USER");
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
User response;
#RestController
public class UserController {
#GetMapping("/user")
public Principal user(Principal principal) {
System.err.println(principal);
return principal;
}
The Webflux is;
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.9.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
</dependencies>
Properties;
server:
port: 8083
spring:
security:
oauth2:
client:
registration:
myAppTwo:
client-name: Test8082
client-id: myClientId2
client-secret: mySecret2
authorization-grant-type: authorization_code
redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
provider:
myAppTwo:
authorization-uri: http://localhost:8889/oauth/authorize
token-uri: http://localhost:8889/oauth/token
user-info-uri: http://localhost:8889/user
user-name-attribute: name
Webflux end point;
#RestController
public class Controller {
#GetMapping(value = "/test3")
Mono<OAuth2User> getTest3(#AuthenticationPrincipal Mono<OAuth2User> ouser) {
System.err.println("o =" + ouser);
return ouser;
}
}
Running http://localhost:8083/test3 via Chrome take me to the log-in page on the Authorization server, after which I enter the credentials and then then URL above returns the expected Response.
When I add a Gateway;
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.9.RELEASE</version>
<relativePath/>
</parent>
<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.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
With properties;
server:
port: 8888
spring:
autoconfigure:
# TODO: remove when fixed https://github.com/spring-projects/spring-security/issues/17949
# Without this line, Gateway tries to log in using it's own security, rather than deferring to OAuth2
exclude: org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration
cloud:
gateway:
routes:
- id: oauth
predicates:
- Path=/oauth2/**
uri: http://localhost:8889
filters:
- TokenRelay=
- RemoveRequestHeader=Cookie
- id: route2
predicates:
- Path=/2/**
uri: http://localhost:8083
filters:
- RewritePath=/2/(?<myPath>.*), /$\{myPath}
- TokenRelay=
- RemoveRequestHeader=Cookie
security:
oauth2:
client:
registration:
gateway:
client-id: myGatewayId
client-secret: myGatewaySecret
authorization-grant-type: authorization_code
redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
provider: gateway
provider:
gateway:
authorization-uri: http://localhost:8889/oauth/authorize
token-uri: http://localhost:8889/oauth/token
user-info-uri: http://localhost:8889/user
user-name-attribute: name
jwk-set-uri: http://localhost:8889/oauth/token_key
Now if I try http://localhost:8888/2/test3 I am still re-directed to the log-in. The toString on the Authorization server logs the credentials, the Webflux still gives 302, but the Gateway does the following;
Route matched: route2
Mapping [Exchange: GET http://localhost:8888/2/test3] to Route{id='route2', uri=http://localhost:8083, order=0, predicate=Paths: [/2/**], match trailing slash: true, gatewayFilters=[[[RewritePath /2/(?<myPath>.*) = '/${myPath}'], order = 1], [org.springframework.cloud.security.oauth2.gateway.TokenRelayGatewayFilterFactory$$Lambda$666/1724736027#4b96b22, order = 2], [[RemoveRequestHeader name = 'Cookie'], order = 3]]}
[98bb6dad] Mapped to org.springframework.cloud.gateway.handler.FilteringWebHandler#6fa90b79
Sorted gatewayFilterFactories: [[GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.RemoveCachedBodyFilter#1894593a}, order = -2147483648], [GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter#b835727}, order = -2147482648], [GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.NettyWriteResponseFilter#7fd26ad8}, order = -1], [GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.ForwardPathFilter#7cea0110}, order = 0], [GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.GatewayMetricsFilter#5527b211}, order = 0], [[RewritePath /2/(?<myPath>.*) = '/${myPath}'], order = 1], [org.springframework.cloud.security.oauth2.gateway.TokenRelayGatewayFilterFactory$$Lambda$666/1724736027#4b96b22, order = 2], [[RemoveRequestHeader name = 'Cookie'], order = 3], [GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter#14b0e127}, order = 10000], [GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.config.GatewayNoLoadBalancerClientAutoConfiguration$NoLoadBalancerClientFilter#54cf7c6a}, order = 10100], [GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.WebsocketRoutingFilter#468dda3e}, order = 2147483646], [GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.NettyRoutingFilter#3d37203b}, order = 2147483647], [GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.ForwardRoutingFilter#10823d72}, order = 2147483647]]
"GET /2/test3 HTTP/1.1" 302 0 8888 8 ms
Resolved [ResponseStatusException: 400 BAD_REQUEST "Invalid client registration id"] for HTTP GET /oauth2/authorization/myAppTwo
Writing "<html><body><h1>Whitelabel Error Page</h1><p>This application has no configured error view, so you (truncated)...
"GET /oauth2/authorization/myAppTwo HTTP/1.1" 400 312 8888 2 ms
"GET /favicon.ico HTTP/1.1" 302 0 8888 2 ms
"GET /oauth2/authorization/gateway HTTP/1.1" 302 0 8888 2 ms
Writing form fields [grant_type, code, redirect_uri] (content masked)
Decoded [{access_token=2c14f1e7-5d95-4fed-be95-2d8518d1fb48, token_type=bearer, expires_in=40912, scope=all}]
Decoded [{authorities=[{authority=ROLE_USER}], details={remoteAddress=127.0.0.1, sessionId=null, tokenValue=2 (truncated)...]
"GET /login/oauth2/code/gateway?code=fGdiyz&state=ZynriL0UtU37b4rMfDHM7JheNYYo0UnZQvgu4U2kWwQ%3D HTTP/1.1" 302 0 8888 82 ms
"GET / HTTP/1.1" 200 3348 8888 5 ms
Via the same browser session, if I try the direct URL http://localhost:8083/test, it response correctly (i.e. I am logged in and 8083 has my credentials).
I see via debug that DefaultServerOAuth2AuthorizationRequestResolver.findByRegistrationId first checks the redirect for gateway and passes. However, it tries and fails on a second pass for the redirect of myAppTwo, which was not defined the Gateway's YML and I assume shouldn't be. Removing the route oauth seems to have no affect. I never see that route being hit.
So how do I get the Gateway to redirect to myAppTwo on port 8083?
Update When I use KeyCloak instead of my own AuthorizationServer/ResourceServer I get the same issue.
There's need to integrate Keycloak with my spring boot application. What i need is that any REST request coming to my API will have a header e.g. "Authorisation" which will have value as "basic " to be used as auth token.
The request came to API should be validated from keyclaok without redirecting to any login page of keycloak.
All the tutorials to integrate keycloak with spring boot shows a login page or pre generated bearer token.
When i try to do this, below is my SecurityConfig.java:
#Configuration
#EnableWebSecurity
#ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
#Bean
public KeycloakSpringBootConfigResolver keycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
#Bean
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests().antMatchers("/myapi*").hasRole("user").anyRequest().permitAll();
}
}
My application.properties:
server.port=8081
keycloak.auth-server-url=http://localhost:9080/auth
keycloak.realm=myrealm
keycloak.resource=myclient
keycloak.public-client=false
keycloak.credentials.secret=mysecret
keycloak.use-resource-role-mappings=true
keycloak.enabled=true
keycloak.ssl-required=external
pom.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.example.api</groupId>
<artifactId>springboot-kc-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-kc-api</name>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.keycloak.bom</groupId>
<artifactId>keycloak-adapter-bom</artifactId>
<version>6.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Whenever a GET request is made, keycloak debug shows below log:
o.k.adapters.OAuthRequestAuthenticator : Sending redirect to login page: http://localhost:9080/auth/realms/myrealm/protocol/openid-connect/auth?response_type=code&client_id=myclient&redirect_uri=http%3A%2F%2Flocalhost%3A8081%2Fmyapi%2Fsampleget?param1=val1&state=a2b5072a-acb8-4bf6-8f33-b3f25deab492&login=true&scope=openid
Keycloak configuration:
Client Protocol : openid-connect
Access Type : confidential
Valid Redirect URIs: http://localhost:8081/myapi/*
Above setup working fine for an API written in Java REST Easy framework for one of existing application running on JBoss EAP 7.
Need help to understand how to configure spring boot API to use auth header in request to authenticate & authorise request.
This can be achieved by enabling the bearer only mode. Start with enabling this in your spring boot service via application.properties:
keycloak.bearer-only=true
See [1] for more details on this.
You can also enforce this inside the admin console for your client.
[1] https://www.keycloak.org/docs/latest/securing_apps/index.html#_java_adapter_config
You need to enable basic auth in the adapter configuration and also send the client secret. What this will do is not redirect to login page but send 401 if the basic auth headers are missing.
keycloak.enable-basic-auth=true
keycloak.credentials.secret=${client.secret}
Check out here for solution.
I just wanna give you the class which is created to talk to Keycloak through the api in spring boot. I think this will help you!
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder
import org.keycloak.admin.client.Keycloak
import org.keycloak.admin.client.KeycloakBuilder
import org.keycloak.admin.client.resource.RealmResource
import org.keycloak.admin.client.resource.UsersResource
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component
#Component
class KeycloakComponent {
#Value("\${keycloakconfig.server.url}")
var serverUrl: String = ""
#Value("\${keycloakconfig.username}")
var username: String = ""
#Value("\${keycloakconfig.password}")
var password: String = ""
#Value("\${keycloakconfig.realm}")
var realmName: String = ""
#Value("\${keycloakconfig.client.id}")
var clientId: String = ""
#Value("\${keycloakconfig.client.secret}")
var clientSecret: String = ""
val keycloak: Keycloak by lazy {
KeycloakBuilder.builder()
.serverUrl(serverUrl)
.username(username)
.password(password)
.realm(realmName)
.clientId(clientId)
.clientSecret(clientSecret)
.resteasyClient(ResteasyClientBuilder().connectionPoolSize(20).register(CustomJacksonProvider()).build())
.build()
}
val realm: RealmResource by lazy {
keycloak.realm(realmName)
}
val userResource: UsersResource by lazy {
realm.users()
}
fun keycloakForFetchUserToken(username:String, password: String): Keycloak {
return KeycloakBuilder.builder()
.serverUrl(serverUrl)
.username(username)
.password(password)
.realm(realmName)
.clientId(clientId)
.clientSecret(clientSecret)
.resteasyClient(ResteasyClientBuilder().connectionPoolSize(20).register(CustomJacksonProvider()).build())
.build()
}
}
If something does not make sense, do not hesitate to contact
I'm trying use Spring Boot Admin Server but in the dashboard my application is not listed there.
What did I do, in my pom.xml I added the following dependencies:
<!-- https://mvnrepository.com/artifact/de.codecentric/spring-boot-admin-server -->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server</artifactId>
<version>2.0.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/de.codecentric/spring-boot-admin-server-ui -->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server-ui</artifactId>
<version>2.0.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/de.codecentric/spring-boot-admin-starter-client -->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>2.0.2</version>
</dependency>
In my ServidorApplication Class:
#Configuration
#EnableAdminServer
#SpringBootApplication
#EnableAutoConfiguration(exclude = { JacksonAutoConfiguration.class })
public class ServidorApplication {
public static void main(String[] args) {
SpringApplication.run(ServidorApplication.class, args);System.err.println("Sem parametros de inicializacao");
}
GsonHttpMessageConverter gsonHttpMessageConverter() {
return new GsonHttpMessageConverter(new Gson());
}
}
And in my application.properties:
spring.boot.admin.url=http://localhost:8084
management.security.enabled=false
But when I open the Spring Boot Admin dashboard I do not have any application.
Print of my dashboard
can someone help me?
Instead of admin.url use admin.client.url
spring.boot.admin.client.url=http://localhost:8084