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