1
2
3
4
5
6
7
8
9
10
11
12
13
14 package waffle.apache;
15
16 import java.io.IOException;
17 import java.security.Principal;
18
19 import javax.servlet.http.HttpServletResponse;
20 import javax.servlet.http.HttpSession;
21
22 import org.apache.catalina.LifecycleException;
23 import org.apache.catalina.connector.Request;
24 import org.slf4j.LoggerFactory;
25
26 import com.google.common.io.BaseEncoding;
27 import com.sun.jna.platform.win32.Win32Exception;
28
29 import waffle.util.AuthorizationHeader;
30 import waffle.util.NtlmServletRequest;
31 import waffle.windows.auth.IWindowsIdentity;
32 import waffle.windows.auth.IWindowsSecurityContext;
33
34
35
36
37
38
39 public class NegotiateAuthenticator extends WaffleAuthenticatorBase {
40
41
42
43
44 public NegotiateAuthenticator() {
45 super();
46 this.log = LoggerFactory.getLogger(NegotiateAuthenticator.class);
47 this.info = "waffle.apache.NegotiateAuthenticator/1.0";
48 this.log.debug("[waffle.apache.NegotiateAuthenticator] loaded");
49 }
50
51
52
53
54 @Override
55 public synchronized void startInternal() throws LifecycleException {
56 this.log.info("[waffle.apache.NegotiateAuthenticator] started");
57 super.startInternal();
58 }
59
60
61
62
63 @Override
64 public synchronized void stopInternal() throws LifecycleException {
65 super.stopInternal();
66 this.log.info("[waffle.apache.NegotiateAuthenticator] stopped");
67 }
68
69
70
71
72 @Override
73 public boolean authenticate(final Request request, final HttpServletResponse response) {
74
75 Principal principal = request.getUserPrincipal();
76 final AuthorizationHeader authorizationHeader = new AuthorizationHeader(request);
77 final boolean ntlmPost = authorizationHeader.isNtlmType1PostAuthorizationHeader();
78
79 this.log.debug("{} {}, contentlength: {}", request.getMethod(), request.getRequestURI(),
80 Integer.valueOf(request.getContentLength()));
81 this.log.debug("authorization: {}, ntlm post: {}", authorizationHeader, Boolean.valueOf(ntlmPost));
82
83 if (principal != null && !ntlmPost) {
84
85 this.log.debug("previously authenticated user: {}", principal.getName());
86 return true;
87 }
88
89
90 if (!authorizationHeader.isNull()) {
91
92 final String securityPackage = authorizationHeader.getSecurityPackage();
93
94 final String connectionId = NtlmServletRequest.getConnectionId(request);
95
96 this.log.debug("security package: {}, connection id: {}", securityPackage, connectionId);
97
98 if (ntlmPost) {
99
100 this.auth.resetSecurityToken(connectionId);
101 }
102
103
104 IWindowsSecurityContext securityContext;
105
106 try {
107 final byte[] tokenBuffer = authorizationHeader.getTokenBytes();
108 this.log.debug("token buffer: {} byte(s)", Integer.valueOf(tokenBuffer.length));
109 try {
110 securityContext = this.auth.acceptSecurityToken(connectionId, tokenBuffer, securityPackage);
111 } catch (final Win32Exception e) {
112 this.log.warn("error logging in user: {}", e.getMessage());
113 this.log.trace("{}", e);
114 this.sendUnauthorized(response);
115 return false;
116 }
117 this.log.debug("continue required: {}", Boolean.valueOf(securityContext.isContinue()));
118
119 final byte[] continueTokenBytes = securityContext.getToken();
120 if (continueTokenBytes != null && continueTokenBytes.length > 0) {
121 final String continueToken = BaseEncoding.base64().encode(continueTokenBytes);
122 this.log.debug("continue token: {}", continueToken);
123 response.addHeader("WWW-Authenticate", securityPackage + " " + continueToken);
124 }
125
126 if (securityContext.isContinue() || ntlmPost) {
127 response.setHeader("Connection", "keep-alive");
128 response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
129 response.flushBuffer();
130 return false;
131 }
132
133 } catch (final IOException e) {
134 this.log.warn("error logging in user: {}", e.getMessage());
135 this.log.trace("{}", e);
136 this.sendUnauthorized(response);
137 return false;
138 }
139
140
141 if (this.context == null || this.context.getRealm() == null) {
142 this.log.warn("missing context/realm");
143 this.sendError(response, HttpServletResponse.SC_SERVICE_UNAVAILABLE);
144 return false;
145 }
146
147
148 final IWindowsIdentity windowsIdentity = securityContext.getIdentity();
149
150
151 if (!this.allowGuestLogin && windowsIdentity.isGuest()) {
152 this.log.warn("guest login disabled: {}", windowsIdentity.getFqn());
153 this.sendUnauthorized(response);
154 return false;
155 }
156
157 try {
158 this.log.debug("logged in user: {} ({})", windowsIdentity.getFqn(), windowsIdentity.getSidString());
159
160 final GenericWindowsPrincipal windowsPrincipal = new GenericWindowsPrincipal(windowsIdentity,
161 this.principalFormat, this.roleFormat);
162
163 this.log.debug("roles: {}", windowsPrincipal.getRolesString());
164
165 principal = windowsPrincipal;
166
167
168 final HttpSession session = request.getSession(true);
169 this.log.debug("session id: {}", session == null ? "null" : session.getId());
170
171
172 this.register(request, response, principal, securityPackage, principal.getName(), null);
173 this.log.info("successfully logged in user: {}", principal.getName());
174
175 } finally {
176 windowsIdentity.dispose();
177 }
178
179 return true;
180 }
181
182 this.log.debug("authorization required");
183 this.sendUnauthorized(response);
184 return false;
185 }
186 }