Skip to content

Commit c908095

Browse files
Merge branch 'main' into gh-34
2 parents d78f8ba + c35ba7b commit c908095

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+3842
-40
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 the original author or authors.
2+
* Copyright 2020-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,60 +21,50 @@
2121

2222
import javax.servlet.http.HttpServletRequest;
2323

24-
import org.springframework.beans.factory.annotation.Value;
2524
import org.springframework.context.annotation.Bean;
25+
import org.springframework.context.annotation.Configuration;
2626
import org.springframework.security.authentication.AuthenticationManager;
2727
import org.springframework.security.authentication.AuthenticationManagerResolver;
28+
import org.springframework.security.authentication.ProviderManager;
2829
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
29-
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
30-
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
3130
import org.springframework.security.oauth2.jwt.JwtDecoder;
32-
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
3331
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider;
3432
import org.springframework.security.oauth2.server.resource.authentication.JwtBearerTokenAuthenticationConverter;
3533
import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenAuthenticationProvider;
36-
import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector;
3734
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
35+
import org.springframework.security.web.SecurityFilterChain;
3836

3937
/**
4038
* OAuth Resource Security configuration.
4139
*
4240
* @author Josh Cummings
4341
*/
44-
@EnableWebSecurity
45-
public class OAuth2ResourceServerSecurityConfiguration extends WebSecurityConfigurerAdapter {
42+
@Configuration
43+
public class OAuth2ResourceServerSecurityConfiguration {
4644

47-
@Value("${tenantOne.jwk-set-uri}")
48-
String jwkSetUri;
49-
50-
@Value("${tenantTwo.introspection-uri}")
51-
String introspectionUri;
52-
53-
@Value("${tenantTwo.introspection-client-id}")
54-
String introspectionClientId;
55-
56-
@Value("${tenantTwo.introspection-client-secret}")
57-
String introspectionClientSecret;
58-
59-
@Override
60-
protected void configure(HttpSecurity http) throws Exception {
45+
@Bean
46+
SecurityFilterChain apiSecurity(HttpSecurity http,
47+
AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver) throws Exception {
6148
// @formatter:off
6249
http
6350
.authorizeRequests((requests) -> requests
64-
.mvcMatchers("/**/message/**").hasAuthority("SCOPE_message:read")
65-
.anyRequest().authenticated()
51+
.mvcMatchers("/**/message/**").hasAuthority("SCOPE_message:read")
52+
.anyRequest().authenticated()
6653
)
6754
.oauth2ResourceServer((resourceServer) -> resourceServer
68-
.authenticationManagerResolver(multitenantAuthenticationManager())
55+
.authenticationManagerResolver(authenticationManagerResolver)
6956
);
7057
// @formatter:on
58+
59+
return http.build();
7160
}
7261

7362
@Bean
74-
AuthenticationManagerResolver<HttpServletRequest> multitenantAuthenticationManager() {
63+
AuthenticationManagerResolver<HttpServletRequest> multitenantAuthenticationManager(JwtDecoder jwtDecoder,
64+
OpaqueTokenIntrospector opaqueTokenIntrospector) {
7565
Map<String, AuthenticationManager> authenticationManagers = new HashMap<>();
76-
authenticationManagers.put("tenantOne", jwt());
77-
authenticationManagers.put("tenantTwo", opaque());
66+
authenticationManagers.put("tenantOne", jwt(jwtDecoder));
67+
authenticationManagers.put("tenantTwo", opaque(opaqueTokenIntrospector));
7868
return (request) -> {
7969
String[] pathParts = request.getRequestURI().split("/");
8070
String tenantId = (pathParts.length > 0) ? pathParts[1] : null;
@@ -86,17 +76,14 @@ AuthenticationManagerResolver<HttpServletRequest> multitenantAuthenticationManag
8676
};
8777
}
8878

89-
AuthenticationManager jwt() {
90-
JwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri(this.jwkSetUri).build();
79+
AuthenticationManager jwt(JwtDecoder jwtDecoder) {
9180
JwtAuthenticationProvider authenticationProvider = new JwtAuthenticationProvider(jwtDecoder);
9281
authenticationProvider.setJwtAuthenticationConverter(new JwtBearerTokenAuthenticationConverter());
93-
return authenticationProvider::authenticate;
82+
return new ProviderManager(authenticationProvider);
9483
}
9584

96-
AuthenticationManager opaque() {
97-
OpaqueTokenIntrospector introspectionClient = new NimbusOpaqueTokenIntrospector(this.introspectionUri,
98-
this.introspectionClientId, this.introspectionClientSecret);
99-
return new OpaqueTokenAuthenticationProvider(introspectionClient)::authenticate;
85+
AuthenticationManager opaque(OpaqueTokenIntrospector introspectionClient) {
86+
return new ProviderManager(new OpaqueTokenAuthenticationProvider(introspectionClient));
10087
}
10188

10289
}
Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
tenantOne.jwk-set-uri: ${mockwebserver.url}/.well-known/jwks.json
2-
tenantTwo.introspection-uri: ${mockwebserver.url}/introspect
3-
tenantTwo.introspection-client-id: client
4-
tenantTwo.introspection-client-secret: secret
1+
spring:
2+
security:
3+
oauth2:
4+
resourceserver:
5+
jwt:
6+
jwk-set-uri: ${mockwebserver.url}/.well-known/jwks.json
7+
opaquetoken:
8+
introspection-uri: ${mockwebserver.url}/introspect
9+
client-id: client
10+
client-secret: secret
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
plugins {
2+
id "java"
3+
id "war"
4+
id "nebula.integtest" version "7.0.9"
5+
id "org.gretty" version "3.0.3"
6+
}
7+
8+
apply from: "gradle/gretty.gradle"
9+
10+
repositories {
11+
jcenter()
12+
maven { url "https://repo.spring.io/snapshot" }
13+
}
14+
15+
dependencies {
16+
implementation platform("org.springframework.security:spring-security-bom:5.6.0-SNAPSHOT")
17+
implementation platform("org.springframework:spring-framework-bom:5.3.9")
18+
implementation platform("org.junit:junit-bom:5.7.0")
19+
20+
implementation "org.springframework.security:spring-security-config"
21+
implementation "org.springframework.security:spring-security-web"
22+
implementation "org.springframework.security:spring-security-acl"
23+
implementation "org.springframework.security:spring-security-taglibs"
24+
implementation 'org.springframework:spring-web'
25+
implementation "org.springframework:spring-webmvc"
26+
implementation 'org.springframework:spring-aop'
27+
implementation 'org.springframework:spring-beans'
28+
implementation 'org.springframework:spring-context'
29+
implementation 'org.springframework:spring-jdbc'
30+
implementation 'org.springframework:spring-tx'
31+
implementation 'org.slf4j:slf4j-api:1.7.30'
32+
implementation 'org.slf4j:slf4j-simple:1.7.30'
33+
implementation 'javax.servlet:jstl:1.2'
34+
35+
runtime 'net.sf.ehcache:ehcache:2.10.5'
36+
runtime 'org.hsqldb:hsqldb:2.5.0'
37+
runtime 'org.springframework:spring-context-support'
38+
39+
providedCompile 'javax.servlet:javax.servlet-api:4.0.0'
40+
41+
testImplementation "org.springframework:spring-test"
42+
testImplementation "org.springframework.security:spring-security-test"
43+
testImplementation("org.junit.jupiter:junit-jupiter-api")
44+
testImplementation "org.assertj:assertj-core:3.18.0"
45+
46+
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
47+
48+
integTestImplementation "org.seleniumhq.selenium:htmlunit-driver:2.44.0"
49+
}
50+
51+
tasks.withType(Test).configureEach {
52+
useJUnitPlatform()
53+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Properties file with server URL settings for remote access.
2+
# Applied by PropertyPlaceholderConfigurer from "clientContext.xml".
3+
#
4+
5+
serverName=localhost
6+
httpPort=8080
7+
contextPath=/spring-security-sample-contacts-filter
8+
rmiPort=1099
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "https://www.springframework.org/dtd/spring-beans.dtd">
3+
4+
<!--
5+
- Contacts web application
6+
- Client application context
7+
-->
8+
9+
<beans>
10+
11+
<!-- Resolves ${...} placeholders from client.properties -->
12+
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
13+
<property name="location"><value>client.properties</value></property>
14+
</bean>
15+
16+
<!-- Proxy for the RMI-exported ContactManager -->
17+
<!-- COMMENTED OUT BY DEFAULT TO AVOID CONFLICTS WITH APPLICATION SERVERS
18+
<bean id="rmiProxy" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
19+
<property name="serviceInterface">
20+
<value>sample.contact.ContactManager</value>
21+
</property>
22+
<property name="serviceUrl">
23+
<value>rmi://${serverName}:${rmiPort}/contactManager</value>
24+
</property>
25+
<property name="remoteInvocationFactory">
26+
<ref bean="remoteInvocationFactory"/>
27+
</property>
28+
</bean>
29+
30+
<bean id="remoteInvocationFactory" class="org.springframework.security.ui.rmi.ContextPropagatingRemoteInvocationFactory"/>
31+
-->
32+
33+
<!-- Proxy for the HTTP-invoker-exported ContactManager -->
34+
<!-- Spring's HTTP invoker uses Java serialization via HTTP -->
35+
<bean id="httpInvokerProxy" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
36+
<property name="serviceInterface">
37+
<value>sample.contact.ContactManager</value>
38+
</property>
39+
<property name="serviceUrl">
40+
<value>http://${serverName}:${httpPort}${contextPath}/remoting/ContactManager-httpinvoker</value>
41+
</property>
42+
<property name="httpInvokerRequestExecutor">
43+
<ref bean="httpInvokerRequestExecutor"/>
44+
</property>
45+
</bean>
46+
47+
<!-- Automatically propagates ContextHolder-managed Authentication principal
48+
and credentials to a HTTP invoker BASIC authentication header -->
49+
<bean id="httpInvokerRequestExecutor" class="org.springframework.security.core.context.httpinvoker.AuthenticationSimpleHttpInvokerRequestExecutor"/>
50+
51+
<!-- Proxy for the Hessian-exported ContactManager
52+
<bean id="hessianProxy" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
53+
<property name="serviceInterface">
54+
<value>sample.contact.ContactManager</value>
55+
</property>
56+
<property name="serviceUrl">
57+
<value>http://${serverName}:${httpPort}${contextPath}/remoting/ContactManager-hessian</value>
58+
</property>
59+
</bean>
60+
-->
61+
62+
<!-- Proxy for the Burlap-exported ContactManager
63+
<bean id="burlapProxy" class="org.springframework.remoting.caucho.BurlapProxyFactoryBean">
64+
<property name="serviceInterface">
65+
<value>sample.contact.ContactManager</value>
66+
</property>
67+
<property name="serviceUrl">
68+
<value>http://${serverName}:${httpPort}${contextPath}/remoting/ContactManager-burlap</value>
69+
</property>
70+
</bean>
71+
-->
72+
73+
</beans>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
version=5.6.0-SNAPSHOT
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
gretty {
2+
servletContainer = "tomcat9"
3+
contextPath = "/"
4+
fileLogEnabled = false
5+
integrationTestTask = 'integrationTest'
6+
}
7+
8+
Task prepareAppServerForIntegrationTests = project.tasks.create('prepareAppServerForIntegrationTests') {
9+
group = 'Verification'
10+
description = 'Prepares the app server for integration tests'
11+
doFirst {
12+
project.gretty {
13+
httpPort = -1
14+
}
15+
}
16+
}
17+
18+
project.tasks.matching { it.name == "appBeforeIntegrationTest" }.all { task ->
19+
task.dependsOn prepareAppServerForIntegrationTests
20+
}
21+
22+
project.tasks.matching { it.name == "integrationTest" }.all {
23+
task -> task.doFirst {
24+
def gretty = project.gretty
25+
String host = project.gretty.host ?: 'localhost'
26+
boolean isHttps = gretty.httpsEnabled
27+
Integer httpPort = integrationTest.systemProperties['gretty.httpPort']
28+
Integer httpsPort = integrationTest.systemProperties['gretty.httpsPort']
29+
int port = isHttps ? httpsPort : httpPort
30+
String contextPath = project.gretty.contextPath
31+
String httpBaseUrl = "http://${host}:${httpPort}${contextPath}"
32+
String httpsBaseUrl = "https://${host}:${httpsPort}${contextPath}"
33+
String baseUrl = isHttps ? httpsBaseUrl : httpBaseUrl
34+
integrationTest.systemProperty 'app.port', port
35+
integrationTest.systemProperty 'app.httpPort', httpPort
36+
integrationTest.systemProperty 'app.httpsPort', httpsPort
37+
integrationTest.systemProperty 'app.baseURI', baseUrl
38+
integrationTest.systemProperty 'app.httpBaseURI', httpBaseUrl
39+
integrationTest.systemProperty 'app.httpsBaseURI', httpsBaseUrl
40+
}
41+
}
Binary file not shown.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
distributionBase=GRADLE_USER_HOME
2+
distributionPath=wrapper/dists
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9-bin.zip
4+
zipStoreBase=GRADLE_USER_HOME
5+
zipStorePath=wrapper/dists

0 commit comments

Comments
 (0)