Skip to content

Commit 31fc5ea

Browse files
committed
Merge branch 'release/0.8.7'
2 parents e664c3e + 16d9615 commit 31fc5ea

File tree

12 files changed

+951
-871
lines changed

12 files changed

+951
-871
lines changed

.github/workflows/workflows.yaml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: Tests
2+
3+
on: [push]
4+
5+
jobs:
6+
tests:
7+
runs-on: ubuntu-latest
8+
strategy:
9+
matrix:
10+
java: [ 8, 11 ]
11+
kubernetes: [ 'v1.20.1', 'v1.19.6', 'v1.18.14', 'v1.17.16', 'v1.16.14']
12+
13+
steps:
14+
- uses: actions/checkout@v2
15+
- name: Set up JDK
16+
uses: actions/setup-java@v1
17+
with:
18+
java-version: ${{ matrix.java }}
19+
- name: Cache Maven packages
20+
uses: actions/cache@v2
21+
with:
22+
path: ~/.m2
23+
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
24+
restore-keys: ${{ runner.os }}-m2
25+
- name: Setup Minikube
26+
uses: manusa/actions-setup-minikube@v2.3.0
27+
with:
28+
minikube version: 'v1.16.0'
29+
kubernetes version: ${{ matrix.kubernetes }}
30+
- name: Setup Docker
31+
run: sudo apt-get -qq -y install conntrack socat ; nohup socat TCP-LISTEN:2375,reuseaddr,fork UNIX-CONNECT:/var/run/docker.sock &
32+
- name: Pull Image
33+
run: docker pull openanalytics/shinyproxy-demo:latest
34+
- name: Build with Maven
35+
run: mvn -U clean install -DskipTests
36+
- name: Run Tests
37+
run: mvn test
38+
39+
dependency:
40+
runs-on: ubuntu-latest
41+
42+
steps:
43+
- uses: actions/checkout@v2
44+
- name: Run Dependency Check
45+
run: mvn -Powasp-dependency-check verify -DskipTests
46+
- name: Archive code coverage results
47+
uses: actions/upload-artifact@v2
48+
with:
49+
name: dependency-check-report
50+
path: target/dependency-check-report.html
51+

.travis.yml

Lines changed: 0 additions & 45 deletions
This file was deleted.

pom.xml

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
<groupId>eu.openanalytics</groupId>
77
<artifactId>containerproxy</artifactId>
8-
<version>0.8.6</version>
8+
<version>0.8.7</version>
99
<name>ContainerProxy</name>
1010
<packaging>jar</packaging>
1111

@@ -289,29 +289,6 @@
289289
<version>2.11.2</version>
290290
</dependency>
291291

292-
293-
<!-- Deps for tests -->
294-
<dependency>
295-
<groupId>org.arquillian.cube</groupId>
296-
<artifactId>arquillian-cube-bom</artifactId>
297-
<version>${version.arquillian_cube}</version>
298-
<scope>import</scope>
299-
<type>pom</type>
300-
</dependency>
301-
<dependency>
302-
<groupId>org.arquillian.cube</groupId>
303-
<artifactId>arquillian-cube-kubernetes-starter</artifactId>
304-
<version>${version.arquillian_cube}</version>
305-
<scope>test</scope>
306-
</dependency>
307-
<dependency>
308-
<groupId>org.arquillian.cube</groupId>
309-
<artifactId>arquillian-cube-requirement</artifactId>
310-
<version>${version.arquillian_cube}</version>
311-
<scope>test</scope>
312-
</dependency>
313-
314-
315292
<!-- Recursive dependencies which are upgraded for security -->
316293
<dependency>
317294
<groupId>commons-collections</groupId>

src/main/java/eu/openanalytics/containerproxy/ContainerProxyApplication.java

Lines changed: 64 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,41 +20,42 @@
2020
*/
2121
package eu.openanalytics.containerproxy;
2222

23+
import com.fasterxml.jackson.datatype.jsr353.JSR353Module;
2324
import eu.openanalytics.containerproxy.util.ProxyMappingManager;
2425
import io.undertow.Handlers;
2526
import io.undertow.servlet.api.ServletSessionConfig;
27+
import org.apache.logging.log4j.LogManager;
28+
import org.apache.logging.log4j.Logger;
2629
import org.springframework.boot.SpringApplication;
30+
import org.springframework.boot.actuate.health.Health;
31+
import org.springframework.boot.actuate.health.HealthIndicator;
32+
import org.springframework.boot.actuate.redis.RedisHealthIndicator;
2733
import org.springframework.boot.autoconfigure.SpringBootApplication;
2834
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
2935
import org.springframework.boot.web.server.PortInUseException;
3036
import org.springframework.boot.web.servlet.FilterRegistrationBean;
3137
import org.springframework.context.annotation.Bean;
3238
import org.springframework.context.annotation.ComponentScan;
33-
import org.springframework.context.event.ContextRefreshedEvent;
34-
import org.springframework.context.event.EventListener;
3539
import org.springframework.core.env.Environment;
40+
import org.springframework.data.redis.connection.RedisConnectionFactory;
3641
import org.springframework.session.data.redis.config.ConfigureRedisAction;
3742
import org.springframework.web.filter.FormContentFilter;
38-
import org.springframework.web.filter.HiddenHttpMethodFilter;
39-
40-
import com.fasterxml.jackson.datatype.jsr353.JSR353Module;
4143

4244
import javax.annotation.PostConstruct;
4345
import javax.inject.Inject;
4446
import java.net.InetAddress;
4547
import java.net.UnknownHostException;
4648
import java.nio.file.Files;
4749
import java.nio.file.Paths;
50+
import java.util.Objects;
4851
import java.util.Properties;
49-
import org.apache.logging.log4j.LogManager;
50-
import org.apache.logging.log4j.Logger;
5152

5253
@SpringBootApplication
5354
@ComponentScan("eu.openanalytics")
5455
public class ContainerProxyApplication {
5556
public static final String CONFIG_FILENAME = "application.yml";
5657
public static final String CONFIG_DEMO_PROFILE = "demo";
57-
58+
5859
@Inject
5960
private Environment environment;
6061

@@ -68,9 +69,9 @@ public static void main(String[] args) {
6869

6970
boolean hasExternalConfig = Files.exists(Paths.get(CONFIG_FILENAME));
7071
if (!hasExternalConfig) app.setAdditionalProfiles(CONFIG_DEMO_PROFILE);
71-
72+
7273
setDefaultProperties(app);
73-
74+
7475
try {
7576
app.setLogStartupInfo(false);
7677
app.run(args);
@@ -81,13 +82,13 @@ public static void main(String[] args) {
8182
if (e instanceof PortInUseException) System.exit(-1);
8283
}
8384
}
84-
85+
8586
@PostConstruct
86-
public void init() {
87+
public void init() {
8788
if (environment.getProperty("server.use-forward-headers") != null) {
8889
log.warn("WARNING: Using server.use-forward-headers will not work in this ShinyProxy release. See https://shinyproxy.io/documentation/security/#https-ssl--tls on how to change your configuration.");
8990
}
90-
}
91+
}
9192

9293
@Bean
9394
public UndertowServletWebServerFactory servletContainer() {
@@ -111,11 +112,11 @@ public UndertowServletWebServerFactory servletContainer() {
111112
throw new IllegalArgumentException("Invalid bind address specified", e);
112113
}
113114
factory.setPort(Integer.parseInt(environment.getProperty("proxy.port", "8080")));
114-
return factory;
115+
return factory;
115116
}
116-
117+
117118
// Disable specific Spring filters that parse the request body, preventing it from being proxied.
118-
119+
119120
@Bean
120121
public FilterRegistrationBean<FormContentFilter> registration2(FormContentFilter filter) {
121122
FilterRegistrationBean<FormContentFilter> registration = new FilterRegistrationBean<>(filter);
@@ -125,6 +126,7 @@ public FilterRegistrationBean<FormContentFilter> registration2(FormContentFilter
125126

126127
/**
127128
* Register the Jackson module which implements compatibility between javax.json and Jackson.
129+
*
128130
* @return
129131
*/
130132
@Bean
@@ -134,30 +136,66 @@ public JSR353Module jsr353Module() {
134136

135137
/**
136138
* Compatibility with AWS ElastiCache
139+
*
137140
* @return
138141
*/
139142
@Bean
140143
public static ConfigureRedisAction configureRedisAction() {
141144
return ConfigureRedisAction.NO_OP;
142145
}
143-
144-
private static void setDefaultProperties(SpringApplication app ) {
146+
147+
@Bean
148+
public HealthIndicator redisSessionHealthIndicator(RedisConnectionFactory rdeRedisConnectionFactory) {
149+
if (Objects.equals(environment.getProperty("spring.session.store-type"), "redis")) {
150+
// if we are using redis for session -> use a proper health check for redis
151+
return new RedisHealthIndicator(rdeRedisConnectionFactory);
152+
} else {
153+
// not using redis for session -> just pretend it's always online
154+
return new HealthIndicator() {
155+
156+
@Override
157+
public Health getHealth(boolean includeDetails) {
158+
return Health.up().build();
159+
}
160+
161+
@Override
162+
public Health health() {
163+
return Health.up().build();
164+
}
165+
};
166+
}
167+
}
168+
169+
private static void setDefaultProperties(SpringApplication app) {
145170
Properties properties = new Properties();
146-
properties.put("management.health.ldap.enabled", false);
147-
properties.put("management.endpoint.health.probes.enabled", true);
148-
171+
149172
// use in-memory session storage by default. Can be overwritten in application.yml
150173
properties.put("spring.session.store-type", "none");
151-
174+
152175
// disable multi-part handling by Spring. We don't need this anywhere in the application.
153176
// When enabled this will cause problems when proxying file-uploads to the shiny apps.
154177
properties.put("spring.servlet.multipart.enabled", "false");
155-
178+
156179
// disable logging of requests, since this reads part of the requests and therefore undertow is unable to correctly handle those requests
157180
properties.put("logging.level.org.springframework.web.servlet.DispatcherServlet", "INFO");
158-
181+
159182
properties.put("spring.application.name", "ContainerProxy");
183+
184+
// Health configuration
185+
// ====================
186+
187+
// enable redisSession check for the readiness probe
188+
properties.put("management.endpoint.health.group.readiness.include", "readinessProbe,redisSession");
189+
// disable ldap health endpoint
190+
properties.put("management.health.ldap.enabled", false);
191+
// disable default redis health endpoint since it's managed by redisSession
192+
properties.put("management.health.redis.enabled", "false");
193+
// enable Kubernetes porobes
194+
properties.put("management.endpoint.health.probes.enabled", true);
195+
196+
// ====================
197+
160198
app.setDefaultProperties(properties);
161199
}
162-
163-
}
200+
201+
}

src/main/java/eu/openanalytics/containerproxy/auth/impl/KeycloakAuthenticationBackend.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@
5050
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
5151
import org.springframework.context.ApplicationContext;
5252
import org.springframework.context.annotation.Bean;
53+
import org.springframework.context.annotation.Lazy;
5354
import org.springframework.core.env.Environment;
55+
import org.springframework.security.authentication.AuthenticationManager;
5456
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
5557
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
5658
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@@ -85,7 +87,11 @@ public class KeycloakAuthenticationBackend implements IAuthenticationBackend {
8587

8688
@Inject
8789
ApplicationContext ctx;
88-
90+
91+
@Inject
92+
@Lazy
93+
AuthenticationManager authenticationManager;
94+
8995
@Override
9096
public String getName() {
9197
return NAME;
@@ -126,14 +132,14 @@ protected KeycloakAuthenticationProcessingFilter keycloakAuthenticationProcessin
126132
// Possible solution for issue #21037, create a custom RequestMatcher that doesn't include a QueryParamPresenceRequestMatcher(OAuth2Constants.ACCESS_TOKEN) request matcher.
127133
// The QueryParamPresenceRequestMatcher(OAuth2Constants.ACCESS_TOKEN) caused the HTTP requests to be changed before they where processed.
128134
// Because the HTTP requests are adapted before they are processed, the requested failed to complete successfully and caused an io.undertow.server.TruncatedResponseException
129-
// If in the future we need a RequestMatcher for het ACCESS_TOKEN, we can implement one ourself
135+
// If in the future we need a RequestMatcher for het ACCESS_TOKEN, we can implement one ourself
130136
RequestMatcher requestMatcher =
131137
new OrRequestMatcher(
132138
new AntPathRequestMatcher(KeycloakAuthenticationProcessingFilter.DEFAULT_LOGIN_URL),
133139
new RequestHeaderRequestMatcher(KeycloakAuthenticationProcessingFilter.AUTHORIZATION_HEADER)
134140
);
135-
136-
KeycloakAuthenticationProcessingFilter filter = new KeycloakAuthenticationProcessingFilter(webSecurityConfigurerAdapter.authenticationManagerBean(), requestMatcher);
141+
142+
KeycloakAuthenticationProcessingFilter filter = new KeycloakAuthenticationProcessingFilter(authenticationManager, requestMatcher);
137143
filter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy());
138144
// Fix: call afterPropertiesSet manually, because Spring doesn't invoke it for some reason.
139145
filter.setApplicationContext(ctx);

src/main/java/eu/openanalytics/containerproxy/auth/impl/OpenIDAuthenticationBackend.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
import net.minidev.json.JSONArray;
7070
import net.minidev.json.parser.JSONParser;
7171
import net.minidev.json.parser.ParseException;
72+
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
7273

7374
public class OpenIDAuthenticationBackend implements IAuthenticationBackend {
7475

@@ -115,7 +116,7 @@ public void configureHttpSecurity(HttpSecurity http, AuthorizedUrl anyRequestCon
115116
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
116117
AuthenticationException exception) throws IOException, ServletException {
117118
log.error(exception);
118-
response.sendRedirect("/auth-error");
119+
response.sendRedirect(ServletUriComponentsBuilder.fromCurrentContextPath().path("/auth-error").build().toUriString());
119120
}
120121

121122
})

0 commit comments

Comments
 (0)