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