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.servlet;
25
26 import com.sun.jna.WString;
27 import com.sun.jna.platform.win32.Advapi32Util;
28 import com.sun.jna.platform.win32.LMAccess;
29 import com.sun.jna.platform.win32.LMErr;
30 import com.sun.jna.platform.win32.Netapi32;
31
32 import java.io.IOException;
33 import java.nio.charset.StandardCharsets;
34 import java.security.Principal;
35 import java.util.Base64;
36
37 import javax.security.auth.Subject;
38 import javax.servlet.ServletException;
39
40 import org.junit.jupiter.api.AfterEach;
41 import org.junit.jupiter.api.Assertions;
42 import org.junit.jupiter.api.Assumptions;
43 import org.junit.jupiter.api.BeforeEach;
44 import org.junit.jupiter.api.Test;
45
46 import waffle.mock.MockWindowsAccount;
47 import waffle.mock.http.RecordUserNameFilterChain;
48 import waffle.mock.http.SimpleHttpRequest;
49 import waffle.mock.http.SimpleHttpResponse;
50 import waffle.windows.auth.impl.WindowsAuthProviderImpl;
51
52
53
54
55 class ImpersonateTest {
56
57
58 private NegotiateSecurityFilter filter;
59
60
61 private LMAccess.USER_INFO_1 userInfo;
62
63
64 private int resultOfNetAddUser;
65
66
67
68
69 @BeforeEach
70 void setUp() {
71 this.filter = new NegotiateSecurityFilter();
72 this.filter.setAuth(new WindowsAuthProviderImpl());
73 try {
74 this.filter.init(null);
75 } catch (final ServletException e) {
76 Assertions.fail(e.getMessage());
77 }
78
79 this.userInfo = new LMAccess.USER_INFO_1();
80 this.userInfo.usri1_name = new WString(MockWindowsAccount.TEST_USER_NAME).toString();
81 this.userInfo.usri1_password = new WString(MockWindowsAccount.TEST_PASSWORD).toString();
82 this.userInfo.usri1_priv = LMAccess.USER_PRIV_USER;
83
84 this.resultOfNetAddUser = Netapi32.INSTANCE.NetUserAdd(null, 1, this.userInfo, null);
85
86 Assumptions.assumeTrue(LMErr.NERR_Success == this.resultOfNetAddUser);
87 }
88
89
90
91
92 @AfterEach
93 void tearDown() {
94 this.filter.destroy();
95
96 if (LMErr.NERR_Success == this.resultOfNetAddUser) {
97 Assertions.assertEquals(LMErr.NERR_Success, Netapi32.INSTANCE.NetUserDel(null, this.userInfo.usri1_name));
98 }
99 }
100
101
102
103
104
105
106
107
108
109 @Test
110 void testImpersonateEnabled() throws IOException, ServletException {
111
112 Assertions.assertNotEquals(MockWindowsAccount.TEST_USER_NAME, Advapi32Util.getUserName(),
113 "Current user shouldn't be the test user prior to the test");
114
115 final SimpleHttpRequest request = new SimpleHttpRequest();
116 request.setMethod("GET");
117 final String userHeaderValue = MockWindowsAccount.TEST_USER_NAME + ":" + MockWindowsAccount.TEST_PASSWORD;
118 final String basicAuthHeader = "Basic "
119 + Base64.getEncoder().encodeToString(userHeaderValue.getBytes(StandardCharsets.UTF_8));
120 request.addHeader("Authorization", basicAuthHeader);
121
122 final SimpleHttpResponse response = new SimpleHttpResponse();
123 final RecordUserNameFilterChain filterChain = new RecordUserNameFilterChain();
124
125 AutoDisposableWindowsPrincipal windowsPrincipal = null;
126 try {
127 this.filter.setImpersonate(true);
128 this.filter.doFilter(request, response, filterChain);
129
130 final Subject subject = (Subject) request.getSession(false).getAttribute("javax.security.auth.subject");
131 final boolean authenticated = subject != null && subject.getPrincipals().size() > 0;
132 Assertions.assertTrue(authenticated, "Test user should be authenticated");
133
134 final Principal principal = subject.getPrincipals().iterator().next();
135 Assertions.assertTrue(principal instanceof AutoDisposableWindowsPrincipal);
136 windowsPrincipal = (AutoDisposableWindowsPrincipal) principal;
137
138 Assertions.assertEquals(MockWindowsAccount.TEST_USER_NAME, filterChain.getUserName(),
139 "Test user should be impersonated");
140 Assertions.assertNotEquals(MockWindowsAccount.TEST_USER_NAME, Advapi32Util.getUserName(),
141 "Impersonation context should have been reverted");
142 } finally {
143 if (windowsPrincipal != null) {
144 windowsPrincipal.getIdentity().dispose();
145 }
146 }
147 }
148
149
150
151
152
153
154
155
156
157 @Test
158 void testImpersonateDisabled() throws IOException, ServletException {
159
160 Assertions.assertNotEquals(MockWindowsAccount.TEST_USER_NAME, Advapi32Util.getUserName(),
161 "Current user shouldn't be the test user prior to the test");
162 final SimpleHttpRequest request = new SimpleHttpRequest();
163 request.setMethod("GET");
164 final String userHeaderValue = MockWindowsAccount.TEST_USER_NAME + ":" + MockWindowsAccount.TEST_PASSWORD;
165 final String basicAuthHeader = "Basic "
166 + Base64.getEncoder().encodeToString(userHeaderValue.getBytes(StandardCharsets.UTF_8));
167 request.addHeader("Authorization", basicAuthHeader);
168 final SimpleHttpResponse response = new SimpleHttpResponse();
169 final RecordUserNameFilterChain filterChain = new RecordUserNameFilterChain();
170
171 WindowsPrincipal windowsPrincipal = null;
172 try {
173 this.filter.setImpersonate(false);
174 this.filter.doFilter(request, response, filterChain);
175
176 final Subject subject = (Subject) request.getSession(false).getAttribute("javax.security.auth.subject");
177 final boolean authenticated = subject != null && subject.getPrincipals().size() > 0;
178 Assertions.assertTrue(authenticated, "Test user should be authenticated");
179
180 final Principal principal = subject.getPrincipals().iterator().next();
181 Assertions.assertTrue(principal instanceof WindowsPrincipal);
182 windowsPrincipal = (WindowsPrincipal) principal;
183
184 Assertions.assertNotEquals(MockWindowsAccount.TEST_USER_NAME, filterChain.getUserName(),
185 "Test user should not be impersonated");
186 Assertions.assertNotEquals(MockWindowsAccount.TEST_USER_NAME, Advapi32Util.getUserName(),
187 "Impersonation context should have been reverted");
188 } finally {
189 if (windowsPrincipal != null) {
190 windowsPrincipal.getIdentity().dispose();
191 }
192 }
193 }
194 }