Problem Spring Boot Admin Server not display Applications - spring-boot-admin

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

Related

org.apache.shiro.web.filter.authc.LogoutFilter is already configured in ShiroWebModule

I'm using Shiro 1.7.1 and Guice 4.2.3, below is the snippet of my POM file,
<properties>
<shiro.version>1.7.1</shiro.version>
<guice.version>4.2.3</guice.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-guice</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>${guice.version}</version>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-servlet</artifactId>
<version>${guice.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
...
</dependencies>
I'm customizing Shiro's LogoutFilter by creating a new class,
package com.myshiro.myshiro;
import org.apache.shiro.web.filter.authc.LogoutFilter;
public class MyLogoutFilter extends LogoutFilter {
}
and bind org.apache.shiro.web.filter.authc.LogoutFilter to the above customized MyLogoutFilter,
package com.myshiro.myshiro;
public class MyShiroModule extends ShiroWebModule {
public MyShiroModule(ServletContext servletContext) {
super(servletContext);
}
protected void configureShiroWeb() {
try {
bindRealm().toConstructor(IniRealm.class.getConstructor(Ini.class));
} catch (NoSuchMethodException e) {
addError(e);
}
bind(org.apache.shiro.web.filter.authc.LogoutFilter.class).to(MyLogoutFilter.class).in(Scopes.SINGLETON);
addFilterChain("/logout", LOGOUT);
}
}
and I try to create the Guice injector in the unit test class like this,
public class MyShiroModuleTest {
#Mock
private ServletContext servletContext;
#Test
public void test() {
Guice.createInjector(new MyShiroModule(servletContext));
}
}
and it failed with the following errors,
1) Binding to null instances is not allowed. Use toProvider(Providers.of(null)) if this is your intended behaviour.
at org.apache.shiro.guice.web.ShiroWebModule.configureShiro(ShiroWebModule.java:136)
2) A binding to org.apache.shiro.web.filter.authc.LogoutFilter was already configured at com.myshiro.myshiro.MyShiroModule.configureShiroWeb(MyShiroModule.java:25).
at org.apache.shiro.guice.web.ShiroWebModule.setupFilterChainConfigs(ShiroWebModule.java:209)
From the second note above, it explained that the binding to org.apache.shiro.web.filter.authc.LogoutFilter is already configured in both MyShiroModule and ShiroWebModule. Do you have any idea of how to bind to my customized LogoutFilter?
This issue did not happened in Shiro 1.3.x.
My sample project is available here, you can see the error simply when you mvn clean install.
Sounds like your problem is related to Guice 4, and less about Shiro. Instead of re-using the same binding key, define a new one, something like:
bind(MyLogoutFilter.class).to(MyLogoutFilter.class).in(Scopes.SINGLETON);
addFilterChain("/logout", Key.get(MyLogoutFilter.class));

How to integrate Keycloak with Spring boot(API) without login page

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

Apache Camel routing API call to message queue

I have two applications that talk to each other using a REST API.
I would like to know if I can use Apache Camel as a proxy that could "persist" the API calls, for example storing them as messages in ActiveMQ, and then later route the requests to the actual API endpoint.
Practically, I would like to use Apache Camel to "enhance" the API endpoints adding persistence, throttling of requests, etc...
What component do you suggest to use?
You can always try to bridge your HTTP request into a queue, but making the thread wait by forcing the exchangePattern to InOut.
See this example :
import org.apache.activemq.broker.BrokerService;
import org.apache.camel.LoggingLevel;
import org.apache.camel.builder.RouteBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger logger = LoggerFactory.getLogger(SimpleRouteBuilder.class);
public static void main(String[] args) throws Exception {
org.apache.camel.main.Main main = new org.apache.camel.main.Main();
main.addRouteBuilder(new SimpleRouteBuilder());
logger.info("Next call is blocking, ctrl-c to exit\n");
main.run();
}
}
class SimpleRouteBuilder extends RouteBuilder {
private static final Logger logger = LoggerFactory.getLogger(SimpleRouteBuilder.class);
public void configure() throws Exception {
// launching an activemq in background
final BrokerService broker = new BrokerService();
broker.setBrokerName("activemq");
broker.addConnector("tcp://localhost:61616");
Runnable runnable = () -> {
try {
broker.start();
} catch (Exception e) {
e.printStackTrace();
}
};
runnable.run();
// receiving http request but queuing them
from("jetty:http://127.0.0.1:10000/input")
.log(LoggingLevel.INFO, logger, "received request")
.to("activemq:queue:persist?exchangePattern=InOut"); // InOut has to be forced with JMS
// dequeuing and calling backend
from("activemq:queue:persist")
.log(LoggingLevel.INFO, logger,"requesting to destination")
.removeHeaders("CamelHttp*")
.setHeader("Cache-Control",constant("private, max-age=0,no-store"))
.to("jetty:http://perdu.com?httpMethod=GET");
}
}
If you are using maven, here is the 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>be.jschoreels.camel</groupId>
<artifactId>camel-simple</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>2.19.2</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jms</artifactId>
<version>2.19.2</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jetty</artifactId>
<version>2.19.2</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-camel</artifactId>
<version>5.15.3</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.15.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.activemq/activemq-kahadb-store -->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-kahadb-store</artifactId>
<version>5.15.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</project>

Spring Cloud Ribbon: Load balancer rule configuration doesn't work

Here is my application.properties:
spring.application.name=person
server.port=8080
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
# this line of config doesn't work
person.ribbon.NFLoadBalancerRuleClassName=asdfasdfasdf
By setting person.ribbon.NFLoadBalancerRuleClassName to asdfasdfasdf there should be some errors shown in console output but there's none, which means this config doesn't work. I cannot tell what's going on.
Here are the dependencies:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
</dependencies>
The version of spring-cloud is Brixton.SR3,
I successfully configured Ribbon with following configuration class:
#Configuration
#RibbonClient(name = "person", configuration = RibbonConfiguration.RibbonConfig.class)
public class RibbonConfiguration {
static class RibbonConfig {
#Bean
public IRule rule() {
return new WeightedResponseTimeRule();
}
}
}

spring boot with java + groovy _maven in embedded tomcat, controller but error

Sorry if this is already answered, I am not able to find it.
I have created new project using spring boot.
My requirements are that I have some java classes, some groovy classes and they should be able to call each others.
I am using maven and running my embedded tomcat by
mvn spring-boot:run
Problem is, RestController which is Java Class is there and I am able to call it REST URL.
But the controller which is in Groovy, is not able to be called and gives me error.
curl localhost:8080/
{"timestamp":1455913384508,"status":404,"error":"Not Found","message":"No message available","path":"/"}
Good part is that I am able to call groovy class from java.
Below are my files.
<?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>
<groupId>org.springframework</groupId>
<artifactId>gs-spring-boot</artifactId>
<version>0.1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.3.7</version>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<!-- 2.8.0-01 and later require maven-compiler-plugin 3.1 or higher -->
<version>3.1</version>
<configuration>
<compilerId>groovy-eclipse-compiler</compilerId>
</configuration>
<dependencies>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-eclipse-compiler</artifactId>
<version>2.9.1-01</version>
</dependency>
<!-- for 2.8.0-01 and later you must have an explicit dependency on
groovy-eclipse-batch -->
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-eclipse-batch</artifactId>
<version>2.3.7-01</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
app.groovy:
package hello
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
#RestController
class ThisWillActuallyRun {
#RequestMapping("/home")
String home() {
return "Hello World!"
}
}
Application.java
package hello;
import java.util.Arrays;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
System.out.println("Let's inspect the beans provided by Spring Boot:");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
}
}
Controller class
package hello;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
#RestController
public class HelloController {
#RequestMapping("/hello")
public String index() {
ThisWillActuallyRun t = new ThisWillActuallyRun() ;
String v = t.home() ;
System.out.println("value from groovy="+v) ;
return "Greetings from Spring Boot!";
}
}
This works:
curl localhost:8080/hello
Greetings from Spring Boot!
Thanks a lot for the help.
I don't see a problem with your Groovy controller ThisWillActuallyRun
One concern I would have is that you have 2 separate controllers, but did not provide a #RequestMapping(path="controllerpath") at the top of your class on each controller. You did not specify a unique context (relative path) to your controller.
In addition, your curl command only goes to "/". I don't see any mapping for that.
It may work if you curl to "/home", just like you did for "/hello". Regardless, it is a better practice to give a controller level path as well.
An example of how the URL would look if you annotated the #RequestMapping at the top of your 2 controllers might look like:
#RestController
#RequestMapping(path="destination")
class ThisWillActuallyRun {
#RequestMapping("/home")
String home() { }
}
#RestController
#RequestMapping(path="greeting")
public class HelloController {
#RequestMapping("/hello")
public String index() {}
}
Then to reach the 2 endpoints would look like:
http://localhost:8080/destination/home
http://localhost:8080/greeting/hello