1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package waffle.spring;
25
26 import java.io.IOException;
27 import java.util.Locale;
28
29 import javax.servlet.FilterChain;
30 import javax.servlet.ServletException;
31 import javax.servlet.ServletRequest;
32 import javax.servlet.ServletResponse;
33 import javax.servlet.http.HttpServletRequest;
34 import javax.servlet.http.HttpServletResponse;
35
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38 import org.springframework.security.core.Authentication;
39 import org.springframework.security.core.GrantedAuthority;
40 import org.springframework.security.core.context.SecurityContextHolder;
41 import org.springframework.web.filter.GenericFilterBean;
42
43 import waffle.servlet.AutoDisposableWindowsPrincipal;
44 import waffle.servlet.WindowsPrincipal;
45 import waffle.servlet.spi.SecurityFilterProviderCollection;
46 import waffle.util.AuthorizationHeader;
47 import waffle.windows.auth.IWindowsIdentity;
48 import waffle.windows.auth.IWindowsImpersonationContext;
49 import waffle.windows.auth.PrincipalFormat;
50
51
52
53
54 public class NegotiateSecurityFilter extends GenericFilterBean {
55
56
57 private static final Logger LOGGER = LoggerFactory.getLogger(NegotiateSecurityFilter.class);
58
59
60 private SecurityFilterProviderCollection provider;
61
62
63 private PrincipalFormat principalFormat = PrincipalFormat.FQN;
64
65
66 private PrincipalFormat roleFormat = PrincipalFormat.FQN;
67
68
69 private boolean allowGuestLogin = true;
70
71
72 private boolean impersonate;
73
74
75 private GrantedAuthorityFactory grantedAuthorityFactory = WindowsAuthenticationToken.DEFAULT_GRANTED_AUTHORITY_FACTORY;
76
77
78 private GrantedAuthority defaultGrantedAuthority = WindowsAuthenticationToken.DEFAULT_GRANTED_AUTHORITY;
79
80
81
82
83 public NegotiateSecurityFilter() {
84 super();
85 NegotiateSecurityFilter.LOGGER.debug("[waffle.spring.NegotiateSecurityFilter] loaded");
86 }
87
88 @Override
89 public void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain)
90 throws IOException, ServletException {
91
92 final HttpServletRequest request = (HttpServletRequest) req;
93 final HttpServletResponse response = (HttpServletResponse) res;
94
95 NegotiateSecurityFilter.LOGGER.debug("{} {}, contentlength: {}", request.getMethod(), request.getRequestURI(),
96 Integer.valueOf(request.getContentLength()));
97
98 final AuthorizationHeader authorizationHeader = new AuthorizationHeader(request);
99
100
101 if (!authorizationHeader.isNull()
102 && this.provider.isSecurityPackageSupported(authorizationHeader.getSecurityPackage())) {
103
104
105 IWindowsIdentity windowsIdentity;
106
107 try {
108 windowsIdentity = this.provider.doFilter(request, response);
109 if (windowsIdentity == null) {
110 return;
111 }
112 } catch (final IOException e) {
113 NegotiateSecurityFilter.LOGGER.warn("error logging in user: {}", e.getMessage());
114 NegotiateSecurityFilter.LOGGER.trace("", e);
115 this.sendUnauthorized(response, true);
116 return;
117 }
118
119 IWindowsImpersonationContext ctx = null;
120 try {
121 if (!this.allowGuestLogin && windowsIdentity.isGuest()) {
122 NegotiateSecurityFilter.LOGGER.warn("guest login disabled: {}", windowsIdentity.getFqn());
123 this.sendUnauthorized(response, true);
124 return;
125 }
126
127 NegotiateSecurityFilter.LOGGER.debug("logged in user: {} ({})", windowsIdentity.getFqn(),
128 windowsIdentity.getSidString());
129
130 final WindowsPrincipal principal = this.impersonate
131 ? new AutoDisposableWindowsPrincipal(windowsIdentity, this.principalFormat, this.roleFormat)
132 : new WindowsPrincipal(windowsIdentity, this.principalFormat, this.roleFormat);
133
134 NegotiateSecurityFilter.LOGGER.debug("roles: {}", principal.getRolesString());
135
136 final Authentication authentication = new WindowsAuthenticationToken(principal,
137 this.grantedAuthorityFactory, this.defaultGrantedAuthority);
138
139 if (!this.setAuthentication(request, response, authentication)) {
140 return;
141 }
142
143 NegotiateSecurityFilter.LOGGER.info("successfully logged in user: {}", windowsIdentity.getFqn());
144
145 if (this.impersonate) {
146 NegotiateSecurityFilter.LOGGER.debug("impersonating user");
147 ctx = windowsIdentity.impersonate();
148 }
149
150 chain.doFilter(request, response);
151 } finally {
152 if (this.impersonate && ctx != null) {
153 NegotiateSecurityFilter.LOGGER.debug("terminating impersonation");
154 ctx.revertToSelf();
155 } else {
156 windowsIdentity.dispose();
157 }
158 }
159 } else {
160 chain.doFilter(request, response);
161 }
162 }
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177 protected boolean setAuthentication(final HttpServletRequest request, final HttpServletResponse response,
178 final Authentication authentication) {
179 SecurityContextHolder.getContext().setAuthentication(authentication);
180 return true;
181 }
182
183 @Override
184 public void afterPropertiesSet() throws ServletException {
185 super.afterPropertiesSet();
186
187 if (this.provider == null) {
188 throw new ServletException("Missing NegotiateSecurityFilter.Provider");
189 }
190 }
191
192
193
194
195
196
197
198
199
200 protected void sendUnauthorized(final HttpServletResponse response, final boolean close) {
201 try {
202 this.provider.sendUnauthorized(response);
203 if (close) {
204 response.setHeader("Connection", "close");
205 } else {
206 response.setHeader("Connection", "keep-alive");
207 }
208 response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
209 response.flushBuffer();
210 } catch (final IOException e) {
211 throw new RuntimeException(e);
212 }
213 }
214
215
216
217
218
219
220 public PrincipalFormat getPrincipalFormat() {
221 return this.principalFormat;
222 }
223
224
225
226
227
228
229
230 public void setPrincipalFormatEnum(final PrincipalFormat value) {
231 this.principalFormat = value;
232 }
233
234
235
236
237
238
239
240 public void setPrincipalFormat(final String value) {
241 this.setPrincipalFormatEnum(PrincipalFormat.valueOf(value.toUpperCase(Locale.ENGLISH)));
242 }
243
244
245
246
247
248
249 public PrincipalFormat getRoleFormat() {
250 return this.roleFormat;
251 }
252
253
254
255
256
257
258
259 public void setRoleFormatEnum(final PrincipalFormat value) {
260 this.roleFormat = value;
261 }
262
263
264
265
266
267
268
269 public void setRoleFormat(final String value) {
270 this.setRoleFormatEnum(PrincipalFormat.valueOf(value.toUpperCase(Locale.ENGLISH)));
271 }
272
273
274
275
276
277
278 public boolean isAllowGuestLogin() {
279 return this.allowGuestLogin;
280 }
281
282
283
284
285
286
287
288 public void setAllowGuestLogin(final boolean value) {
289 this.allowGuestLogin = value;
290 }
291
292
293
294
295
296
297
298 public void setImpersonate(final boolean value) {
299 this.impersonate = value;
300 }
301
302
303
304
305
306
307 public boolean isImpersonate() {
308 return this.impersonate;
309 }
310
311
312
313
314
315
316 public SecurityFilterProviderCollection getProvider() {
317 return this.provider;
318 }
319
320
321
322
323
324
325
326 public void setProvider(final SecurityFilterProviderCollection value) {
327 this.provider = value;
328 }
329
330
331
332
333
334
335 public GrantedAuthorityFactory getGrantedAuthorityFactory() {
336 return this.grantedAuthorityFactory;
337 }
338
339
340
341
342
343
344
345 public void setGrantedAuthorityFactory(final GrantedAuthorityFactory value) {
346 this.grantedAuthorityFactory = value;
347 }
348
349
350
351
352
353
354 public GrantedAuthority getDefaultGrantedAuthority() {
355 return this.defaultGrantedAuthority;
356 }
357
358
359
360
361
362
363
364 public void setDefaultGrantedAuthority(final GrantedAuthority value) {
365 this.defaultGrantedAuthority = value;
366 }
367 }