Add CAS Gateway sample
Closes gh-174
This commit is contained in:
@@ -17,6 +17,8 @@ services:
|
||||
--server.port=8080
|
||||
--cas.service-registry.core.init-from-json=true
|
||||
--cas.service-registry.json.location=file:/etc/cas/services
|
||||
--cas.tgc.secure=false
|
||||
--cas.tgc.sameSitePolicy=Lax
|
||||
volumes:
|
||||
- ./services/http-1.json:/etc/cas/services/http-1.json
|
||||
networks:
|
||||
|
||||
@@ -5,6 +5,8 @@ plugins {
|
||||
id 'java'
|
||||
}
|
||||
|
||||
ext['spring-security.version'] = '6.3.0-SNAPSHOT'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url "https://repo.spring.io/milestone" }
|
||||
|
||||
@@ -38,4 +38,9 @@ public class IndexController {
|
||||
return "loggedout";
|
||||
}
|
||||
|
||||
@GetMapping("/public")
|
||||
String publicPage() {
|
||||
return "public";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ import org.springframework.security.cas.ServiceProperties;
|
||||
import org.springframework.security.cas.authentication.CasAuthenticationProvider;
|
||||
import org.springframework.security.cas.web.CasAuthenticationEntryPoint;
|
||||
import org.springframework.security.cas.web.CasAuthenticationFilter;
|
||||
import org.springframework.security.cas.web.CasGatewayAuthenticationRedirectFilter;
|
||||
import org.springframework.security.cas.web.CasGatewayResolverRequestMatcher;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
@@ -38,6 +40,9 @@ import org.springframework.security.core.userdetails.UserDetailsByNameServiceWra
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
@Configuration
|
||||
public class SecurityConfig {
|
||||
@@ -52,14 +57,30 @@ public class SecurityConfig {
|
||||
private ServletWebServerApplicationContext context;
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http, UserDetailsService userDetailsService) throws Exception {
|
||||
http.authorizeHttpRequests((authorize) -> authorize.requestMatchers(HttpMethod.GET, "/loggedout").permitAll()
|
||||
.anyRequest().authenticated())
|
||||
public SecurityFilterChain filterChain(HttpSecurity http, UserDetailsService userDetailsService,
|
||||
MvcRequestMatcher.Builder builder) throws Exception {
|
||||
// @formatter:off
|
||||
CasGatewayAuthenticationRedirectFilter casGatewayAuthenticationRedirectFilter = new CasGatewayAuthenticationRedirectFilter(this.casLoginUrl, serviceProperties());
|
||||
casGatewayAuthenticationRedirectFilter.setRequestMatcher(new AndRequestMatcher(
|
||||
builder.pattern("/public"), new CasGatewayResolverRequestMatcher(serviceProperties())));
|
||||
http
|
||||
.authorizeHttpRequests((authorize) -> authorize
|
||||
.requestMatchers(HttpMethod.GET, "/loggedout").permitAll()
|
||||
.requestMatchers("/public").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.exceptionHandling((exceptions) -> exceptions.authenticationEntryPoint(casAuthenticationEntryPoint()))
|
||||
.logout((logout) -> logout.logoutSuccessUrl("/loggedout"))
|
||||
.addFilter(casAuthenticationFilter(userDetailsService))
|
||||
.addFilterBefore(new SingleSignOutFilter(), CasAuthenticationFilter.class);
|
||||
.addFilterBefore(new SingleSignOutFilter(), CasAuthenticationFilter.class)
|
||||
.addFilterAfter(casGatewayAuthenticationRedirectFilter, CasAuthenticationFilter.class);
|
||||
return http.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
MvcRequestMatcher.Builder mvcRequestMatcherBuilder(HandlerMappingIntrospector introspector) {
|
||||
return new MvcRequestMatcher.Builder(introspector);
|
||||
}
|
||||
|
||||
public CasAuthenticationProvider casAuthenticationProvider(UserDetailsService userDetailsService) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
cas.base.url=http://localhost:8090/cas
|
||||
server.port=8081
|
||||
cas.base.url=http://localhost.example:8090/cas
|
||||
cas.login.url=${cas.base.url}/login
|
||||
cas.logout.url=${cas.base.url}/logout
|
||||
service.base.url=http://localhost:8080
|
||||
service.base.url=http://localhost:8081
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<!doctype html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org" xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
|
||||
<head>
|
||||
<title>Spring Security - CAS Login & Logout</title>
|
||||
<meta charset="utf-8" />
|
||||
<style>
|
||||
span, dt {
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<main role="main" class="container-fluid">
|
||||
<h1 class="mt-5">This is a public page that performs a CAS Gateway Authentication</h1>
|
||||
<p class="lead">You are successfully logged in as <span sec:authentication="name"></span></p>
|
||||
|
||||
<h6>Visit the <a href="https://github.com/apereo/cas" target="_blank">Apereo CAS</a> documentation for more details.</h6>
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -29,8 +29,10 @@ import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.test.context.DynamicPropertyRegistry;
|
||||
import org.springframework.test.context.DynamicPropertySource;
|
||||
|
||||
@@ -43,11 +45,15 @@ class CasLoginApplicationTests {
|
||||
@LocalServerPort
|
||||
int port;
|
||||
|
||||
@Autowired
|
||||
Environment environment;
|
||||
|
||||
@Container
|
||||
static GenericContainer<?> casServer = new GenericContainer<>(DockerImageName.parse("apereo/cas:6.6.6"))
|
||||
.withCommand("--cas.standalone.configuration-directory=/etc/cas/config", "--server.ssl.enabled=false",
|
||||
"--server.port=8080", "--cas.service-registry.core.init-from-json=true",
|
||||
"--cas.service-registry.json.location=file:/etc/cas/services")
|
||||
"--cas.service-registry.json.location=file:/etc/cas/services", "--cas.tgc.secure=false",
|
||||
"--cas.tgc.sameSitePolicy=Lax")
|
||||
.withExposedPorts(8080).withClasspathResourceMapping("cas/services/https-1.json",
|
||||
"/etc/cas/services/https-1.json", BindMode.READ_WRITE)
|
||||
.waitingFor(Wait.forLogMessage(".*Ready to process requests.*", 1));
|
||||
@@ -92,4 +98,19 @@ class CasLoginApplicationTests {
|
||||
assertThat(logoutMsg).isEqualTo("You are successfully logged out of the app, but not CAS");
|
||||
}
|
||||
|
||||
@Test
|
||||
void publicPageWhenCasGatewayAuthenticationThenAuthenticated() {
|
||||
doCasLogin();
|
||||
Selenide.open("http://localhost:" + this.port + "/public");
|
||||
String lead = Selenide.$(By.className("lead")).text();
|
||||
assertThat(lead).isEqualTo("You are successfully logged in as casuser");
|
||||
}
|
||||
|
||||
private void doCasLogin() {
|
||||
Selenide.open(this.environment.getProperty("cas.login.url"));
|
||||
Selenide.$(By.name("username")).setValue("casuser");
|
||||
Selenide.$(By.name("password")).setValue("Mellon");
|
||||
Selenide.$(By.name("submitBtn")).click();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user