1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.springframework.security.ui.logout;
17
18 import java.io.IOException;
19
20 import javax.servlet.FilterChain;
21 import javax.servlet.ServletException;
22 import javax.servlet.http.HttpServletRequest;
23 import javax.servlet.http.HttpServletResponse;
24
25 import org.springframework.security.Authentication;
26 import org.springframework.security.ui.SpringSecurityFilter;
27 import org.springframework.security.ui.FilterChainOrder;
28 import org.springframework.security.util.RedirectUtils;
29 import org.springframework.security.util.UrlUtils;
30 import org.springframework.security.context.SecurityContextHolder;
31 import org.springframework.util.Assert;
32 import org.springframework.util.StringUtils;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 public class LogoutFilter extends SpringSecurityFilter {
49
50
51
52 private String filterProcessesUrl = "/j_spring_security_logout";
53 private String logoutSuccessUrl;
54 private LogoutHandler[] handlers;
55 private boolean useRelativeContext;
56
57
58
59 public LogoutFilter(String logoutSuccessUrl, LogoutHandler[] handlers) {
60 Assert.notEmpty(handlers, "LogoutHandlers are required");
61 this.logoutSuccessUrl = logoutSuccessUrl;
62 Assert.isTrue(UrlUtils.isValidRedirectUrl(logoutSuccessUrl), logoutSuccessUrl + " isn't a valid redirect URL");
63 this.handlers = handlers;
64 }
65
66
67
68 public void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException,
69 ServletException {
70
71 if (requiresLogout(request, response)) {
72 Authentication auth = SecurityContextHolder.getContext().getAuthentication();
73
74 if (logger.isDebugEnabled()) {
75 logger.debug("Logging out user '" + auth + "' and redirecting to logout page");
76 }
77
78 for (int i = 0; i < handlers.length; i++) {
79 handlers[i].logout(request, response, auth);
80 }
81
82 String targetUrl = determineTargetUrl(request, response);
83
84 sendRedirect(request, response, targetUrl);
85
86 return;
87 }
88
89 chain.doFilter(request, response);
90 }
91
92
93
94
95
96
97
98
99
100 protected boolean requiresLogout(HttpServletRequest request, HttpServletResponse response) {
101 String uri = request.getRequestURI();
102 int pathParamIndex = uri.indexOf(';');
103
104 if (pathParamIndex > 0) {
105
106 uri = uri.substring(0, pathParamIndex);
107 }
108
109 int queryParamIndex = uri.indexOf('?');
110
111 if (queryParamIndex > 0) {
112
113 uri = uri.substring(0, queryParamIndex);
114 }
115
116 if ("".equals(request.getContextPath())) {
117 return uri.endsWith(filterProcessesUrl);
118 }
119
120 return uri.endsWith(request.getContextPath() + filterProcessesUrl);
121 }
122
123
124
125
126
127
128
129
130
131 protected String determineTargetUrl(HttpServletRequest request, HttpServletResponse response) {
132 String targetUrl = request.getParameter("logoutSuccessUrl");
133
134 if(!StringUtils.hasLength(targetUrl)) {
135 targetUrl = getLogoutSuccessUrl();
136 }
137
138 if (!StringUtils.hasLength(targetUrl)) {
139 targetUrl = request.getHeader("Referer");
140 }
141
142 if (!StringUtils.hasLength(targetUrl)) {
143 targetUrl = "/";
144 }
145
146 return targetUrl;
147 }
148
149
150
151
152
153
154
155
156
157
158 protected void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url)
159 throws IOException {
160
161 RedirectUtils.sendRedirect(request, response, url, useRelativeContext);
162 }
163
164 public void setFilterProcessesUrl(String filterProcessesUrl) {
165 Assert.hasText(filterProcessesUrl, "FilterProcessesUrl required");
166 Assert.isTrue(UrlUtils.isValidRedirectUrl(filterProcessesUrl), filterProcessesUrl + " isn't a valid redirect URL");
167 this.filterProcessesUrl = filterProcessesUrl;
168 }
169
170 protected String getLogoutSuccessUrl() {
171 return logoutSuccessUrl;
172 }
173
174 protected String getFilterProcessesUrl() {
175 return filterProcessesUrl;
176 }
177
178 public void setUseRelativeContext(boolean useRelativeContext) {
179 this.useRelativeContext = useRelativeContext;
180 }
181
182 public int getOrder() {
183 return FilterChainOrder.LOGOUT_FILTER;
184 }
185 }