Skip to content

Commit af5bb78

Browse files
committed
adding /z/{subdomain}/ support in the IdentityZoneResolvingFilter
1 parent cb1ff11 commit af5bb78

File tree

1 file changed

+38
-7
lines changed

1 file changed

+38
-7
lines changed

server/src/main/java/org/cloudfoundry/identity/uaa/zone/IdentityZoneResolvingFilter.java

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.slf4j.LoggerFactory;
1919
import org.springframework.beans.factory.InitializingBean;
2020
import org.springframework.dao.EmptyResultDataAccessException;
21+
import org.springframework.util.StringUtils;
2122
import org.springframework.web.filter.OncePerRequestFilter;
2223

2324
import jakarta.servlet.FilterChain;
@@ -31,12 +32,14 @@
3132

3233
/**
3334
* This filter ensures that all requests are targeting a specific identity zone
34-
* by hostname. If the hostname doesn't match an identity zone, a 404 error is
35-
* sent.
36-
*
35+
* by hostname or by path prefix /z/{subdomain}/. If the hostname doesn't match
36+
* an identity zone, a 404 error is sent. Using both a subdomain (host) and a /z/
37+
* path is not allowed and returns 400.
3738
*/
3839
public class IdentityZoneResolvingFilter extends OncePerRequestFilter implements InitializingBean {
3940

41+
private static final String ZONE_PATH_PREFIX = "/z/";
42+
4043
private final IdentityZoneProvisioning dao;
4144
private final Set<String> staticResources = Set.of("/resources/", "/vendor/font-awesome/");
4245
private final Set<String> defaultZoneHostnames = new HashSet<>();
@@ -49,9 +52,21 @@ public IdentityZoneResolvingFilter(final IdentityZoneProvisioning dao) {
4952
@Override
5053
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
5154
throws ServletException, IOException {
55+
String requestPath = UaaUrlUtils.getRequestPath(request);
56+
String subdomainFromHost = getSubdomainFromHost(request.getServerName());
57+
String subdomainFromPath = getSubdomainFromPath(requestPath);
58+
59+
// 400: path starts with /z/ and host has a zone subdomain
60+
if (requestPath.startsWith(ZONE_PATH_PREFIX) && StringUtils.hasText(subdomainFromHost)) {
61+
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Cannot use both subdomain and zone path");
62+
return;
63+
}
64+
65+
// Host always overrides path domain - path domain only works if there is no Host subdomain
66+
String subdomain = StringUtils.hasText(subdomainFromPath) && "".equals(subdomainFromHost) ?
67+
subdomainFromPath : subdomainFromHost;
68+
5269
IdentityZone identityZone = null;
53-
String hostname = request.getServerName();
54-
String subdomain = getSubdomain(hostname);
5570
if (subdomain != null) {
5671
try {
5772
identityZone = dao.retrieveBySubdomain(subdomain);
@@ -66,7 +81,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
6681
}
6782
if (identityZone == null) {
6883
// skip filter to static resources in order to serve images and css in case of invalid zones
69-
boolean isStaticResource = staticResources.stream().anyMatch(UaaUrlUtils.getRequestPath(request)::startsWith);
84+
boolean isStaticResource = staticResources.stream().anyMatch(requestPath::startsWith);
7085
if (isStaticResource) {
7186
filterChain.doFilter(request, response);
7287
return;
@@ -84,7 +99,23 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
8499
}
85100
}
86101

87-
private String getSubdomain(String hostname) {
102+
/**
103+
* Returns the subdomain if path starts with /z/{subdomain}/, otherwise null.
104+
*/
105+
private String getSubdomainFromPath(String path) {
106+
if (path == null || !path.startsWith(ZONE_PATH_PREFIX)) {
107+
return null;
108+
}
109+
String afterPrefix = path.substring(ZONE_PATH_PREFIX.length());
110+
int slash = afterPrefix.indexOf('/');
111+
if (slash < 0) {
112+
return null;
113+
}
114+
String subdomain = afterPrefix.substring(0, slash);
115+
return StringUtils.hasText(subdomain) ? subdomain : null;
116+
}
117+
118+
private String getSubdomainFromHost(String hostname) {
88119
String lowerHostName = hostname.toLowerCase();
89120
if (defaultZoneHostnames.contains(lowerHostName)) {
90121
return "";

0 commit comments

Comments
 (0)