diff --git a/spring-boot-admin/README.md b/spring-boot-admin/README.md new file mode 100644 index 0000000000..4cea3f0611 --- /dev/null +++ b/spring-boot-admin/README.md @@ -0,0 +1 @@ +Spring Boot Admin \ No newline at end of file diff --git a/spring-boot-admin/spring-boot-admin-client/.gitignore b/spring-boot-admin/spring-boot-admin-client/.gitignore new file mode 100644 index 0000000000..2af7cefb0a --- /dev/null +++ b/spring-boot-admin/spring-boot-admin-client/.gitignore @@ -0,0 +1,24 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +nbproject/private/ +build/ +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ \ No newline at end of file diff --git a/spring-boot-admin/spring-boot-admin-client/pom.xml b/spring-boot-admin/spring-boot-admin-client/pom.xml new file mode 100644 index 0000000000..ecb6c3f8b6 --- /dev/null +++ b/spring-boot-admin/spring-boot-admin-client/pom.xml @@ -0,0 +1,71 @@ + + + 4.0.0 + + com.baeldung + spring-boot-admin-client + 0.0.1-SNAPSHOT + jar + + spring-boot-admin-client + Demo project for Spring Boot + + + org.springframework.boot + spring-boot-starter-parent + 1.5.8.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + 1.5.4 + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-security + + + de.codecentric + spring-boot-admin-starter-client + ${spring-boot-admin-starter-client.version} + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + build-info + + + + + + + + + diff --git a/spring-boot-admin/spring-boot-admin-client/src/main/java/com/baeldung/springbootadminclient/SpringBootAdminClientApplication.java b/spring-boot-admin/spring-boot-admin-client/src/main/java/com/baeldung/springbootadminclient/SpringBootAdminClientApplication.java new file mode 100644 index 0000000000..596da131a6 --- /dev/null +++ b/spring-boot-admin/spring-boot-admin-client/src/main/java/com/baeldung/springbootadminclient/SpringBootAdminClientApplication.java @@ -0,0 +1,12 @@ +package com.baeldung.springbootadminclient; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringBootAdminClientApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringBootAdminClientApplication.class, args); + } +} diff --git a/spring-boot-admin/spring-boot-admin-client/src/main/resources/application.properties b/spring-boot-admin/spring-boot-admin-client/src/main/resources/application.properties new file mode 100644 index 0000000000..58c178ecd9 --- /dev/null +++ b/spring-boot-admin/spring-boot-admin-client/src/main/resources/application.properties @@ -0,0 +1,16 @@ +#basic auth creddentials +security.user.name=client +security.user.password=client + +#configs to connect to a secured server +spring.boot.admin.url=http://localhost:8080 +spring.boot.admin.username=admin +spring.boot.admin.password=admin + +#configs to give secured server info +spring.boot.admin.client.metadata.user.name=${security.user.name} +spring.boot.admin.client.metadata.user.password=${security.user.password} + +#app config +spring.application.name=spring-boot-admin-client +server.port=8081 \ No newline at end of file diff --git a/spring-boot-admin/spring-boot-admin-client/src/main/resources/logback.xml b/spring-boot-admin/spring-boot-admin-client/src/main/resources/logback.xml new file mode 100644 index 0000000000..ff96acae79 --- /dev/null +++ b/spring-boot-admin/spring-boot-admin-client/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + + %date [%thread] %-5level %logger{25} - %msg%n + + + + + + + \ No newline at end of file diff --git a/spring-boot-admin/spring-boot-admin-client/src/test/java/com/baeldung/springbootadminclient/SpringBootAdminClientApplicationTests.java b/spring-boot-admin/spring-boot-admin-client/src/test/java/com/baeldung/springbootadminclient/SpringBootAdminClientApplicationTests.java new file mode 100644 index 0000000000..d70fb1c7cf --- /dev/null +++ b/spring-boot-admin/spring-boot-admin-client/src/test/java/com/baeldung/springbootadminclient/SpringBootAdminClientApplicationTests.java @@ -0,0 +1,55 @@ +package com.baeldung.springbootadminclient; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.core.env.Environment; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import static org.junit.Assert.assertEquals; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = RANDOM_PORT) +public class SpringBootAdminClientApplicationTests { + + @Autowired Environment environment; + + @Autowired WebApplicationContext wac; + + private MockMvc mockMvc; + + @Before + public void setup() { + mockMvc = MockMvcBuilders + .webAppContextSetup(wac) + .build(); + } + + @Test + public void whenEnvironmentAvailable_ThenAdminServerPropertiesExist() { + assertEquals(environment.getProperty("spring.boot.admin.url"), "http://localhost:8080"); + assertEquals(environment.getProperty("spring.boot.admin.username"), "admin"); + assertEquals(environment.getProperty("spring.boot.admin.password"), "admin"); + } + + @Test + public void whenHttpBasicAttempted_ThenSuccess() throws Exception { + mockMvc.perform(get("/env").with(httpBasic("client", "client"))); + } + + @Test + public void whenInvalidHttpBasicAttempted_ThenUnauthorized() throws Exception { + mockMvc + .perform(get("/env").with(httpBasic("client", "invalid"))) + .andExpect(status().isUnauthorized()); + } +} diff --git a/spring-boot-admin/spring-boot-admin-server/.gitignore b/spring-boot-admin/spring-boot-admin-server/.gitignore new file mode 100644 index 0000000000..2af7cefb0a --- /dev/null +++ b/spring-boot-admin/spring-boot-admin-server/.gitignore @@ -0,0 +1,24 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +nbproject/private/ +build/ +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ \ No newline at end of file diff --git a/spring-boot-admin/spring-boot-admin-server/pom.xml b/spring-boot-admin/spring-boot-admin-server/pom.xml new file mode 100644 index 0000000000..b199e63b31 --- /dev/null +++ b/spring-boot-admin/spring-boot-admin-server/pom.xml @@ -0,0 +1,95 @@ + + + 4.0.0 + + com.baeldung + spring-boot-admin-server + 0.0.1-SNAPSHOT + jar + + spring-boot-admin-server + Demo project for Spring Boot + + + org.springframework.boot + spring-boot-starter-parent + 1.5.8.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + 1.5.4 + 1.5.4 + + + + + org.springframework.boot + spring-boot-starter + + + + + de.codecentric + spring-boot-admin-server + ${spring-boot-admin-server.version} + + + de.codecentric + spring-boot-admin-server-ui + ${spring-boot-admin-server.version} + + + + + de.codecentric + spring-boot-admin-server-ui-login + ${spring-boot-admin-server.version} + + + org.springframework.boot + spring-boot-starter-security + + + com.hazelcast + hazelcast + + + + de.codecentric + spring-boot-admin-starter-client + ${spring-boot-admin-starter-client.version} + + + + + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/spring-boot-admin/spring-boot-admin-server/src/main/java/com/baeldung/springbootadminserver/SpringBootAdminServerApplication.java b/spring-boot-admin/spring-boot-admin-server/src/main/java/com/baeldung/springbootadminserver/SpringBootAdminServerApplication.java new file mode 100644 index 0000000000..d1fb4e769b --- /dev/null +++ b/spring-boot-admin/spring-boot-admin-server/src/main/java/com/baeldung/springbootadminserver/SpringBootAdminServerApplication.java @@ -0,0 +1,14 @@ +package com.baeldung.springbootadminserver; + +import de.codecentric.boot.admin.config.EnableAdminServer; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@EnableAdminServer +@SpringBootApplication +public class SpringBootAdminServerApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringBootAdminServerApplication.class, args); + } +} diff --git a/spring-boot-admin/spring-boot-admin-server/src/main/java/com/baeldung/springbootadminserver/configs/HazelcastConfig.java b/spring-boot-admin/spring-boot-admin-server/src/main/java/com/baeldung/springbootadminserver/configs/HazelcastConfig.java new file mode 100644 index 0000000000..b19b7820af --- /dev/null +++ b/spring-boot-admin/spring-boot-admin-server/src/main/java/com/baeldung/springbootadminserver/configs/HazelcastConfig.java @@ -0,0 +1,24 @@ +package com.baeldung.springbootadminserver.configs; + +import com.hazelcast.config.Config; +import com.hazelcast.config.EvictionPolicy; +import com.hazelcast.config.ListConfig; +import com.hazelcast.config.MapConfig; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class HazelcastConfig { + + @Bean + public Config hazelcast() { + return new Config() + .setProperty("hazelcast.jmx", "true") + .addMapConfig(new MapConfig("spring-boot-admin-application-store") + .setBackupCount(1) + .setEvictionPolicy(EvictionPolicy.NONE)) + .addListConfig(new ListConfig("spring-boot-admin-event-store") + .setBackupCount(1) + .setMaxSize(1000)); + } +} diff --git a/spring-boot-admin/spring-boot-admin-server/src/main/java/com/baeldung/springbootadminserver/configs/NotifierConfiguration.java b/spring-boot-admin/spring-boot-admin-server/src/main/java/com/baeldung/springbootadminserver/configs/NotifierConfiguration.java new file mode 100644 index 0000000000..10a31464ab --- /dev/null +++ b/spring-boot-admin/spring-boot-admin-server/src/main/java/com/baeldung/springbootadminserver/configs/NotifierConfiguration.java @@ -0,0 +1,42 @@ +package com.baeldung.springbootadminserver.configs; + +import de.codecentric.boot.admin.notify.LoggingNotifier; +import de.codecentric.boot.admin.notify.RemindingNotifier; +import de.codecentric.boot.admin.notify.filter.FilteringNotifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; + +import java.util.concurrent.TimeUnit; + +@Configuration +@EnableScheduling +public class NotifierConfiguration { + + // @Autowired private Notifier notifier; + + @Bean + public LoggingNotifier notifier() { + return new LoggingNotifier(); + } + + @Bean + public FilteringNotifier filteringNotifier() { + return new FilteringNotifier(notifier()); + } + + @Bean + @Primary + public RemindingNotifier remindingNotifier() { + RemindingNotifier remindingNotifier = new RemindingNotifier(filteringNotifier()); + remindingNotifier.setReminderPeriod(TimeUnit.MINUTES.toMillis(5)); + return remindingNotifier; + } + + @Scheduled(fixedRate = 60_000L) + public void remind() { + remindingNotifier().sendReminders(); + } +} diff --git a/spring-boot-admin/spring-boot-admin-server/src/main/java/com/baeldung/springbootadminserver/configs/WebSecurityConfig.java b/spring-boot-admin/spring-boot-admin-server/src/main/java/com/baeldung/springbootadminserver/configs/WebSecurityConfig.java new file mode 100644 index 0000000000..4a7c8330b7 --- /dev/null +++ b/spring-boot-admin/spring-boot-admin-server/src/main/java/com/baeldung/springbootadminserver/configs/WebSecurityConfig.java @@ -0,0 +1,33 @@ +package com.baeldung.springbootadminserver.configs; + +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@Configuration +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .formLogin() + .loginPage("/login.html") + .loginProcessingUrl("/login") + .permitAll(); + http + .logout() + .logoutUrl("/logout"); + http + .csrf() + .disable(); + http + .authorizeRequests() + .antMatchers("/login.html", "/**/*.css", "/img/**", "/third-party/**") + .permitAll(); + http + .authorizeRequests() + .antMatchers("/**") + .authenticated(); + http.httpBasic(); + } +} diff --git a/spring-boot-admin/spring-boot-admin-server/src/main/resources/application.properties b/spring-boot-admin/spring-boot-admin-server/src/main/resources/application.properties new file mode 100644 index 0000000000..362f6428e8 --- /dev/null +++ b/spring-boot-admin/spring-boot-admin-server/src/main/resources/application.properties @@ -0,0 +1,28 @@ +spring.application.name=spring-boot-admin-server + +security.user.name=admin +security.user.password=admin + +#configs to connect to self register the admin server as a client +spring.boot.admin.url=http://localhost:8080 +spring.boot.admin.username=${security.user.name} +spring.boot.admin.password=${security.user.password} + +#configs to give secured server info +spring.boot.admin.client.metadata.user.name=${security.user.name} +spring.boot.admin.client.metadata.user.password=${security.user.password} + +#mail notifications +#spring.mail.host=smtp.gmail.com +#spring.mail.username=test@gmail.com +#spring.mail.password=password +#spring.mail.port=587 +#spring.mail.properties.mail.smtp.auth=true +#spring.mail.properties.mail.smtp.starttls.enable=true + +#spring.boot.admin.notify.mail.to=test@gmail.com + +#hipchat notifications +#spring.boot.admin.notify.hipchat.auth-token= +#spring.boot.admin.notify.hipchat.room-id= +#spring.boot.admin.notify.hipchat.url=https://youcompany.hipchat.com/v2/ \ No newline at end of file diff --git a/spring-boot-admin/spring-boot-admin-server/src/main/resources/logback.xml b/spring-boot-admin/spring-boot-admin-server/src/main/resources/logback.xml new file mode 100644 index 0000000000..ff96acae79 --- /dev/null +++ b/spring-boot-admin/spring-boot-admin-server/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + + %date [%thread] %-5level %logger{25} - %msg%n + + + + + + + \ No newline at end of file diff --git a/spring-boot-admin/spring-boot-admin-server/src/test/java/com/baeldung/springbootadminserver/HazelcastConfigTest.java b/spring-boot-admin/spring-boot-admin-server/src/test/java/com/baeldung/springbootadminserver/HazelcastConfigTest.java new file mode 100644 index 0000000000..8ca50a6f75 --- /dev/null +++ b/spring-boot-admin/spring-boot-admin-server/src/test/java/com/baeldung/springbootadminserver/HazelcastConfigTest.java @@ -0,0 +1,24 @@ +package com.baeldung.springbootadminserver; + +import com.baeldung.springbootadminserver.configs.HazelcastConfig; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.junit.Assert.assertNotEquals; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = { HazelcastConfig.class }, webEnvironment = NONE) +public class HazelcastConfigTest { + + @Autowired private ApplicationContext applicationContext; + + @Test + public void whenApplicationContextStarts_HazelcastConfigBeanExists() { + assertNotEquals(applicationContext.getBean("hazelcast"), null); + } +} diff --git a/spring-boot-admin/spring-boot-admin-server/src/test/java/com/baeldung/springbootadminserver/NotifierConfigurationTest.java b/spring-boot-admin/spring-boot-admin-server/src/test/java/com/baeldung/springbootadminserver/NotifierConfigurationTest.java new file mode 100644 index 0000000000..85f6b374a4 --- /dev/null +++ b/spring-boot-admin/spring-boot-admin-server/src/test/java/com/baeldung/springbootadminserver/NotifierConfigurationTest.java @@ -0,0 +1,41 @@ +package com.baeldung.springbootadminserver; + +import com.baeldung.springbootadminserver.configs.NotifierConfiguration; +import de.codecentric.boot.admin.notify.Notifier; +import de.codecentric.boot.admin.notify.RemindingNotifier; +import de.codecentric.boot.admin.notify.filter.FilteringNotifier; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.junit.Assert.assertNotEquals; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = { NotifierConfiguration.class }, webEnvironment = NONE) +public class NotifierConfigurationTest { + + @Autowired private ApplicationContext applicationContext; + + @Test + public void whenApplicationContextStart_ThenNotifierBeanExists() { + Notifier notifier = (Notifier) applicationContext.getBean("notifier"); + assertNotEquals(notifier, null); + } + + @Test + public void whenApplicationContextStart_ThenFilteringNotifierBeanExists() { + FilteringNotifier filteringNotifier = (FilteringNotifier) applicationContext.getBean("filteringNotifier"); + assertNotEquals(filteringNotifier, null); + } + + @Test + public void whenApplicationContextStart_ThenRemindingNotifierBeanExists() { + RemindingNotifier remindingNotifier = (RemindingNotifier) applicationContext.getBean("remindingNotifier"); + assertNotEquals(remindingNotifier, null); + } + +} diff --git a/spring-boot-admin/spring-boot-admin-server/src/test/java/com/baeldung/springbootadminserver/WebSecurityConfigTest.java b/spring-boot-admin/spring-boot-admin-server/src/test/java/com/baeldung/springbootadminserver/WebSecurityConfigTest.java new file mode 100644 index 0000000000..40611f00f6 --- /dev/null +++ b/spring-boot-admin/spring-boot-admin-server/src/test/java/com/baeldung/springbootadminserver/WebSecurityConfigTest.java @@ -0,0 +1,71 @@ +package com.baeldung.springbootadminserver; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class WebSecurityConfigTest { + + @Autowired WebApplicationContext wac; + + private MockMvc mockMvc; + + @Before + public void setup() { + mockMvc = MockMvcBuilders + .webAppContextSetup(wac) + .build(); + } + + @Test + public void whenApplicationStarts_ThenGetLoginPageWithSuccess() throws Exception { + mockMvc + .perform(get("/login.html")) + .andExpect(status().is2xxSuccessful()); + } + + @Test + public void whenFormLoginAttempted_ThenSuccess() throws Exception { + mockMvc.perform(formLogin("/login") + .user("admin") + .password("admin")); + } + + @Test + public void whenFormLoginWithSuccess_ThenApiEndpointsAreAccessible() throws Exception { + mockMvc.perform(formLogin("/login") + .user("admin") + .password("admin")); + + mockMvc + .perform(get("/api/applications/")) + .andExpect(status().is2xxSuccessful()); + + } + + @Test + public void whenHttpBasicAttempted_ThenSuccess() throws Exception { + mockMvc.perform(get("/env").with(httpBasic("admin", "admin"))); + } + + @Test + public void whenInvalidHttpBasicAttempted_ThenUnauthorized() throws Exception { + mockMvc + .perform(get("/env").with(httpBasic("admin", "invalid"))) + .andExpect(status().isUnauthorized()); + } + +}