From 429bbbbaf14a8016c09f0fba0c8ff347e6270f26 Mon Sep 17 00:00:00 2001 From: db Date: Tue, 26 Jun 2018 01:41:28 +0100 Subject: [PATCH 1/9] Server Sent Events example using Spring Webflux and React --- .../sse/controller/EventController.java | 26 ++++++++++++ .../reactive/sse/model/EventSubscription.java | 22 ++++++++++ .../service/EventSubscriptionsService.java | 41 +++++++++++++++++++ .../service/emitter/DateEmitterService.java | 27 ++++++++++++ .../src/main/resources/static/app.js | 36 ++++++++++++++++ .../src/main/resources/static/sse-index.html | 19 +++++++++ .../reactive/sse/ServerSentEventsTest.java | 39 ++++++++++++++++++ 7 files changed, 210 insertions(+) create mode 100644 spring-5-reactive/src/main/java/com/baeldung/reactive/sse/controller/EventController.java create mode 100644 spring-5-reactive/src/main/java/com/baeldung/reactive/sse/model/EventSubscription.java create mode 100644 spring-5-reactive/src/main/java/com/baeldung/reactive/sse/service/EventSubscriptionsService.java create mode 100644 spring-5-reactive/src/main/java/com/baeldung/reactive/sse/service/emitter/DateEmitterService.java create mode 100644 spring-5-reactive/src/main/resources/static/app.js create mode 100644 spring-5-reactive/src/main/resources/static/sse-index.html create mode 100644 spring-5-reactive/src/test/java/com/baeldung/reactive/sse/ServerSentEventsTest.java diff --git a/spring-5-reactive/src/main/java/com/baeldung/reactive/sse/controller/EventController.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/sse/controller/EventController.java new file mode 100644 index 0000000000..e692aa3a74 --- /dev/null +++ b/spring-5-reactive/src/main/java/com/baeldung/reactive/sse/controller/EventController.java @@ -0,0 +1,26 @@ +package com.baeldung.reactive.sse.controller; + + +import com.baeldung.reactive.sse.service.EventSubscriptionsService; +import org.springframework.http.MediaType; +import org.springframework.http.codec.ServerSentEvent; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Flux; + +@RestController +public class EventController { + + private EventSubscriptionsService eventSubscriptionsService; + + public EventController(EventSubscriptionsService eventSubscriptionsService) { + this.eventSubscriptionsService = eventSubscriptionsService; + } + + @GetMapping( + produces = MediaType.TEXT_EVENT_STREAM_VALUE, + value = "/sse/events") + public Flux events() { + return eventSubscriptionsService.subscribe(); + } +} diff --git a/spring-5-reactive/src/main/java/com/baeldung/reactive/sse/model/EventSubscription.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/sse/model/EventSubscription.java new file mode 100644 index 0000000000..4d3ce27156 --- /dev/null +++ b/spring-5-reactive/src/main/java/com/baeldung/reactive/sse/model/EventSubscription.java @@ -0,0 +1,22 @@ +package com.baeldung.reactive.sse.model; + +import org.springframework.http.codec.ServerSentEvent; +import reactor.core.publisher.DirectProcessor; +import reactor.core.publisher.Flux; + +public class EventSubscription { + + private DirectProcessor directProcessor; + + public EventSubscription() { + this.directProcessor = DirectProcessor.create(); + } + + public void emit(ServerSentEvent e) { + directProcessor.onNext(e); + } + + public Flux subscribe() { + return directProcessor; + } +} diff --git a/spring-5-reactive/src/main/java/com/baeldung/reactive/sse/service/EventSubscriptionsService.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/sse/service/EventSubscriptionsService.java new file mode 100644 index 0000000000..f245ce6184 --- /dev/null +++ b/spring-5-reactive/src/main/java/com/baeldung/reactive/sse/service/EventSubscriptionsService.java @@ -0,0 +1,41 @@ +package com.baeldung.reactive.sse.service; + +import com.baeldung.reactive.sse.model.EventSubscription; +import org.springframework.http.codec.ServerSentEvent; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +@Service +public class EventSubscriptionsService { + + private List listeners; + + public EventSubscriptionsService() { + this.listeners = new ArrayList<>(); + } + + public Flux subscribe() { + EventSubscription e = new EventSubscription(); + listeners.add(e); + + return e.subscribe(); + } + + public void sendDateEvent(Date date) { + for (EventSubscription e : listeners) { + try { + e.emit(ServerSentEvent.builder(date) + .event("date") + .id(UUID.randomUUID().toString()) + .build()); + } catch (Exception ex) { + listeners.remove(e); + } + } + } +} diff --git a/spring-5-reactive/src/main/java/com/baeldung/reactive/sse/service/emitter/DateEmitterService.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/sse/service/emitter/DateEmitterService.java new file mode 100644 index 0000000000..29b70865dc --- /dev/null +++ b/spring-5-reactive/src/main/java/com/baeldung/reactive/sse/service/emitter/DateEmitterService.java @@ -0,0 +1,27 @@ +package com.baeldung.reactive.sse.service.emitter; + +import com.baeldung.reactive.sse.service.EventSubscriptionsService; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Flux; + +import javax.annotation.PostConstruct; +import java.time.Duration; +import java.util.Date; +import java.util.stream.Stream; + +@Service +public class DateEmitterService { + + private EventSubscriptionsService eventSubscriptionsService; + + public DateEmitterService(EventSubscriptionsService eventSubscriptionsService) { + this.eventSubscriptionsService = eventSubscriptionsService; + } + + @PostConstruct + public void init() { + Flux.fromStream(Stream.generate(Date::new)) + .delayElements(Duration.ofSeconds(1)) + .subscribe(data -> eventSubscriptionsService.sendDateEvent(new Date())); + } +} diff --git a/spring-5-reactive/src/main/resources/static/app.js b/spring-5-reactive/src/main/resources/static/app.js new file mode 100644 index 0000000000..2af2ae5844 --- /dev/null +++ b/spring-5-reactive/src/main/resources/static/app.js @@ -0,0 +1,36 @@ +let Clock = React.createClass({ + + getInitialState: function() { + const self = this; + const ev = new EventSource("http://localhost:8080/sse/events"); + + self.setState({currentDate : moment(new Date()).format("MMMM Do YYYY, h:mm:ss a")}); + + ev.addEventListener("date", function(e) { + self.setState({currentDate : moment(JSON.parse(e.data).date).format("MMMM Do YYYY, h:mm:ss a")}); + }, false); + + return {currentDate: moment(new Date()).format("MMMM Do YYYY, h:mm:ss a") }; + }, + + render() { + return ( +

+ Current time: {this.state.currentDate} +

+ ); + } + +}); + +let App = React.createClass({ + render() { + return ( +
+ +
+ ); + } +}); + +ReactDOM.render(, document.getElementById('root') ); \ No newline at end of file diff --git a/spring-5-reactive/src/main/resources/static/sse-index.html b/spring-5-reactive/src/main/resources/static/sse-index.html new file mode 100644 index 0000000000..875c8176af --- /dev/null +++ b/spring-5-reactive/src/main/resources/static/sse-index.html @@ -0,0 +1,19 @@ + + + + + React + Spring + + + +
+ + + + + + + + + + \ No newline at end of file diff --git a/spring-5-reactive/src/test/java/com/baeldung/reactive/sse/ServerSentEventsTest.java b/spring-5-reactive/src/test/java/com/baeldung/reactive/sse/ServerSentEventsTest.java new file mode 100644 index 0000000000..48e8c23c37 --- /dev/null +++ b/spring-5-reactive/src/test/java/com/baeldung/reactive/sse/ServerSentEventsTest.java @@ -0,0 +1,39 @@ +package com.baeldung.reactive.sse; + +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.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.reactive.server.WebTestClient; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class ServerSentEventsTest { + + @Autowired + private WebTestClient webClient; + + @Test + public void contextLoads() { + } + + @Test + public void givenValidRequest_shouldReceiveOk() throws Exception { + + webClient.get().uri("/events").accept(MediaType.TEXT_EVENT_STREAM) + .exchange() + .expectStatus().isOk(); + } + + @Test + public void givenInvalidHttpVerb_shouldReceiveMethodNotAllowedError() throws Exception { + + webClient.post().uri("/events").accept(MediaType.TEXT_EVENT_STREAM) + .exchange() + .expectStatus().isEqualTo(HttpStatus.METHOD_NOT_ALLOWED); + } + +} From 69bb8daf0c0a5532df785670929cf1159107a420 Mon Sep 17 00:00:00 2001 From: db Date: Fri, 13 Jul 2018 22:16:18 +0100 Subject: [PATCH 2/9] spring security custom AuthenticationFailureHandler --- spring-boot-security/pom.xml | 23 ++++- .../SpringBootSecurityApplication.java | 12 +++ .../configuration/SecurityConfiguration.java | 40 +++++++++ .../CustomAuthenticationFailureHandler.java | 28 ++++++ .../form_login/FormLoginIntegrationTest.java | 87 +++++++++++++++++++ 5 files changed, 187 insertions(+), 3 deletions(-) create mode 100644 spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/SpringBootSecurityApplication.java create mode 100644 spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/configuration/SecurityConfiguration.java create mode 100644 spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/security/CustomAuthenticationFailureHandler.java create mode 100644 spring-boot-security/src/test/java/com/baeldung/springbootsecurity/form_login/FormLoginIntegrationTest.java diff --git a/spring-boot-security/pom.xml b/spring-boot-security/pom.xml index 8763c210c8..b10f8e6e47 100644 --- a/spring-boot-security/pom.xml +++ b/spring-boot-security/pom.xml @@ -10,9 +10,10 @@ Spring Boot Security Auto-Configuration - com.baeldung - parent-modules - 1.0.0-SNAPSHOT + org.springframework.boot + spring-boot-starter-parent + 1.5.9.RELEASE + @@ -55,6 +56,11 @@ spring-security-test test + + org.springframework.security + spring-security-test + test + @@ -62,6 +68,16 @@ org.springframework.boot spring-boot-maven-plugin + + + + repackage + + + com.baeldung.springbootsecurity.basic_auth.SpringBootSecurityApplication + + + @@ -69,6 +85,7 @@ UTF-8 UTF-8 + 1.8 diff --git a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/SpringBootSecurityApplication.java b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/SpringBootSecurityApplication.java new file mode 100644 index 0000000000..9f4796e1f9 --- /dev/null +++ b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/SpringBootSecurityApplication.java @@ -0,0 +1,12 @@ +package com.baeldung.springbootsecurity.form_login; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication(scanBasePackages = "com.baeldung.springbootsecurity.form_login") +public class SpringBootSecurityApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringBootSecurityApplication.class, args); + } +} diff --git a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/configuration/SecurityConfiguration.java b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/configuration/SecurityConfiguration.java new file mode 100644 index 0000000000..1f5c53eb2b --- /dev/null +++ b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/configuration/SecurityConfiguration.java @@ -0,0 +1,40 @@ +package com.baeldung.springbootsecurity.form_login.configuration; + +import com.baeldung.springbootsecurity.form_login.security.CustomAuthenticationFailureHandler; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.web.authentication.AuthenticationFailureHandler; + +@Configuration +@EnableWebSecurity +public class SecurityConfiguration extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth + .inMemoryAuthentication() + .withUser("baeldung") + .password("baeldung") + .roles("USER"); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeRequests() + .anyRequest() + .authenticated() + .and() + .formLogin() + .failureHandler(customAuthenticationFailureHandler()); + } + + @Bean + public AuthenticationFailureHandler customAuthenticationFailureHandler() { + return new CustomAuthenticationFailureHandler(); + } +} diff --git a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/security/CustomAuthenticationFailureHandler.java b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/security/CustomAuthenticationFailureHandler.java new file mode 100644 index 0000000000..2617c1f475 --- /dev/null +++ b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/security/CustomAuthenticationFailureHandler.java @@ -0,0 +1,28 @@ +package com.baeldung.springbootsecurity.form_login.security; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.http.HttpStatus; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.AuthenticationFailureHandler; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Calendar; +import java.util.HashMap; +import java.util.Map; + +public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler { + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { + response.setStatus(HttpStatus.UNAUTHORIZED.value()); + Map data = new HashMap<>(); + data.put("timestamp", Calendar.getInstance().getTime()); + data.put("exception", exception.getMessage()); + + response.getOutputStream().println(objectMapper.writeValueAsString(data)); + } +} diff --git a/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/form_login/FormLoginIntegrationTest.java b/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/form_login/FormLoginIntegrationTest.java new file mode 100644 index 0000000000..d5b5d8637b --- /dev/null +++ b/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/form_login/FormLoginIntegrationTest.java @@ -0,0 +1,87 @@ +package com.baeldung.springbootsecurity.form_login; + +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.MvcResult; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import javax.servlet.Filter; + +import static org.junit.Assert.assertTrue; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; +import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated; +import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = com.baeldung.springbootsecurity.form_login.SpringBootSecurityApplication.class) +public class FormLoginIntegrationTest { + + @Autowired + private WebApplicationContext context; + + @Autowired + private Filter springSecurityFilterChain; + + private MockMvc mvc; + + @Before + public void setup() { + mvc = MockMvcBuilders + .webAppContextSetup(context) + .addFilters(springSecurityFilterChain) + .build(); + } + + @Test + public void givenRequestWithoutSessionOrCsrfToken_shouldFailWith403() throws Exception { + mvc + .perform(post("/")) + .andExpect(status().isForbidden()); + } + + @Test + public void givenRequestWithInvalidCsrfToken_shouldFailWith403() throws Exception { + mvc + .perform(post("/").with(csrf().useInvalidToken())) + .andExpect(status().isForbidden()); + } + + @Test + public void givenRequestWithValidCsrfTokenAndWithoutSessionToken_shouldReceive302WithLocationHeaderToLoginPage() throws Exception { + MvcResult mvcResult = mvc.perform(post("/").with(csrf())).andReturn(); + assertTrue(mvcResult.getResponse().getStatus() == 302); + assertTrue(mvcResult.getResponse().getHeader("Location").contains("login")); + } + + @Test + public void givenValidRequestWithValidCredentials_shouldLoginSuccessfully() throws Exception { + mvc + .perform(formLogin().user("baeldung").password("baeldung")) + .andExpect(status().isFound()) + .andExpect(redirectedUrl("/")) + .andExpect(authenticated().withUsername("baeldung")); + } + + @Test + public void givenValidRequestWithInvalidCredentials_shouldFailWith401() throws Exception { + MvcResult result = mvc + .perform(formLogin().user("random").password("random")) + .andExpect(status().isUnauthorized()) + .andDo(print()) + .andExpect(unauthenticated()) + .andReturn(); + + assertTrue(result.getResponse().getContentAsString().contains("Bad credentials")); + } +} From a9a0a3978ec55b695dbf073f768dbe831cf72621 Mon Sep 17 00:00:00 2001 From: db Date: Sat, 14 Jul 2018 16:01:28 +0100 Subject: [PATCH 3/9] refactor --- spring-boot-security/pom.xml | 20 ++++--------- .../configuration/SecurityConfiguration.java | 29 ++++++++++++++++++- .../CustomAuthenticationFailureHandler.java | 28 ------------------ 3 files changed, 33 insertions(+), 44 deletions(-) delete mode 100644 spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/security/CustomAuthenticationFailureHandler.java diff --git a/spring-boot-security/pom.xml b/spring-boot-security/pom.xml index b10f8e6e47..130bd52235 100644 --- a/spring-boot-security/pom.xml +++ b/spring-boot-security/pom.xml @@ -10,10 +10,9 @@ Spring Boot Security Auto-Configuration - org.springframework.boot - spring-boot-starter-parent - 1.5.9.RELEASE - + com.baeldung + parent-modules + 1.0.0-SNAPSHOT @@ -21,7 +20,7 @@ org.springframework.boot spring-boot-dependencies - 1.5.9.RELEASE + ${spring-boot.version} pom import @@ -68,16 +67,6 @@ org.springframework.boot spring-boot-maven-plugin - - - - repackage - - - com.baeldung.springbootsecurity.basic_auth.SpringBootSecurityApplication - - - @@ -86,6 +75,7 @@ UTF-8 UTF-8 1.8 + 1.5.9.RELEASE diff --git a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/configuration/SecurityConfiguration.java b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/configuration/SecurityConfiguration.java index 1f5c53eb2b..6ab522ef00 100644 --- a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/configuration/SecurityConfiguration.java +++ b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/configuration/SecurityConfiguration.java @@ -1,14 +1,24 @@ package com.baeldung.springbootsecurity.form_login.configuration; -import com.baeldung.springbootsecurity.form_login.security.CustomAuthenticationFailureHandler; +import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpStatus; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AuthenticationFailureHandler; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Calendar; +import java.util.HashMap; +import java.util.Map; + @Configuration @EnableWebSecurity public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @@ -37,4 +47,21 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { public AuthenticationFailureHandler customAuthenticationFailureHandler() { return new CustomAuthenticationFailureHandler(); } + + /** + * Custom AuthenticationFailureHandler + */ + public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler { + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { + response.setStatus(HttpStatus.UNAUTHORIZED.value()); + Map data = new HashMap<>(); + data.put("timestamp", Calendar.getInstance().getTime()); + data.put("exception", exception.getMessage()); + + response.getOutputStream().println(objectMapper.writeValueAsString(data)); + } + } } diff --git a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/security/CustomAuthenticationFailureHandler.java b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/security/CustomAuthenticationFailureHandler.java deleted file mode 100644 index 2617c1f475..0000000000 --- a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/security/CustomAuthenticationFailureHandler.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.baeldung.springbootsecurity.form_login.security; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.springframework.http.HttpStatus; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.web.authentication.AuthenticationFailureHandler; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.util.Calendar; -import java.util.HashMap; -import java.util.Map; - -public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler { - private final ObjectMapper objectMapper = new ObjectMapper(); - - @Override - public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { - response.setStatus(HttpStatus.UNAUTHORIZED.value()); - Map data = new HashMap<>(); - data.put("timestamp", Calendar.getInstance().getTime()); - data.put("exception", exception.getMessage()); - - response.getOutputStream().println(objectMapper.writeValueAsString(data)); - } -} From f18ad815a3af6666e4b7ca2c62401e0e5d59fb43 Mon Sep 17 00:00:00 2001 From: db Date: Sat, 14 Jul 2018 16:10:57 +0100 Subject: [PATCH 4/9] moved SSE to branch --- .../sse/controller/EventController.java | 26 ------------ .../reactive/sse/model/EventSubscription.java | 22 ---------- .../service/EventSubscriptionsService.java | 41 ------------------- .../service/emitter/DateEmitterService.java | 27 ------------ .../src/main/resources/static/app.js | 36 ---------------- .../src/main/resources/static/sse-index.html | 19 --------- .../reactive/sse/ServerSentEventsTest.java | 39 ------------------ 7 files changed, 210 deletions(-) delete mode 100644 spring-5-reactive/src/main/java/com/baeldung/reactive/sse/controller/EventController.java delete mode 100644 spring-5-reactive/src/main/java/com/baeldung/reactive/sse/model/EventSubscription.java delete mode 100644 spring-5-reactive/src/main/java/com/baeldung/reactive/sse/service/EventSubscriptionsService.java delete mode 100644 spring-5-reactive/src/main/java/com/baeldung/reactive/sse/service/emitter/DateEmitterService.java delete mode 100644 spring-5-reactive/src/main/resources/static/app.js delete mode 100644 spring-5-reactive/src/main/resources/static/sse-index.html delete mode 100644 spring-5-reactive/src/test/java/com/baeldung/reactive/sse/ServerSentEventsTest.java diff --git a/spring-5-reactive/src/main/java/com/baeldung/reactive/sse/controller/EventController.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/sse/controller/EventController.java deleted file mode 100644 index e692aa3a74..0000000000 --- a/spring-5-reactive/src/main/java/com/baeldung/reactive/sse/controller/EventController.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.baeldung.reactive.sse.controller; - - -import com.baeldung.reactive.sse.service.EventSubscriptionsService; -import org.springframework.http.MediaType; -import org.springframework.http.codec.ServerSentEvent; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; -import reactor.core.publisher.Flux; - -@RestController -public class EventController { - - private EventSubscriptionsService eventSubscriptionsService; - - public EventController(EventSubscriptionsService eventSubscriptionsService) { - this.eventSubscriptionsService = eventSubscriptionsService; - } - - @GetMapping( - produces = MediaType.TEXT_EVENT_STREAM_VALUE, - value = "/sse/events") - public Flux events() { - return eventSubscriptionsService.subscribe(); - } -} diff --git a/spring-5-reactive/src/main/java/com/baeldung/reactive/sse/model/EventSubscription.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/sse/model/EventSubscription.java deleted file mode 100644 index 4d3ce27156..0000000000 --- a/spring-5-reactive/src/main/java/com/baeldung/reactive/sse/model/EventSubscription.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.baeldung.reactive.sse.model; - -import org.springframework.http.codec.ServerSentEvent; -import reactor.core.publisher.DirectProcessor; -import reactor.core.publisher.Flux; - -public class EventSubscription { - - private DirectProcessor directProcessor; - - public EventSubscription() { - this.directProcessor = DirectProcessor.create(); - } - - public void emit(ServerSentEvent e) { - directProcessor.onNext(e); - } - - public Flux subscribe() { - return directProcessor; - } -} diff --git a/spring-5-reactive/src/main/java/com/baeldung/reactive/sse/service/EventSubscriptionsService.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/sse/service/EventSubscriptionsService.java deleted file mode 100644 index f245ce6184..0000000000 --- a/spring-5-reactive/src/main/java/com/baeldung/reactive/sse/service/EventSubscriptionsService.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.baeldung.reactive.sse.service; - -import com.baeldung.reactive.sse.model.EventSubscription; -import org.springframework.http.codec.ServerSentEvent; -import org.springframework.stereotype.Service; -import reactor.core.publisher.Flux; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.UUID; - -@Service -public class EventSubscriptionsService { - - private List listeners; - - public EventSubscriptionsService() { - this.listeners = new ArrayList<>(); - } - - public Flux subscribe() { - EventSubscription e = new EventSubscription(); - listeners.add(e); - - return e.subscribe(); - } - - public void sendDateEvent(Date date) { - for (EventSubscription e : listeners) { - try { - e.emit(ServerSentEvent.builder(date) - .event("date") - .id(UUID.randomUUID().toString()) - .build()); - } catch (Exception ex) { - listeners.remove(e); - } - } - } -} diff --git a/spring-5-reactive/src/main/java/com/baeldung/reactive/sse/service/emitter/DateEmitterService.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/sse/service/emitter/DateEmitterService.java deleted file mode 100644 index 29b70865dc..0000000000 --- a/spring-5-reactive/src/main/java/com/baeldung/reactive/sse/service/emitter/DateEmitterService.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.baeldung.reactive.sse.service.emitter; - -import com.baeldung.reactive.sse.service.EventSubscriptionsService; -import org.springframework.stereotype.Service; -import reactor.core.publisher.Flux; - -import javax.annotation.PostConstruct; -import java.time.Duration; -import java.util.Date; -import java.util.stream.Stream; - -@Service -public class DateEmitterService { - - private EventSubscriptionsService eventSubscriptionsService; - - public DateEmitterService(EventSubscriptionsService eventSubscriptionsService) { - this.eventSubscriptionsService = eventSubscriptionsService; - } - - @PostConstruct - public void init() { - Flux.fromStream(Stream.generate(Date::new)) - .delayElements(Duration.ofSeconds(1)) - .subscribe(data -> eventSubscriptionsService.sendDateEvent(new Date())); - } -} diff --git a/spring-5-reactive/src/main/resources/static/app.js b/spring-5-reactive/src/main/resources/static/app.js deleted file mode 100644 index 2af2ae5844..0000000000 --- a/spring-5-reactive/src/main/resources/static/app.js +++ /dev/null @@ -1,36 +0,0 @@ -let Clock = React.createClass({ - - getInitialState: function() { - const self = this; - const ev = new EventSource("http://localhost:8080/sse/events"); - - self.setState({currentDate : moment(new Date()).format("MMMM Do YYYY, h:mm:ss a")}); - - ev.addEventListener("date", function(e) { - self.setState({currentDate : moment(JSON.parse(e.data).date).format("MMMM Do YYYY, h:mm:ss a")}); - }, false); - - return {currentDate: moment(new Date()).format("MMMM Do YYYY, h:mm:ss a") }; - }, - - render() { - return ( -

- Current time: {this.state.currentDate} -

- ); - } - -}); - -let App = React.createClass({ - render() { - return ( -
- -
- ); - } -}); - -ReactDOM.render(, document.getElementById('root') ); \ No newline at end of file diff --git a/spring-5-reactive/src/main/resources/static/sse-index.html b/spring-5-reactive/src/main/resources/static/sse-index.html deleted file mode 100644 index 875c8176af..0000000000 --- a/spring-5-reactive/src/main/resources/static/sse-index.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - React + Spring - - - -
- - - - - - - - - - \ No newline at end of file diff --git a/spring-5-reactive/src/test/java/com/baeldung/reactive/sse/ServerSentEventsTest.java b/spring-5-reactive/src/test/java/com/baeldung/reactive/sse/ServerSentEventsTest.java deleted file mode 100644 index 48e8c23c37..0000000000 --- a/spring-5-reactive/src/test/java/com/baeldung/reactive/sse/ServerSentEventsTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.baeldung.reactive.sse; - -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.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.reactive.server.WebTestClient; - -@RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -public class ServerSentEventsTest { - - @Autowired - private WebTestClient webClient; - - @Test - public void contextLoads() { - } - - @Test - public void givenValidRequest_shouldReceiveOk() throws Exception { - - webClient.get().uri("/events").accept(MediaType.TEXT_EVENT_STREAM) - .exchange() - .expectStatus().isOk(); - } - - @Test - public void givenInvalidHttpVerb_shouldReceiveMethodNotAllowedError() throws Exception { - - webClient.post().uri("/events").accept(MediaType.TEXT_EVENT_STREAM) - .exchange() - .expectStatus().isEqualTo(HttpStatus.METHOD_NOT_ALLOWED); - } - -} From 509998a7c6b769ee4ff66bbe352d6b9afef47181 Mon Sep 17 00:00:00 2001 From: db Date: Sun, 15 Jul 2018 09:24:32 +0100 Subject: [PATCH 5/9] remove pom properties --- spring-boot-security/pom.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/spring-boot-security/pom.xml b/spring-boot-security/pom.xml index 130bd52235..1f904d0a67 100644 --- a/spring-boot-security/pom.xml +++ b/spring-boot-security/pom.xml @@ -72,9 +72,6 @@ - UTF-8 - UTF-8 - 1.8 1.5.9.RELEASE From aa0af30497bfc2b8699ba5a890d6ba6494f441d6 Mon Sep 17 00:00:00 2001 From: db Date: Wed, 18 Jul 2018 12:40:56 +0100 Subject: [PATCH 6/9] moved AuthenticationFailureHandler example to spring-security-mvc-login --- .../SpringBootSecurityApplication.java | 12 --- .../configuration/SecurityConfiguration.java | 67 -------------- .../form_login/FormLoginIntegrationTest.java | 87 ------------------- .../form_login/FormLoginUnitTest.java | 87 ------------------- .../CustomAuthenticationFailureHandler.java | 22 +++++ .../baeldung/spring/SecSecurityConfig.java | 51 ++++++----- .../src/main/resources/webSecurityConfig.xml | 8 +- .../baeldung/security/FormLoginUnitTest.java | 63 ++++++++++++++ 8 files changed, 119 insertions(+), 278 deletions(-) delete mode 100644 spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/SpringBootSecurityApplication.java delete mode 100644 spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/configuration/SecurityConfiguration.java delete mode 100644 spring-boot-security/src/test/java/com/baeldung/springbootsecurity/form_login/FormLoginIntegrationTest.java delete mode 100644 spring-boot-security/src/test/java/com/baeldung/springbootsecurity/form_login/FormLoginUnitTest.java create mode 100644 spring-security-mvc-login/src/main/java/org/baeldung/security/CustomAuthenticationFailureHandler.java create mode 100644 spring-security-mvc-login/src/test/java/org/baeldung/security/FormLoginUnitTest.java diff --git a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/SpringBootSecurityApplication.java b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/SpringBootSecurityApplication.java deleted file mode 100644 index 9f4796e1f9..0000000000 --- a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/SpringBootSecurityApplication.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.baeldung.springbootsecurity.form_login; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication(scanBasePackages = "com.baeldung.springbootsecurity.form_login") -public class SpringBootSecurityApplication { - - public static void main(String[] args) { - SpringApplication.run(SpringBootSecurityApplication.class, args); - } -} diff --git a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/configuration/SecurityConfiguration.java b/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/configuration/SecurityConfiguration.java deleted file mode 100644 index 6ab522ef00..0000000000 --- a/spring-boot-security/src/main/java/com/baeldung/springbootsecurity/form_login/configuration/SecurityConfiguration.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.baeldung.springbootsecurity.form_login.configuration; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpStatus; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.web.authentication.AuthenticationFailureHandler; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.util.Calendar; -import java.util.HashMap; -import java.util.Map; - -@Configuration -@EnableWebSecurity -public class SecurityConfiguration extends WebSecurityConfigurerAdapter { - - @Override - protected void configure(AuthenticationManagerBuilder auth) throws Exception { - auth - .inMemoryAuthentication() - .withUser("baeldung") - .password("baeldung") - .roles("USER"); - } - - @Override - protected void configure(HttpSecurity http) throws Exception { - http - .authorizeRequests() - .anyRequest() - .authenticated() - .and() - .formLogin() - .failureHandler(customAuthenticationFailureHandler()); - } - - @Bean - public AuthenticationFailureHandler customAuthenticationFailureHandler() { - return new CustomAuthenticationFailureHandler(); - } - - /** - * Custom AuthenticationFailureHandler - */ - public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler { - private final ObjectMapper objectMapper = new ObjectMapper(); - - @Override - public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { - response.setStatus(HttpStatus.UNAUTHORIZED.value()); - Map data = new HashMap<>(); - data.put("timestamp", Calendar.getInstance().getTime()); - data.put("exception", exception.getMessage()); - - response.getOutputStream().println(objectMapper.writeValueAsString(data)); - } - } -} diff --git a/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/form_login/FormLoginIntegrationTest.java b/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/form_login/FormLoginIntegrationTest.java deleted file mode 100644 index d5b5d8637b..0000000000 --- a/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/form_login/FormLoginIntegrationTest.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.baeldung.springbootsecurity.form_login; - -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.MvcResult; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; - -import javax.servlet.Filter; - -import static org.junit.Assert.assertTrue; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; -import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated; -import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = com.baeldung.springbootsecurity.form_login.SpringBootSecurityApplication.class) -public class FormLoginIntegrationTest { - - @Autowired - private WebApplicationContext context; - - @Autowired - private Filter springSecurityFilterChain; - - private MockMvc mvc; - - @Before - public void setup() { - mvc = MockMvcBuilders - .webAppContextSetup(context) - .addFilters(springSecurityFilterChain) - .build(); - } - - @Test - public void givenRequestWithoutSessionOrCsrfToken_shouldFailWith403() throws Exception { - mvc - .perform(post("/")) - .andExpect(status().isForbidden()); - } - - @Test - public void givenRequestWithInvalidCsrfToken_shouldFailWith403() throws Exception { - mvc - .perform(post("/").with(csrf().useInvalidToken())) - .andExpect(status().isForbidden()); - } - - @Test - public void givenRequestWithValidCsrfTokenAndWithoutSessionToken_shouldReceive302WithLocationHeaderToLoginPage() throws Exception { - MvcResult mvcResult = mvc.perform(post("/").with(csrf())).andReturn(); - assertTrue(mvcResult.getResponse().getStatus() == 302); - assertTrue(mvcResult.getResponse().getHeader("Location").contains("login")); - } - - @Test - public void givenValidRequestWithValidCredentials_shouldLoginSuccessfully() throws Exception { - mvc - .perform(formLogin().user("baeldung").password("baeldung")) - .andExpect(status().isFound()) - .andExpect(redirectedUrl("/")) - .andExpect(authenticated().withUsername("baeldung")); - } - - @Test - public void givenValidRequestWithInvalidCredentials_shouldFailWith401() throws Exception { - MvcResult result = mvc - .perform(formLogin().user("random").password("random")) - .andExpect(status().isUnauthorized()) - .andDo(print()) - .andExpect(unauthenticated()) - .andReturn(); - - assertTrue(result.getResponse().getContentAsString().contains("Bad credentials")); - } -} diff --git a/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/form_login/FormLoginUnitTest.java b/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/form_login/FormLoginUnitTest.java deleted file mode 100644 index d518f3b0c2..0000000000 --- a/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/form_login/FormLoginUnitTest.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.baeldung.springbootsecurity.form_login; - -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.MvcResult; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; - -import javax.servlet.Filter; - -import static org.junit.Assert.assertTrue; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; -import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated; -import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = com.baeldung.springbootsecurity.form_login.SpringBootSecurityApplication.class) -public class FormLoginUnitTest { - - @Autowired - private WebApplicationContext context; - - @Autowired - private Filter springSecurityFilterChain; - - private MockMvc mvc; - - @Before - public void setup() { - mvc = MockMvcBuilders - .webAppContextSetup(context) - .addFilters(springSecurityFilterChain) - .build(); - } - - @Test - public void givenRequestWithoutSessionOrCsrfToken_shouldFailWith403() throws Exception { - mvc - .perform(post("/")) - .andExpect(status().isForbidden()); - } - - @Test - public void givenRequestWithInvalidCsrfToken_shouldFailWith403() throws Exception { - mvc - .perform(post("/").with(csrf().useInvalidToken())) - .andExpect(status().isForbidden()); - } - - @Test - public void givenRequestWithValidCsrfTokenAndWithoutSessionToken_shouldReceive302WithLocationHeaderToLoginPage() throws Exception { - MvcResult mvcResult = mvc.perform(post("/").with(csrf())).andReturn(); - assertTrue(mvcResult.getResponse().getStatus() == 302); - assertTrue(mvcResult.getResponse().getHeader("Location").contains("login")); - } - - @Test - public void givenValidRequestWithValidCredentials_shouldLoginSuccessfully() throws Exception { - mvc - .perform(formLogin().user("baeldung").password("baeldung")) - .andExpect(status().isFound()) - .andExpect(redirectedUrl("/")) - .andExpect(authenticated().withUsername("baeldung")); - } - - @Test - public void givenValidRequestWithInvalidCredentials_shouldFailWith401() throws Exception { - MvcResult result = mvc - .perform(formLogin().user("random").password("random")) - .andExpect(status().isUnauthorized()) - .andDo(print()) - .andExpect(unauthenticated()) - .andReturn(); - - assertTrue(result.getResponse().getContentAsString().contains("Bad credentials")); - } -} diff --git a/spring-security-mvc-login/src/main/java/org/baeldung/security/CustomAuthenticationFailureHandler.java b/spring-security-mvc-login/src/main/java/org/baeldung/security/CustomAuthenticationFailureHandler.java new file mode 100644 index 0000000000..5eddf3883e --- /dev/null +++ b/spring-security-mvc-login/src/main/java/org/baeldung/security/CustomAuthenticationFailureHandler.java @@ -0,0 +1,22 @@ +package org.baeldung.security; + +import org.springframework.http.HttpStatus; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.AuthenticationFailureHandler; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Calendar; + +public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler { + + @Override + public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException { + httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value()); + + String jsonPayload = "{\"message\" : \"%s\", \"timestamp\" : \"%s\" }"; + httpServletResponse.getOutputStream().println(String.format(jsonPayload, e.getMessage(), Calendar.getInstance().getTime())); + } +} diff --git a/spring-security-mvc-login/src/main/java/org/baeldung/spring/SecSecurityConfig.java b/spring-security-mvc-login/src/main/java/org/baeldung/spring/SecSecurityConfig.java index d9a43d48d0..accc7c9afd 100644 --- a/spring-security-mvc-login/src/main/java/org/baeldung/spring/SecSecurityConfig.java +++ b/spring-security-mvc-login/src/main/java/org/baeldung/spring/SecSecurityConfig.java @@ -1,6 +1,7 @@ package org.baeldung.spring; import org.baeldung.security.CustomAccessDeniedHandler; +import org.baeldung.security.CustomAuthenticationFailureHandler; import org.baeldung.security.CustomLogoutSuccessHandler; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -10,6 +11,7 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; @Configuration @@ -26,11 +28,11 @@ public class SecSecurityConfig extends WebSecurityConfigurerAdapter { protected void configure(final AuthenticationManagerBuilder auth) throws Exception { // @formatter:off auth.inMemoryAuthentication() - .withUser("user1").password("user1Pass").roles("USER") - .and() - .withUser("user2").password("user2Pass").roles("USER") - .and() - .withUser("admin").password("adminPass").roles("ADMIN"); + .withUser("user1").password("user1Pass").roles("USER") + .and() + .withUser("user2").password("user2Pass").roles("USER") + .and() + .withUser("admin").password("adminPass").roles("ADMIN"); // @formatter:on } @@ -38,23 +40,24 @@ public class SecSecurityConfig extends WebSecurityConfigurerAdapter { protected void configure(final HttpSecurity http) throws Exception { // @formatter:off http - .csrf().disable() - .authorizeRequests() - .antMatchers("/admin/**").hasRole("ADMIN") - .antMatchers("/anonymous*").anonymous() - .antMatchers("/login*").permitAll() - .anyRequest().authenticated() - .and() - .formLogin() - .loginPage("/login.html") - .loginProcessingUrl("/perform_login") - .defaultSuccessUrl("/homepage.html",true) - .failureUrl("/login.html?error=true") - .and() - .logout() - .logoutUrl("/perform_logout") - .deleteCookies("JSESSIONID") - .logoutSuccessHandler(logoutSuccessHandler()); + .csrf().disable() + .authorizeRequests() + .antMatchers("/admin/**").hasRole("ADMIN") + .antMatchers("/anonymous*").anonymous() + .antMatchers("/login*").permitAll() + .anyRequest().authenticated() + .and() + .formLogin() + .loginPage("/login.html") + .loginProcessingUrl("/perform_login") + .defaultSuccessUrl("/homepage.html", true) + //.failureUrl("/login.html?error=true") + .failureHandler(authenticationFailureHandler()) + .and() + .logout() + .logoutUrl("/perform_logout") + .deleteCookies("JSESSIONID") + .logoutSuccessHandler(logoutSuccessHandler()); //.and() //.exceptionHandling().accessDeniedPage("/accessDenied"); //.exceptionHandling().accessDeniedHandler(accessDeniedHandler()); @@ -71,4 +74,8 @@ public class SecSecurityConfig extends WebSecurityConfigurerAdapter { return new CustomAccessDeniedHandler(); } + @Bean + public AuthenticationFailureHandler authenticationFailureHandler() { + return new CustomAuthenticationFailureHandler(); + } } diff --git a/spring-security-mvc-login/src/main/resources/webSecurityConfig.xml b/spring-security-mvc-login/src/main/resources/webSecurityConfig.xml index f0fa956934..189522889f 100644 --- a/spring-security-mvc-login/src/main/resources/webSecurityConfig.xml +++ b/spring-security-mvc-login/src/main/resources/webSecurityConfig.xml @@ -15,20 +15,22 @@ - + - + + + diff --git a/spring-security-mvc-login/src/test/java/org/baeldung/security/FormLoginUnitTest.java b/spring-security-mvc-login/src/test/java/org/baeldung/security/FormLoginUnitTest.java new file mode 100644 index 0000000000..4b3a091e6c --- /dev/null +++ b/spring-security-mvc-login/src/test/java/org/baeldung/security/FormLoginUnitTest.java @@ -0,0 +1,63 @@ +package org.baeldung.security; + +import org.baeldung.spring.SecSecurityConfig; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import javax.servlet.Filter; + +import static org.junit.Assert.assertTrue; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin; +import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = {SecSecurityConfig.class}) +@WebAppConfiguration +public class FormLoginUnitTest { + + @Autowired + private WebApplicationContext context; + + @Autowired + private Filter springSecurityFilterChain; + + private MockMvc mvc; + + @Before + public void setup() { + mvc = MockMvcBuilders + .webAppContextSetup(context) + .addFilters(springSecurityFilterChain) + .build(); + } + + @Test + public void givenValidRequestWithValidCredentials_shouldLoginSuccessfully() throws Exception { + mvc + .perform(formLogin("/perform_login").user("user1").password("user1Pass")) + .andExpect(status().isFound()) + .andExpect(authenticated().withUsername("user1")); + } + + @Test + public void givenValidRequestWithInvalidCredentials_shouldFailWith401() throws Exception { + MvcResult result = mvc + .perform(formLogin("/perform_login").user("random").password("random")).andReturn(); + /*.andExpect(status().isUnauthorized()) + .andDo(print()) + .andExpect(unauthenticated()) + .andReturn();*/ + + assertTrue(result.getResponse().getContentAsString().contains("Bad credentials")); + } +} From 2a773d637cb456908990a7aec1c0b7eedf24d62a Mon Sep 17 00:00:00 2001 From: db Date: Fri, 27 Jul 2018 02:33:14 +0100 Subject: [PATCH 7/9] PrincipalExtractor and AuthoritiesExtractor example --- spring-security-sso/pom.xml | 1 + .../pom.xml | 53 +++++++++++++++++++ .../main/java/org/baeldung/Application.java | 18 +++++++ .../configuration/SecurityConfig.java | 38 +++++++++++++ .../extractor/CustomAuthoritiesExtractor.java | 27 ++++++++++ .../extractor/CustomPrincipalExtractor.java | 13 +++++ .../src/main/resources/application.yml | 14 +++++ .../src/main/resources/templates/index.html | 21 ++++++++ .../src/test/java/ApplicationUnitTest.java | 53 +++++++++++++++++++ 9 files changed, 238 insertions(+) create mode 100644 spring-security-sso/spring-security-principal-authorities-extractor/pom.xml create mode 100644 spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/Application.java create mode 100644 spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/configuration/SecurityConfig.java create mode 100644 spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/extractor/CustomAuthoritiesExtractor.java create mode 100644 spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/extractor/CustomPrincipalExtractor.java create mode 100644 spring-security-sso/spring-security-principal-authorities-extractor/src/main/resources/application.yml create mode 100644 spring-security-sso/spring-security-principal-authorities-extractor/src/main/resources/templates/index.html create mode 100644 spring-security-sso/spring-security-principal-authorities-extractor/src/test/java/ApplicationUnitTest.java diff --git a/spring-security-sso/pom.xml b/spring-security-sso/pom.xml index 764e899640..0cf468c2e3 100644 --- a/spring-security-sso/pom.xml +++ b/spring-security-sso/pom.xml @@ -19,6 +19,7 @@ spring-security-sso-auth-server spring-security-sso-ui spring-security-sso-ui-2 + spring-security-principal-authorities-extractor diff --git a/spring-security-sso/spring-security-principal-authorities-extractor/pom.xml b/spring-security-sso/spring-security-principal-authorities-extractor/pom.xml new file mode 100644 index 0000000000..5bd8de9c16 --- /dev/null +++ b/spring-security-sso/spring-security-principal-authorities-extractor/pom.xml @@ -0,0 +1,53 @@ + + + + spring-security-sso + org.baeldung + 1.0.0-SNAPSHOT + + 4.0.0 + + spring-security-principal-authorities-extractor + + + + org.springframework.boot + spring-boot-starter-security + + + + org.springframework.security.oauth.boot + spring-security-oauth2-autoconfigure + ${oauth-auto.version} + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + org.thymeleaf.extras + thymeleaf-extras-springsecurity4 + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.security + spring-security-test + test + + + \ No newline at end of file diff --git a/spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/Application.java b/spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/Application.java new file mode 100644 index 0000000000..0dfbbef86e --- /dev/null +++ b/spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/Application.java @@ -0,0 +1,18 @@ +package org.baeldung; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; + +@SpringBootApplication +public class Application { + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + + @GetMapping("/") + public String homePage(Model model) { + return "index"; + } +} diff --git a/spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/configuration/SecurityConfig.java b/spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/configuration/SecurityConfig.java new file mode 100644 index 0000000000..4de1932392 --- /dev/null +++ b/spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/configuration/SecurityConfig.java @@ -0,0 +1,38 @@ +package org.baeldung.configuration; + +import org.baeldung.extractor.CustomAuthoritiesExtractor; +import org.baeldung.extractor.CustomPrincipalExtractor; +import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso; +import org.springframework.boot.autoconfigure.security.oauth2.resource.AuthoritiesExtractor; +import org.springframework.boot.autoconfigure.security.oauth2.resource.PrincipalExtractor; +import org.springframework.context.annotation.Bean; +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 +@EnableOAuth2Sso +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.antMatcher("/**") + .authorizeRequests() + .antMatchers("/login**") + .permitAll() + .anyRequest() + .authenticated() + .and() + .formLogin().disable(); + } + + @Bean + public PrincipalExtractor principalExtractor() { + return new CustomPrincipalExtractor(); + } + + @Bean + public AuthoritiesExtractor authoritiesExtractor() { + return new CustomAuthoritiesExtractor(); + } +} diff --git a/spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/extractor/CustomAuthoritiesExtractor.java b/spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/extractor/CustomAuthoritiesExtractor.java new file mode 100644 index 0000000000..c1a78634aa --- /dev/null +++ b/spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/extractor/CustomAuthoritiesExtractor.java @@ -0,0 +1,27 @@ +package org.baeldung.extractor; + +import org.springframework.boot.autoconfigure.security.oauth2.resource.AuthoritiesExtractor; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.AuthorityUtils; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public class CustomAuthoritiesExtractor implements AuthoritiesExtractor { + private static final List GITHUB_FREE_AUTHORITIES = AuthorityUtils.commaSeparatedStringToAuthorityList("GITHUB_USER,GITHUB_USER_FREE"); + private static final List GITHUB_SUBSCRIBED_AUTHORITIES = AuthorityUtils.commaSeparatedStringToAuthorityList("GITHUB_USER,GITHUB_USER_SUBSCRIBED"); + + @Override + public List extractAuthorities(Map map) { + if (Objects.nonNull(map.get("plan"))) { + if (!((LinkedHashMap) map.get("plan")) + .get("name") + .equals("free")) { + return GITHUB_SUBSCRIBED_AUTHORITIES; + } + } + return GITHUB_FREE_AUTHORITIES; + } +} diff --git a/spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/extractor/CustomPrincipalExtractor.java b/spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/extractor/CustomPrincipalExtractor.java new file mode 100644 index 0000000000..d356c07e3b --- /dev/null +++ b/spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/extractor/CustomPrincipalExtractor.java @@ -0,0 +1,13 @@ +package org.baeldung.extractor; + +import org.springframework.boot.autoconfigure.security.oauth2.resource.PrincipalExtractor; + +import java.util.Map; + +public class CustomPrincipalExtractor implements PrincipalExtractor { + + @Override + public Object extractPrincipal(Map map) { + return map.get("login"); + } +} diff --git a/spring-security-sso/spring-security-principal-authorities-extractor/src/main/resources/application.yml b/spring-security-sso/spring-security-principal-authorities-extractor/src/main/resources/application.yml new file mode 100644 index 0000000000..324df694df --- /dev/null +++ b/spring-security-sso/spring-security-principal-authorities-extractor/src/main/resources/application.yml @@ -0,0 +1,14 @@ +security: + oauth2: + client: + clientId: 89a7c4facbb3434d599d + clientSecret: 9b3b08e4a340bd20e866787e4645b54f73d74b6a + accessTokenUri: https://github.com/login/oauth/access_token + userAuthorizationUri: https://github.com/login/oauth/authorize + clientAuthenticationScheme: form + scope: read:user,user:email + resource: + userInfoUri: https://api.github.com/user +spring: + thymeleaf: + cache: false \ No newline at end of file diff --git a/spring-security-sso/spring-security-principal-authorities-extractor/src/main/resources/templates/index.html b/spring-security-sso/spring-security-principal-authorities-extractor/src/main/resources/templates/index.html new file mode 100644 index 0000000000..414dd54a42 --- /dev/null +++ b/spring-security-sso/spring-security-principal-authorities-extractor/src/main/resources/templates/index.html @@ -0,0 +1,21 @@ + + + + + Spring Security Principal and Authorities extractor + + + + +
+
+

Secured Page

+ Authenticated username: +
+ Authorities: +
+
+
+ + \ No newline at end of file diff --git a/spring-security-sso/spring-security-principal-authorities-extractor/src/test/java/ApplicationUnitTest.java b/spring-security-sso/spring-security-principal-authorities-extractor/src/test/java/ApplicationUnitTest.java new file mode 100644 index 0000000000..c14cbc9866 --- /dev/null +++ b/spring-security-sso/spring-security-principal-authorities-extractor/src/test/java/ApplicationUnitTest.java @@ -0,0 +1,53 @@ +import org.baeldung.Application; +import org.baeldung.configuration.SecurityConfig; +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.ContextConfiguration; +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 javax.servlet.Filter; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ContextConfiguration(classes = {SecurityConfig.class}) +public class ApplicationUnitTest { + + @Autowired + private WebApplicationContext context; + + @Autowired + private Filter springSecurityFilterChain; + + private MockMvc mvc; + + @Before + public void setup() { + mvc = MockMvcBuilders + .webAppContextSetup(context) + .addFilters(springSecurityFilterChain) + .build(); + } + + @Test + public void contextLoads() throws Exception { + } + + @Test + public void givenValidRequestWithoutAuthentication_shouldFailWith302() throws Exception { + mvc + .perform(get("/")) + .andExpect(status().isFound()) + .andReturn(); + } + +} From d1f2917c3394157323a5b3668833953193228052 Mon Sep 17 00:00:00 2001 From: db Date: Sat, 28 Jul 2018 13:06:41 +0100 Subject: [PATCH 8/9] moved PrincipalExtractor and AuthoritiesExtractor example to spring-5-security module --- spring-5-security/pom.xml | 7 +++ .../ExtractorsApplication.java | 20 +++++++ .../configuration/SecurityConfig.java | 10 ++-- .../extractor/CustomAuthoritiesExtractor.java | 8 +-- .../extractor/CustomPrincipalExtractor.java | 2 +- .../application-oauth2-extractors.properties | 6 +++ .../templates/oauth2_extractors.html | 0 .../oauth2extractors/ExtractorsUnitTest.java | 9 ++-- spring-security-sso/pom.xml | 1 - .../pom.xml | 53 ------------------- .../main/java/org/baeldung/Application.java | 18 ------- .../src/main/resources/application.yml | 14 ----- 12 files changed, 50 insertions(+), 98 deletions(-) create mode 100644 spring-5-security/src/main/java/com/baeldung/oauth2extractors/ExtractorsApplication.java rename {spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung => spring-5-security/src/main/java/com/baeldung/oauth2extractors}/configuration/SecurityConfig.java (79%) rename {spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung => spring-5-security/src/main/java/com/baeldung/oauth2extractors}/extractor/CustomAuthoritiesExtractor.java (67%) rename {spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung => spring-5-security/src/main/java/com/baeldung/oauth2extractors}/extractor/CustomPrincipalExtractor.java (86%) create mode 100644 spring-5-security/src/main/resources/application-oauth2-extractors.properties rename spring-security-sso/spring-security-principal-authorities-extractor/src/main/resources/templates/index.html => spring-5-security/src/main/resources/templates/oauth2_extractors.html (100%) rename spring-security-sso/spring-security-principal-authorities-extractor/src/test/java/ApplicationUnitTest.java => spring-5-security/src/test/java/com/baeldung/oauth2extractors/ExtractorsUnitTest.java (85%) delete mode 100644 spring-security-sso/spring-security-principal-authorities-extractor/pom.xml delete mode 100644 spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/Application.java delete mode 100644 spring-security-sso/spring-security-principal-authorities-extractor/src/main/resources/application.yml diff --git a/spring-5-security/pom.xml b/spring-5-security/pom.xml index 8cca2ed916..d0ea46928f 100644 --- a/spring-5-security/pom.xml +++ b/spring-5-security/pom.xml @@ -58,6 +58,13 @@ spring-security-test test + + + + org.springframework.security.oauth.boot + spring-security-oauth2-autoconfigure + 2.0.1.RELEASE + diff --git a/spring-5-security/src/main/java/com/baeldung/oauth2extractors/ExtractorsApplication.java b/spring-5-security/src/main/java/com/baeldung/oauth2extractors/ExtractorsApplication.java new file mode 100644 index 0000000000..c9a18d1599 --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/oauth2extractors/ExtractorsApplication.java @@ -0,0 +1,20 @@ +package com.baeldung.oauth2extractors; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; + +@SpringBootApplication +@Controller +public class ExtractorsApplication { + public static void main(String[] args) { + SpringApplication.run(ExtractorsApplication.class, args); + } + + @RequestMapping("/") + public String index() { + return "oauth2_extractors"; + } + +} diff --git a/spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/configuration/SecurityConfig.java b/spring-5-security/src/main/java/com/baeldung/oauth2extractors/configuration/SecurityConfig.java similarity index 79% rename from spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/configuration/SecurityConfig.java rename to spring-5-security/src/main/java/com/baeldung/oauth2extractors/configuration/SecurityConfig.java index 4de1932392..cc1258d14b 100644 --- a/spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/configuration/SecurityConfig.java +++ b/spring-5-security/src/main/java/com/baeldung/oauth2extractors/configuration/SecurityConfig.java @@ -1,16 +1,18 @@ -package org.baeldung.configuration; +package com.baeldung.oauth2extractors.configuration; -import org.baeldung.extractor.CustomAuthoritiesExtractor; -import org.baeldung.extractor.CustomPrincipalExtractor; +import com.baeldung.oauth2extractors.extractor.CustomAuthoritiesExtractor; +import com.baeldung.oauth2extractors.extractor.CustomPrincipalExtractor; import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso; import org.springframework.boot.autoconfigure.security.oauth2.resource.AuthoritiesExtractor; import org.springframework.boot.autoconfigure.security.oauth2.resource.PrincipalExtractor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @Configuration +@PropertySource("application-oauth2-extractors.properties") @EnableOAuth2Sso public class SecurityConfig extends WebSecurityConfigurerAdapter { @@ -35,4 +37,4 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { public AuthoritiesExtractor authoritiesExtractor() { return new CustomAuthoritiesExtractor(); } -} +} \ No newline at end of file diff --git a/spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/extractor/CustomAuthoritiesExtractor.java b/spring-5-security/src/main/java/com/baeldung/oauth2extractors/extractor/CustomAuthoritiesExtractor.java similarity index 67% rename from spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/extractor/CustomAuthoritiesExtractor.java rename to spring-5-security/src/main/java/com/baeldung/oauth2extractors/extractor/CustomAuthoritiesExtractor.java index c1a78634aa..ad23f6c32f 100644 --- a/spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/extractor/CustomAuthoritiesExtractor.java +++ b/spring-5-security/src/main/java/com/baeldung/oauth2extractors/extractor/CustomAuthoritiesExtractor.java @@ -1,4 +1,4 @@ -package org.baeldung.extractor; +package com.baeldung.oauth2extractors.extractor; import org.springframework.boot.autoconfigure.security.oauth2.resource.AuthoritiesExtractor; import org.springframework.security.core.GrantedAuthority; @@ -10,8 +10,10 @@ import java.util.Map; import java.util.Objects; public class CustomAuthoritiesExtractor implements AuthoritiesExtractor { - private static final List GITHUB_FREE_AUTHORITIES = AuthorityUtils.commaSeparatedStringToAuthorityList("GITHUB_USER,GITHUB_USER_FREE"); - private static final List GITHUB_SUBSCRIBED_AUTHORITIES = AuthorityUtils.commaSeparatedStringToAuthorityList("GITHUB_USER,GITHUB_USER_SUBSCRIBED"); + private List GITHUB_FREE_AUTHORITIES = AuthorityUtils + .commaSeparatedStringToAuthorityList("GITHUB_USER,GITHUB_USER_FREE"); + private List GITHUB_SUBSCRIBED_AUTHORITIES = AuthorityUtils + .commaSeparatedStringToAuthorityList("GITHUB_USER,GITHUB_USER_SUBSCRIBED"); @Override public List extractAuthorities(Map map) { diff --git a/spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/extractor/CustomPrincipalExtractor.java b/spring-5-security/src/main/java/com/baeldung/oauth2extractors/extractor/CustomPrincipalExtractor.java similarity index 86% rename from spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/extractor/CustomPrincipalExtractor.java rename to spring-5-security/src/main/java/com/baeldung/oauth2extractors/extractor/CustomPrincipalExtractor.java index d356c07e3b..c35522f0f3 100644 --- a/spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/extractor/CustomPrincipalExtractor.java +++ b/spring-5-security/src/main/java/com/baeldung/oauth2extractors/extractor/CustomPrincipalExtractor.java @@ -1,4 +1,4 @@ -package org.baeldung.extractor; +package com.baeldung.oauth2extractors.extractor; import org.springframework.boot.autoconfigure.security.oauth2.resource.PrincipalExtractor; diff --git a/spring-5-security/src/main/resources/application-oauth2-extractors.properties b/spring-5-security/src/main/resources/application-oauth2-extractors.properties new file mode 100644 index 0000000000..51d6ee7d6e --- /dev/null +++ b/spring-5-security/src/main/resources/application-oauth2-extractors.properties @@ -0,0 +1,6 @@ +security.oauth2.client.client-id=89a7c4facbb3434d599d +security.oauth2.client.client-secret=9b3b08e4a340bd20e866787e4645b54f73d74b6a +security.oauth2.client.access-token-uri=https://github.com/login/oauth/access_token +security.oauth2.client.user-authorization-uri=https://github.com/login/oauth/authorize +security.oauth2.client.scope=read:user,user:email +security.oauth2.resource.user-info-uri=https://api.github.com/user \ No newline at end of file diff --git a/spring-security-sso/spring-security-principal-authorities-extractor/src/main/resources/templates/index.html b/spring-5-security/src/main/resources/templates/oauth2_extractors.html similarity index 100% rename from spring-security-sso/spring-security-principal-authorities-extractor/src/main/resources/templates/index.html rename to spring-5-security/src/main/resources/templates/oauth2_extractors.html diff --git a/spring-security-sso/spring-security-principal-authorities-extractor/src/test/java/ApplicationUnitTest.java b/spring-5-security/src/test/java/com/baeldung/oauth2extractors/ExtractorsUnitTest.java similarity index 85% rename from spring-security-sso/spring-security-principal-authorities-extractor/src/test/java/ApplicationUnitTest.java rename to spring-5-security/src/test/java/com/baeldung/oauth2extractors/ExtractorsUnitTest.java index c14cbc9866..164bc4933f 100644 --- a/spring-security-sso/spring-security-principal-authorities-extractor/src/test/java/ApplicationUnitTest.java +++ b/spring-5-security/src/test/java/com/baeldung/oauth2extractors/ExtractorsUnitTest.java @@ -1,5 +1,6 @@ -import org.baeldung.Application; -import org.baeldung.configuration.SecurityConfig; +package com.baeldung.oauth2extractors; + +import com.baeldung.oauth2extractors.configuration.SecurityConfig; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -18,9 +19,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @RunWith(SpringRunner.class) -@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@SpringBootTest(classes = ExtractorsApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @ContextConfiguration(classes = {SecurityConfig.class}) -public class ApplicationUnitTest { +public class ExtractorsUnitTest { @Autowired private WebApplicationContext context; diff --git a/spring-security-sso/pom.xml b/spring-security-sso/pom.xml index 0cf468c2e3..764e899640 100644 --- a/spring-security-sso/pom.xml +++ b/spring-security-sso/pom.xml @@ -19,7 +19,6 @@ spring-security-sso-auth-server spring-security-sso-ui spring-security-sso-ui-2 - spring-security-principal-authorities-extractor diff --git a/spring-security-sso/spring-security-principal-authorities-extractor/pom.xml b/spring-security-sso/spring-security-principal-authorities-extractor/pom.xml deleted file mode 100644 index 5bd8de9c16..0000000000 --- a/spring-security-sso/spring-security-principal-authorities-extractor/pom.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - spring-security-sso - org.baeldung - 1.0.0-SNAPSHOT - - 4.0.0 - - spring-security-principal-authorities-extractor - - - - org.springframework.boot - spring-boot-starter-security - - - - org.springframework.security.oauth.boot - spring-security-oauth2-autoconfigure - ${oauth-auto.version} - - - - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.boot - spring-boot-starter-thymeleaf - - - - org.thymeleaf.extras - thymeleaf-extras-springsecurity4 - - - - org.springframework.boot - spring-boot-starter-test - test - - - - org.springframework.security - spring-security-test - test - - - \ No newline at end of file diff --git a/spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/Application.java b/spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/Application.java deleted file mode 100644 index 0dfbbef86e..0000000000 --- a/spring-security-sso/spring-security-principal-authorities-extractor/src/main/java/org/baeldung/Application.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.baeldung; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; - -@SpringBootApplication -public class Application { - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } - - @GetMapping("/") - public String homePage(Model model) { - return "index"; - } -} diff --git a/spring-security-sso/spring-security-principal-authorities-extractor/src/main/resources/application.yml b/spring-security-sso/spring-security-principal-authorities-extractor/src/main/resources/application.yml deleted file mode 100644 index 324df694df..0000000000 --- a/spring-security-sso/spring-security-principal-authorities-extractor/src/main/resources/application.yml +++ /dev/null @@ -1,14 +0,0 @@ -security: - oauth2: - client: - clientId: 89a7c4facbb3434d599d - clientSecret: 9b3b08e4a340bd20e866787e4645b54f73d74b6a - accessTokenUri: https://github.com/login/oauth/access_token - userAuthorizationUri: https://github.com/login/oauth/authorize - clientAuthenticationScheme: form - scope: read:user,user:email - resource: - userInfoUri: https://api.github.com/user -spring: - thymeleaf: - cache: false \ No newline at end of file From 9940bf29608ce6cb0acafe046f30f77a96db0e90 Mon Sep 17 00:00:00 2001 From: db Date: Sat, 28 Jul 2018 13:09:46 +0100 Subject: [PATCH 9/9] removed comment on pom --- spring-5-security/pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/spring-5-security/pom.xml b/spring-5-security/pom.xml index d0ea46928f..7024e6f873 100644 --- a/spring-5-security/pom.xml +++ b/spring-5-security/pom.xml @@ -59,7 +59,6 @@ test - org.springframework.security.oauth.boot spring-security-oauth2-autoconfigure