server
My stock-service client:
#Autowired
RestTemplate restTemplate;
ResponseEntity<List<String>> quoteResponse =
restTemplate.exchange("http://db-service/rest/db/" + userName,
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<String>>() {}
);
Here db-service is registered service in eureka server.
Its working if i hit directly like
/* ResponseEntity<List<String>> quoteResponse =
restTemplate.exchange("http://localhost:8300/rest/db/" + userName,
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<String>>() {}
);*/
#Configuration
public class Config {
#Bean
#LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
As far as I understand that db-service is your any micro-service and you want to send there request. You need to configure ribbon because RestTemplate doesn't understand db-service like host. You should add follow config:
db-service:
ribbon:
eureka:
enabled: false
listOfServers: localhost:8090
ServerListRefreshInterval: 15000
and maven dependency:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
or you could add Discovery service(Eureka) to your system and you don't need to describing listOfSerevers because ribbon will get all information from discovery service
Please try by using spring-cloud-starter-netflix-eureka-client.
And check the version of spring-cloud-dependencies along with spring-boot-starter-parent version.
spring-cloud-starter-netflix-eureka-client should resolve the issue
Related
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.
I am trying to use spring cloud gateway with kubernetes service discovery. Below is the setup which i am using
build.gradle
plugins {
id 'org.springframework.boot' version '2.2.0.BUILD-SNAPSHOT'
id 'io.spring.dependency-management' version '1.0.8.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
maven { url 'https://repo.spring.io/milestone' }
maven { url 'https://repo.spring.io/snapshot' }
}
ext {
set('springCloudVersion', "Hoxton.BUILD-SNAPSHOT")
set('springCloudKubernetesVersion', "1.0.3.RELEASE")
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes'
implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes-ribbon'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
mavenBom "org.springframework.cloud:spring-cloud-kubernetes-dependencies:${springCloudKubernetesVersion}"
}
}
test {
useJUnitPlatform()
}
application.yml
spring:
application.name: gateway
cloud:
gateway:
discovery:
locator:
enabled: true
kubernetes:
reload:
enabled: true
server:
port: 8080
logging:
level:
org.springframework.cloud.gateway: TRACE
org.springframework.cloud.loadbalancer: TRACE
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
enabled: true
info:
enabled: true
DemoApplication.java
package com.example.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.List;
#SpringBootApplication
#EnableDiscoveryClient
#RestController
public class DemoApplication {
#Autowired
private DiscoveryClient discoveryClient;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#GetMapping("/services")
public List<String> services() {
return this.discoveryClient.getServices();
}
}
Spring cloud gateway is not able to redirect the request to other services. The log being printed is
2019-10-13 18:29:38.303 TRACE 1 --- [or-http-epoll-2]
o.s.c.g.f.WeightCalculatorWebFilter : Weights attr: {} 2019-10-13
18:29:38.305 TRACE 1 --- [or-http-epoll-2]
o.s.c.g.h.RoutePredicateHandlerMapping : No RouteDefinition found
for [Exchange: GET http://gateway-url/service-name/hello]
Although when I call http://<gateway-url>/services, then I can see the list of all services. So all the permission is being provided at pod level and service discovery is working fine. I am pretty sure there is some configuration, which i am missing but I am not able to figure it out even after looking at documentation several times.
So, it looks like there is an issue in Spring Cloud Hoxton.M3 release, as it's working fine with Hoxton.M2.
I have opened an issue for the same.
Trying to write Eureka Client With Spring Cloud Netflix v1.2.0.Release
but facing the below mentioned issue. PFB code and configurations.
EurekaClient.java
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#Configuration
#EnableAutoConfiguration
#EnableEurekaClient
#RestController
#ComponentScan(basePackages={"com.west.eas.netflix.config"})
public class EurekaClient {
#RequestMapping("/")
public String home() {
return "Hello World";
}
public static void main(String[] args) {
new SpringApplicationBuilder(EurekaClient.class).run(args);
}
}
application.yml
server:
port: 9000
spring:
application:
name: eas-eureka-client
eureka:
client:
healthcheck:
enabled: true
serviceUrl:
defaultZone: http://localhost:8761/eureka/
instance:
preferIpAddress: true
bootstrap.yml
spring:
application:
name: eu-client
cloud:
config:
uri: http://localhost:8888
encrypt:
failOnError: false
Client fails to start with following error
" Parameter 0 of method eurekaHealthIndicator in
org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration$EurekaHealthIndicatorConfiguration
required a bean of type 'com.netflix.discovery.EurekaClient' that
could not be found."
the below screenshot will have more details on error stack
I even tried setting healthcheck enable to false in application.yml but it still wont work. Any Help would be appreciated.
Regards
The problem seems to be that you are naming your client EurekaClient, There is already a bean with that name. Rename that class to something else and it should work
as #spencergibb mentioned it did go wrong in adding dependencies, I've tried creating a new project via http://start.spring.io/ which resolved my issue.
Iam a beginner to Java and Jersey Restful service, I try to use Jackson to
serielize/deserialize a date, but I can't get it to work
the frontend is a JavaFX application with a Jersey client and I include
the following library to classpath (Jersey client and Jackson jar file)
cglib-2.1.88.jar
guava-14.0.1.jar
hk2-api-2.1.88.jar
hk2-locator-2.1.88.jar
hk2-utils-2.1.88.jar
jackson-annotations-2.7.2.jar
jackson-core-2.7.2.jar
jackson-databind-2.7.2.jar
jackson-jaxrs-base-2.7.2.jar
jackson-jaxrs-json-provider-2.7.2.jar
javax.annotation-api-1.2.jar
javax.inject-2.1.88.jar
javax.ws.rs-api-2.0.jar
jersey-client.jar
jersey-common.jar
persistence-api-1.0.jar
org.osgi.core-4.2.0.jar
osgi-resource-locator-1.0.1.jar
the backend is a Maven Jersey restful service archetype project
groupid: org.glassfish.jersey.archetypes
artifactId: jersey-quickstart-webapp
and in the pom.xml I have add
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.7.2</version>
</dependency>
on both frontend and backend I have a Student class
import java.util.Date;
#XmlRootElement
public class Student {
public Student () { };
Date regDate;
}
frontend code:
Client client = ClientBuilder.newClient();
Student student = client.target("urlpath").path(servicepath).request(APPLICATION.JSON).get(Student.class);
when I make a GET request I get a deserilize Student object with date
Student {
regDate: "2016-04-09 12:23AM ... // this is RIGHT "
}
but when I make a PUT request, on the backend I get a Student object with
Student {
regDate: null; // this is WRONG
}
Did I miss some library on the frontend or some dependency on the backend ...
Did anybody having the same problem as I have, please help .....
I have a JBoss 7.1.1 server, for which I want to write jmx client. As far I understood, jboss 7.1.1 is not using typical rmi based jmx and they have given a layer of remoting-jmx over native management. I am using following code:
JMXServiceURL address = new JMXServiceURL("service:jmx:remoting-jmx://localhost:9999");
Map env = JMXConnectorConfig.getEnvironment(paramtbl);
JMXConnector connector = JMXConnectorFactory.connect(address, env);
But it is giving following exception:
java.net.MalformedURLException: Unsupported protocol: remoting-jmx
I googled it and the following thread seems relevant:
https://community.jboss.org/thread/204653?tstart=0
It asks to add jboss's libraries to my classpath. I tried that also but still getting same exception.
I got the same exception when trying to get a JmxServiceUrl.
Make sure that in your standalone.xml you have the following:
<subsystem xmlns="urn:jboss:domain:jmx:1.1">
<show-model value="true"/>
<remoting-connector use-management-endpoint="true" />
</subsystem>
And you should include in project classpath the jar named: jboss-client.jar, it can be found in JBOSS_DIRECTORY/bin/client. In fact, the JMX client must include that jar in its classpath.
This tip fixed the problem for me..Hope it will be helpful for you
Tried to do the same from Arquillian test on JBoss AS7 and finally had to use:
import org.jboss.remotingjmx.RemotingConnectorProvider;
RemotingConnectorProvider s = new RemotingConnectorProvider();
JMXConnector connector = s.newJMXConnector(url, credentials);
connector.connect();
Could not have "module name="org.jboss.remoting-jmx" services="import"" working
Also works with
environment.put("jmx.remote.protocol.provider.pkgs", "org.jboss.remotingjmx");
JMXConnector connector = JMXConnectorFactory.connect(url, environment);
connector.connect();
I used this code to connect to JBoss in a remote server
ModelControllerClient client = null;
try {
client = createClient(InetAddress.getByName("172.16.73.12"), 9999,
"admin", "pass", "ManagementRealm");
}
catch (UnknownHostException e) {
e.printStackTrace();
}
Where createClient is a method I wrote -
private ModelControllerClient createClient(final InetAddress host,
final int port, final String username, final String password,
final String securityRealmName) {
final CallbackHandler callbackHandler = new CallbackHandler() {
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
for (Callback current : callbacks) {
if (current instanceof NameCallback) {
NameCallback ncb = (NameCallback) current;
ncb.setName(username);
} else if (current instanceof PasswordCallback) {
PasswordCallback pcb = (PasswordCallback) current;
pcb.setPassword(password.toCharArray());
} else if (current instanceof RealmCallback) {
RealmCallback rcb = (RealmCallback) current;
rcb.setText(rcb.getDefaultText());
} else {
throw new UnsupportedCallbackException(current);
}
}
}
};
return ModelControllerClient.Factory
.create(host, port, callbackHandler);
}
For more information on how to read the data obtained from Server or for the complete project using Java/Google visualizer API (to show the statistics in Graph after every 10 secs) , Please refer to this tutorial -
http://javacodingtutorial.blogspot.com/2014/05/reading-jboss-memory-usage-using-java.html
Add the following to your jboss-deployment-structure
<dependencies>
<module name="org.jboss.remoting3.remoting-jmx" services="import"/>
</dependencies>
Activate JMX remoting subsystem by adding following entry in standalone.xml
<subsystem xmlns="urn:jboss:domain:ee:1.1">
<!-- Activate JMX remoting -->
<global-modules>
<module name="org.jboss.remoting-jmx" slot="main"/>
</global-modules>
...
</subsystem>
It seems like "jboss-client.jar" is not available at run-time for JMX connection, So make sure that you have added "jboss-client.jar" in the class path.
And also you are using deprecated protocol "remoting-jmx" instead of "remote".
i.e, "service:jmx:remote://localhost:9999"
Hope it helps.