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 static org.assertj.core.api.Assertions.assertThat;
27
28 import com.sun.jna.WString;
29 import com.sun.jna.platform.win32.Advapi32Util;
30 import com.sun.jna.platform.win32.LMAccess;
31 import com.sun.jna.platform.win32.LMErr;
32 import com.sun.jna.platform.win32.Netapi32;
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.servlet.ServletException;
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 import org.springframework.security.core.Authentication;
47 import org.springframework.security.core.context.SecurityContextHolder;
48
49 import waffle.mock.MockWindowsAccount;
50 import waffle.mock.http.RecordUserNameFilterChain;
51 import waffle.mock.http.SimpleHttpRequest;
52 import waffle.mock.http.SimpleHttpResponse;
53 import waffle.servlet.AutoDisposableWindowsPrincipal;
54 import waffle.servlet.WindowsPrincipal;
55 import waffle.servlet.spi.SecurityFilterProviderCollection;
56 import waffle.windows.auth.impl.WindowsAuthProviderImpl;
57
58
59
60
61 class ImpersonateTest {
62
63
64 private waffle.spring.NegotiateSecurityFilter filter;
65
66
67 private LMAccess.USER_INFO_1 userInfo;
68
69
70 private int resultOfNetAddUser;
71
72
73
74
75 @BeforeEach
76 void setUp() {
77 this.filter = new NegotiateSecurityFilter();
78 this.filter.setProvider(new SecurityFilterProviderCollection(new WindowsAuthProviderImpl()));
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 Assumptions.assumeTrue(this.resultOfNetAddUser == LMErr.NERR_Success,
87 "Unable to add user (need to be administrator to do this).");
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.assertNotEquals("Current user shouldn't be the test user prior to the test",
114 MockWindowsAccount.TEST_USER_NAME, Advapi32Util.getUserName());
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 this.filter.setImpersonate(true);
127 this.filter.doFilter(request, response, filterChain);
128
129 final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
130 Assertions.assertTrue(authentication.isAuthenticated(), "Test user should be authenticated");
131
132 final Principal principal = (Principal) authentication.getPrincipal();
133 assertThat(principal).isInstanceOf(AutoDisposableWindowsPrincipal.class);
134 final AutoDisposableWindowsPrincipal windowsPrincipal = (AutoDisposableWindowsPrincipal) principal;
135 try {
136 Assertions.assertEquals(MockWindowsAccount.TEST_USER_NAME, filterChain.getUserName(),
137 "Test user should be impersonated");
138 Assertions.assertNotEquals(MockWindowsAccount.TEST_USER_NAME, Advapi32Util.getUserName(),
139 "Impersonation context should have been reverted");
140 } finally {
141 windowsPrincipal.getIdentity().dispose();
142 }
143 }
144
145
146
147
148
149
150
151
152
153 @Test
154 void testImpersonateDisabled() throws IOException, ServletException {
155
156 Assertions.assertNotEquals("Current user shouldn't be the test user prior to the test",
157 MockWindowsAccount.TEST_USER_NAME, Advapi32Util.getUserName());
158 final SimpleHttpRequest request = new SimpleHttpRequest();
159 request.setMethod("GET");
160 final String userHeaderValue = MockWindowsAccount.TEST_USER_NAME + ":" + MockWindowsAccount.TEST_PASSWORD;
161 final String basicAuthHeader = "Basic "
162 + Base64.getEncoder().encodeToString(userHeaderValue.getBytes(StandardCharsets.UTF_8));
163 request.addHeader("Authorization", basicAuthHeader);
164 final SimpleHttpResponse response = new SimpleHttpResponse();
165 final RecordUserNameFilterChain filterChain = new RecordUserNameFilterChain();
166
167 this.filter.setImpersonate(false);
168 this.filter.doFilter(request, response, filterChain);
169
170 final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
171 Assertions.assertTrue(authentication.isAuthenticated(), "Test user should be authenticated");
172
173 final Principal principal = (Principal) authentication.getPrincipal();
174 assertThat(principal).isInstanceOf(WindowsPrincipal.class);
175 final WindowsPrincipal windowsPrincipal = (WindowsPrincipal) principal;
176 try {
177 Assertions.assertNotEquals(MockWindowsAccount.TEST_USER_NAME, filterChain.getUserName(),
178 "Test user should not be impersonated");
179 Assertions.assertNotEquals(MockWindowsAccount.TEST_USER_NAME, Advapi32Util.getUserName(),
180 "Impersonation context should have been reverted");
181 } finally {
182 windowsPrincipal.getIdentity().dispose();
183 }
184 }
185 }