Skip to content

Commit 60b3466

Browse files
Polish gh-14193
Issue gh-14193
1 parent 40fbfe9 commit 60b3466

11 files changed

+398
-493
lines changed

cas/src/main/java/org/springframework/security/cas/web/CasAuthenticationFilter.java

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
5454
import org.springframework.security.web.util.matcher.RequestMatcher;
5555
import org.springframework.util.Assert;
56+
import org.springframework.util.StringUtils;
5657

5758
/**
5859
* Processes a CAS service ticket, obtains proxy granting tickets, and processes proxy
@@ -247,25 +248,24 @@ public Authentication attemptAuthentication(HttpServletRequest request, HttpServ
247248
return null;
248249
}
249250
String serviceTicket = obtainArtifact(request);
250-
if (serviceTicket == null) {
251-
boolean gateway = false;
251+
if (!StringUtils.hasText(serviceTicket)) {
252252
HttpSession session = request.getSession(false);
253-
if (session != null) {
254-
gateway = session.getAttribute(TriggerCasGatewayFilter.TRIGGER_CAS_GATEWAY_AUTHENTICATION) != null;
255-
session.removeAttribute(TriggerCasGatewayFilter.TRIGGER_CAS_GATEWAY_AUTHENTICATION);
256-
}
257-
if (gateway) {
253+
if (session != null && session
254+
.getAttribute(CasGatewayAuthenticationRedirectFilter.CAS_GATEWAY_AUTHENTICATION_ATTR) != null) {
258255
this.logger.debug("Failed authentication response from CAS gateway request");
256+
session.removeAttribute(CasGatewayAuthenticationRedirectFilter.CAS_GATEWAY_AUTHENTICATION_ATTR);
259257
SavedRequest savedRequest = this.requestCache.getRequest(request, response);
260258
if (savedRequest != null) {
261-
this.redirectStrategy.sendRedirect(request, response, savedRequest.getRedirectUrl());
259+
String redirectUrl = savedRequest.getRedirectUrl();
260+
this.logger.debug(LogMessage.format("Redirecting to: %s", redirectUrl));
261+
this.requestCache.removeRequest(request, response);
262+
this.redirectStrategy.sendRedirect(request, response, redirectUrl);
263+
return null;
262264
}
263-
return null;
264-
}
265-
else {
266-
this.logger.debug("Failed to obtain an artifact (cas ticket)");
267-
serviceTicket = "";
268265
}
266+
267+
this.logger.debug("Failed to obtain an artifact (cas ticket)");
268+
serviceTicket = "";
269269
}
270270
boolean serviceTicketRequest = serviceTicketRequest(request, response);
271271
CasServiceTicketAuthenticationToken authRequest = serviceTicketRequest
@@ -329,11 +329,23 @@ public final void setServiceProperties(final ServiceProperties serviceProperties
329329
this.authenticateAllArtifacts = serviceProperties.isAuthenticateAllArtifacts();
330330
}
331331

332+
/**
333+
* Set the {@link RedirectStrategy} used to redirect to the saved request if there is
334+
* one saved. Defaults to {@link DefaultRedirectStrategy}.
335+
* @param redirectStrategy the redirect strategy to use
336+
* @since 6.3
337+
*/
332338
public final void setRedirectStrategy(RedirectStrategy redirectStrategy) {
333339
Assert.notNull(redirectStrategy, "redirectStrategy cannot be null");
334340
this.redirectStrategy = redirectStrategy;
335341
}
336342

343+
/**
344+
* The {@link RequestCache} used to retrieve the saved request in failed gateway
345+
* authentication scenarios.
346+
* @param requestCache the request cache to use
347+
* @since 6.3
348+
*/
337349
public final void setRequestCache(RequestCache requestCache) {
338350
Assert.notNull(requestCache, "requestCache cannot be null");
339351
this.requestCache = requestCache;

cas/src/main/java/org/springframework/security/cas/web/CasCookieGatewayRequestMatcher.java

Lines changed: 0 additions & 144 deletions
This file was deleted.
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
* Copyright 2002-2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.cas.web;
18+
19+
import java.io.IOException;
20+
21+
import jakarta.servlet.FilterChain;
22+
import jakarta.servlet.ServletException;
23+
import jakarta.servlet.ServletRequest;
24+
import jakarta.servlet.ServletResponse;
25+
import jakarta.servlet.http.HttpServletRequest;
26+
import jakarta.servlet.http.HttpServletResponse;
27+
import jakarta.servlet.http.HttpSession;
28+
import org.apereo.cas.client.util.CommonUtils;
29+
import org.apereo.cas.client.util.WebUtils;
30+
31+
import org.springframework.security.cas.ServiceProperties;
32+
import org.springframework.security.web.DefaultRedirectStrategy;
33+
import org.springframework.security.web.RedirectStrategy;
34+
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
35+
import org.springframework.security.web.savedrequest.RequestCache;
36+
import org.springframework.security.web.util.matcher.RequestMatcher;
37+
import org.springframework.util.Assert;
38+
import org.springframework.web.filter.GenericFilterBean;
39+
40+
/**
41+
* Redirects the request to the CAS server appending {@code gateway=true} to the URL. Upon
42+
* redirection, the {@link ServiceProperties#isSendRenew()} is ignored and considered as
43+
* {@code false} to align with the specification says that the {@code sendRenew} parameter
44+
* is not compatible with the {@code gateway} parameter. See the <a href=
45+
* "https://apereo.github.io/cas/6.6.x/protocol/CAS-Protocol-V2-Specification.html#:~:text=This%20parameter%20is%20not%20compatible%20with%20the%20%E2%80%9Crenew%E2%80%9D%20parameter.%20Behavior%20is%20undefined%20if%20both%20are%20set.">CAS
46+
* Protocol Specification</a> for more details. To allow other filters to know if the
47+
* request is a gateway request, this filter creates a session and add an attribute with
48+
* name {@link #CAS_GATEWAY_AUTHENTICATION_ATTR} which can be checked by other filters if
49+
* needed. It is recommended that this filter is placed after
50+
* {@link CasAuthenticationFilter} if it is defined.
51+
*
52+
* @author Michael Remond
53+
* @author Jerome LELEU
54+
* @author Marcus da Coregio
55+
* @since 6.3
56+
*/
57+
public final class CasGatewayAuthenticationRedirectFilter extends GenericFilterBean {
58+
59+
public static final String CAS_GATEWAY_AUTHENTICATION_ATTR = "CAS_GATEWAY_AUTHENTICATION";
60+
61+
private final String casLoginUrl;
62+
63+
private final ServiceProperties serviceProperties;
64+
65+
private RequestMatcher requestMatcher;
66+
67+
private RequestCache requestCache = new HttpSessionRequestCache();
68+
69+
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
70+
71+
/**
72+
* Constructs a new instance of this class
73+
* @param serviceProperties the {@link ServiceProperties}
74+
*/
75+
public CasGatewayAuthenticationRedirectFilter(String casLoginUrl, ServiceProperties serviceProperties) {
76+
Assert.hasText(casLoginUrl, "casLoginUrl cannot be null or empty");
77+
Assert.notNull(serviceProperties, "serviceProperties cannot be null");
78+
this.casLoginUrl = casLoginUrl;
79+
this.serviceProperties = serviceProperties;
80+
this.requestMatcher = new CasGatewayResolverRequestMatcher(this.serviceProperties);
81+
}
82+
83+
@Override
84+
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
85+
throws IOException, ServletException {
86+
87+
HttpServletRequest request = (HttpServletRequest) req;
88+
HttpServletResponse response = (HttpServletResponse) res;
89+
90+
if (!this.requestMatcher.matches(request)) {
91+
chain.doFilter(request, response);
92+
return;
93+
}
94+
95+
this.requestCache.saveRequest(request, response);
96+
HttpSession session = request.getSession(true);
97+
session.setAttribute(CAS_GATEWAY_AUTHENTICATION_ATTR, true);
98+
String urlEncodedService = WebUtils.constructServiceUrl(request, response, this.serviceProperties.getService(),
99+
null, this.serviceProperties.getServiceParameter(), this.serviceProperties.getArtifactParameter(),
100+
true);
101+
String redirectUrl = CommonUtils.constructRedirectUrl(this.casLoginUrl,
102+
this.serviceProperties.getServiceParameter(), urlEncodedService, false, true);
103+
this.redirectStrategy.sendRedirect(request, response, redirectUrl);
104+
}
105+
106+
/**
107+
* Sets the {@link RequestMatcher} used to trigger this filter. Defaults to
108+
* {@link CasGatewayResolverRequestMatcher}.
109+
* @param requestMatcher the {@link RequestMatcher} to use
110+
*/
111+
public void setRequestMatcher(RequestMatcher requestMatcher) {
112+
Assert.notNull(requestMatcher, "requestMatcher cannot be null");
113+
this.requestMatcher = requestMatcher;
114+
}
115+
116+
/**
117+
* Sets the {@link RequestCache} used to store the current request to be replayed
118+
* after redirect from the CAS server. Defaults to {@link HttpSessionRequestCache}.
119+
* @param requestCache the {@link RequestCache} to use
120+
*/
121+
public void setRequestCache(RequestCache requestCache) {
122+
Assert.notNull(requestCache, "requestCache cannot be null");
123+
this.requestCache = requestCache;
124+
}
125+
126+
}

0 commit comments

Comments
 (0)