Skip to content

Commit 5ac010e

Browse files
committed
Merge branch 'release/3.0.2'
2 parents fdab820 + 12eb911 commit 5ac010e

16 files changed

+258
-76
lines changed

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
<groupId>eu.openanalytics</groupId>
77
<artifactId>shinyproxy</artifactId>
8-
<version>3.0.1</version>
8+
<version>3.0.2</version>
99
<packaging>jar</packaging>
1010

1111
<name>ShinyProxy</name>
@@ -28,7 +28,7 @@
2828
<java.version>1.8</java.version>
2929
<maven.compiler.source>8</maven.compiler.source>
3030
<maven.compiler.target>8</maven.compiler.target>
31-
<containerproxy.version>1.0.1</containerproxy.version>
31+
<containerproxy.version>1.0.2</containerproxy.version>
3232
<resource.delimiter>&amp;</resource.delimiter>
3333
</properties>
3434

src/main/java/eu/openanalytics/shinyproxy/ShinyProxyConfiguration.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import eu.openanalytics.shinyproxy.runtimevalues.PublicPathKey;
2626
import eu.openanalytics.shinyproxy.runtimevalues.ShinyForceFullReloadKey;
2727
import eu.openanalytics.shinyproxy.runtimevalues.TrackAppUrl;
28+
import eu.openanalytics.shinyproxy.runtimevalues.UserTimeZoneKey;
2829
import eu.openanalytics.shinyproxy.runtimevalues.WebSocketReconnectionModeKey;
2930
import org.springframework.context.annotation.Configuration;
3031
import org.springframework.context.annotation.PropertySource;
@@ -39,5 +40,6 @@ public class ShinyProxyConfiguration {
3940
RuntimeValueKeyRegistry.addRuntimeValueKey(ShinyForceFullReloadKey.inst);
4041
RuntimeValueKeyRegistry.addRuntimeValueKey(WebSocketReconnectionModeKey.inst);
4142
RuntimeValueKeyRegistry.addRuntimeValueKey(TrackAppUrl.inst);
43+
RuntimeValueKeyRegistry.addRuntimeValueKey(UserTimeZoneKey.inst);
4244
}
4345
}

src/main/java/eu/openanalytics/shinyproxy/ShinyProxyIframeScriptInjector.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
package eu.openanalytics.shinyproxy;
2222

2323
import eu.openanalytics.containerproxy.util.ContextPathHelper;
24+
import io.netty.buffer.ByteBuf;
2425
import io.undertow.UndertowMessages;
2526
import io.undertow.server.HttpServerExchange;
2627
import io.undertow.server.protocol.http.ServerFixedLengthStreamSinkConduit;
@@ -113,16 +114,16 @@ public long writeFinal(java.nio.ByteBuffer[] srcs, int offs, int len) throws IOE
113114

114115
@Override
115116
public void terminateWrites() throws IOException {
116-
// 1. get HTML page and add script tag
117-
String r = outputStream.toString();
117+
// 1. check whether it's a html response and success
118118
if (exchange.getStatusCode() == HttpStatus.OK.value()
119119
&& exchange.getResponseHeaders().get("Content-Type") != null
120120
&& exchange.getResponseHeaders().get("Content-Type").stream().anyMatch(headerValue -> headerValue.contains("text/html"))) {
121-
// only inject script of response successful and actually a html response
122-
r += "<script src='" + ContextPathHelper.withEndingSlash() + "js/shiny.iframe.js'></script>";
121+
// 2. inject script
122+
String r = "<script src='" + ContextPathHelper.withEndingSlash() + "js/shiny.iframe.js'></script>";
123+
outputStream.write(r.getBytes(StandardCharsets.UTF_8));
123124
}
124-
// 2. convert to ByteBuffer
125-
ByteBuffer out = ByteBuffer.wrap(r.getBytes(StandardCharsets.UTF_8));
125+
126+
ByteBuffer out = ByteBuffer.wrap(outputStream.toByteArray());
126127
// 3. set Content-Length header
127128
updateContentLength(exchange, out);
128129
// 4. write new response (to the next stream)

src/main/java/eu/openanalytics/shinyproxy/ShinyProxyTestStrategy.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public boolean testProxy(Proxy proxy) {
6262
// proxy got stopped while loading -> no need to try to connect it since the container will already be deleted
6363
return true;
6464
}
65-
URL testURL = new URL(targetURI.toString());
65+
URL testURL = new URL(targetURI.toString() + "/");
6666
HttpURLConnection connection = ((HttpURLConnection) testURL.openConnection());
6767
if (currentAttempt <= 5) {
6868
// When the container has only just started (or when the k8s service has only just been created),

src/main/java/eu/openanalytics/shinyproxy/UISecurityConfig.java

Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,37 +23,63 @@
2323
import eu.openanalytics.containerproxy.auth.IAuthenticationBackend;
2424
import eu.openanalytics.containerproxy.security.ICustomSecurityConfig;
2525
import eu.openanalytics.containerproxy.service.UserService;
26+
import org.springframework.context.annotation.Lazy;
2627
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
28+
import org.springframework.security.web.DefaultRedirectStrategy;
2729
import org.springframework.security.web.access.ExceptionTranslationFilter;
30+
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
2831
import org.springframework.stereotype.Component;
32+
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
2933

3034
import javax.inject.Inject;
35+
import javax.servlet.http.HttpServletRequest;
36+
import javax.servlet.http.HttpServletResponse;
37+
import java.io.IOException;
38+
39+
import static eu.openanalytics.containerproxy.ui.AuthController.AUTH_SUCCESS_URL_SESSION_ATTR;
3140

3241
@Component
3342
public class UISecurityConfig implements ICustomSecurityConfig {
3443

35-
@Inject
36-
private IAuthenticationBackend auth;
37-
38-
@Inject
39-
private UserService userService;
40-
41-
@Override
42-
public void apply(HttpSecurity http) throws Exception {
43-
if (auth.hasAuthorization()) {
44-
45-
// Limit access to the app pages according to spec permissions
46-
http.authorizeRequests().antMatchers("/app/{specId}/**").access("@proxyAccessControlService.canAccessOrHasExistingProxy(authentication, #specId)");
47-
http.authorizeRequests().antMatchers("/app_i/{specId}/**").access("@proxyAccessControlService.canAccessOrHasExistingProxy(authentication, #specId)");
48-
http.authorizeRequests().antMatchers("/app_direct/{specId}/**").access("@proxyAccessControlService.canAccessOrHasExistingProxy(authentication, #specId)");
49-
http.authorizeRequests().antMatchers("/app_direct_i/{specId}/**").access("@proxyAccessControlService.canAccessOrHasExistingProxy(authentication, #specId)");
50-
51-
// Limit access to the admin pages
52-
http.authorizeRequests().antMatchers("/admin").hasAnyRole(userService.getAdminGroups());
53-
http.authorizeRequests().antMatchers("/admin/data").hasAnyRole(userService.getAdminGroups());
54-
55-
http.addFilterAfter(new AuthenticationRequiredFilter(), ExceptionTranslationFilter.class);
56-
}
57-
58-
}
44+
@Inject
45+
private IAuthenticationBackend auth;
46+
47+
@Inject
48+
private UserService userService;
49+
50+
@Inject
51+
@Lazy
52+
private SavedRequestAwareAuthenticationSuccessHandler savedRequestAwareAuthenticationSuccessHandler;
53+
54+
@Override
55+
public void apply(HttpSecurity http) throws Exception {
56+
if (auth.hasAuthorization()) {
57+
58+
// Limit access to the app pages according to spec permissions
59+
http.authorizeRequests().antMatchers("/app/{specId}/**").access("@proxyAccessControlService.canAccessOrHasExistingProxy(authentication, #specId)");
60+
http.authorizeRequests().antMatchers("/app_i/{specId}/**").access("@proxyAccessControlService.canAccessOrHasExistingProxy(authentication, #specId)");
61+
http.authorizeRequests().antMatchers("/app_direct/{specId}/**").access("@proxyAccessControlService.canAccessOrHasExistingProxy(authentication, #specId)");
62+
http.authorizeRequests().antMatchers("/app_direct_i/{specId}/**").access("@proxyAccessControlService.canAccessOrHasExistingProxy(authentication, #specId)");
63+
64+
http.addFilterAfter(new AuthenticationRequiredFilter(), ExceptionTranslationFilter.class);
65+
66+
savedRequestAwareAuthenticationSuccessHandler.setRedirectStrategy(new DefaultRedirectStrategy() {
67+
@Override
68+
public void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url) throws IOException {
69+
String redirectUrl = calculateRedirectUrl(request.getContextPath(), url);
70+
AppRequestInfo appRequestInfo = AppRequestInfo.fromURI(redirectUrl);
71+
if (appRequestInfo != null) {
72+
// before auth, the user tried to open the page of an app, redirect back to that app
73+
// (we don't redirect to any other app, see #30648 and #28624)
74+
request.getSession().setAttribute(AUTH_SUCCESS_URL_SESSION_ATTR, url);
75+
}
76+
response.sendRedirect(ServletUriComponentsBuilder.fromCurrentContextPath().path("/auth-success").build().toUriString());
77+
}
78+
});
79+
}
80+
// Limit access to the admin pages
81+
http.authorizeRequests().antMatchers("/admin").access("@userService.isAdmin()");
82+
http.authorizeRequests().antMatchers("/admin/data").access("@userService.isAdmin()");
83+
84+
}
5985
}

0 commit comments

Comments
 (0)