Skip to content

Commit f1153a7

Browse files
RANGER-5359: Add unit test cases for knox-agent module
1 parent e16ce56 commit f1153a7

File tree

8 files changed

+1963
-0
lines changed

8 files changed

+1963
-0
lines changed

knox-agent/pom.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,18 @@
317317
<version>${junit.jupiter.version}</version>
318318
<scope>test</scope>
319319
</dependency>
320+
<dependency>
321+
<groupId>org.mockito</groupId>
322+
<artifactId>mockito-inline</artifactId>
323+
<version>${mockito.version}</version>
324+
<scope>test</scope>
325+
</dependency>
326+
<dependency>
327+
<groupId>org.mockito</groupId>
328+
<artifactId>mockito-junit-jupiter</artifactId>
329+
<version>${mockito.version}</version>
330+
<scope>test</scope>
331+
</dependency>
320332
</dependencies>
321333
<build>
322334
<sourceDirectory>${basedir}/src/main/java</sourceDirectory>

knox-agent/src/test/java/org/apache/ranger/admin/client/TestRangerAdminJersey2RESTClient.java

Lines changed: 780 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package org.apache.ranger.authorization.knox;
20+
21+
import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
22+
import org.apache.ranger.plugin.policyengine.RangerAccessResource;
23+
import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl;
24+
import org.junit.jupiter.api.Assertions;
25+
import org.junit.jupiter.api.MethodOrderer;
26+
import org.junit.jupiter.api.Test;
27+
import org.junit.jupiter.api.TestMethodOrder;
28+
import org.junit.jupiter.api.extension.ExtendWith;
29+
import org.mockito.junit.jupiter.MockitoExtension;
30+
31+
import java.util.Arrays;
32+
import java.util.HashSet;
33+
import java.util.List;
34+
import java.util.Set;
35+
36+
/**
37+
* @generated by Cursor
38+
* @description <Unit Test for KnoxRangerPlugin class>
39+
*/
40+
@ExtendWith(MockitoExtension.class)
41+
@TestMethodOrder(MethodOrderer.MethodName.class)
42+
public class TestKnoxRangerPlugin {
43+
@Test
44+
public void test01_init_setsResultProcessorOnce() {
45+
KnoxRangerPlugin plugin = new KnoxRangerPlugin();
46+
47+
Assertions.assertNull(plugin.getResultProcessor());
48+
plugin.init();
49+
Assertions.assertNotNull(plugin.getResultProcessor());
50+
51+
// second init should not reset and should not throw
52+
plugin.init();
53+
Assertions.assertNotNull(plugin.getResultProcessor());
54+
}
55+
56+
@Test
57+
public void test02_requestBuilder_verifyBuildable_throwsOnMissing() {
58+
KnoxRangerPlugin.RequestBuilder b = new KnoxRangerPlugin.RequestBuilder();
59+
Assertions.assertThrows(IllegalStateException.class, b::verifyBuildable);
60+
61+
b.service("svc");
62+
Assertions.assertThrows(IllegalStateException.class, b::verifyBuildable);
63+
64+
b.topology("top");
65+
Assertions.assertThrows(IllegalStateException.class, b::verifyBuildable);
66+
67+
b.user("u");
68+
// no exception now
69+
b.verifyBuildable();
70+
}
71+
72+
@Test
73+
public void test03_requestBuilder_build_setsAllFields() {
74+
Set<String> groups = new HashSet<>(Arrays.asList("g1", "g2"));
75+
List<String> fwd = Arrays.asList("1.1.1.1", "2.2.2.2");
76+
77+
KnoxRangerPlugin.RequestBuilder b = new KnoxRangerPlugin.RequestBuilder()
78+
.service("svc")
79+
.topology("top")
80+
.user("user")
81+
.groups(groups)
82+
.clientIp("10.0.0.1")
83+
.remoteIp("10.0.0.1")
84+
.forwardedAddresses(fwd);
85+
86+
RangerAccessRequest req = b.build();
87+
Assertions.assertEquals("user", req.getUser());
88+
Assertions.assertEquals("allow", req.getAction());
89+
Assertions.assertEquals("allow", req.getAccessType());
90+
Assertions.assertEquals("10.0.0.1", req.getClientIPAddress());
91+
Assertions.assertEquals(groups, req.getUserGroups());
92+
Assertions.assertEquals(fwd, req.getForwardedAddresses());
93+
94+
RangerAccessResource res = req.getResource();
95+
Assertions.assertTrue(res instanceof RangerAccessResourceImpl);
96+
Assertions.assertEquals("svc", ((RangerAccessResourceImpl) res).getValue(KnoxRangerPlugin.KnoxConstants.ResourceName.Service));
97+
Assertions.assertEquals("top", ((RangerAccessResourceImpl) res).getValue(KnoxRangerPlugin.KnoxConstants.ResourceName.Topology));
98+
}
99+
}
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package org.apache.ranger.authorization.knox;
20+
21+
import org.apache.knox.gateway.filter.AbstractGatewayFilter;
22+
import org.apache.knox.gateway.security.GroupPrincipal;
23+
import org.apache.knox.gateway.security.ImpersonatedPrincipal;
24+
import org.apache.knox.gateway.security.PrimaryPrincipal;
25+
import org.apache.ranger.audit.provider.MiscUtil;
26+
import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
27+
import org.apache.ranger.plugin.policyengine.RangerAccessResult;
28+
import org.junit.jupiter.api.Assertions;
29+
import org.junit.jupiter.api.MethodOrderer;
30+
import org.junit.jupiter.api.Test;
31+
import org.junit.jupiter.api.TestMethodOrder;
32+
import org.junit.jupiter.api.extension.ExtendWith;
33+
import org.mockito.MockedStatic;
34+
import org.mockito.Mockito;
35+
import org.mockito.junit.jupiter.MockitoExtension;
36+
37+
import javax.security.auth.Subject;
38+
import javax.servlet.FilterChain;
39+
import javax.servlet.FilterConfig;
40+
import javax.servlet.ServletRequest;
41+
import javax.servlet.ServletResponse;
42+
import javax.servlet.http.HttpServletRequest;
43+
import javax.servlet.http.HttpServletResponse;
44+
45+
import java.lang.reflect.Field;
46+
import java.lang.reflect.Method;
47+
import java.security.AccessController;
48+
import java.util.Arrays;
49+
import java.util.List;
50+
51+
import static org.mockito.Mockito.mock;
52+
import static org.mockito.Mockito.times;
53+
import static org.mockito.Mockito.verify;
54+
import static org.mockito.Mockito.when;
55+
56+
/**
57+
* @generated by Cursor
58+
* @description <Unit Test for RangerPDPKnoxFilter class>
59+
*/
60+
@ExtendWith(MockitoExtension.class)
61+
@TestMethodOrder(MethodOrderer.MethodName.class)
62+
public class TestRangerPDPKnoxFilter {
63+
@Test
64+
public void test01_init_initializesPluginOnce() {
65+
RangerPDPKnoxFilter filter = new RangerPDPKnoxFilter();
66+
FilterConfig cfg = mock(FilterConfig.class);
67+
when(cfg.getInitParameter("resource.role"))
68+
.thenReturn("WEBHDFS");
69+
70+
try (MockedStatic<MiscUtil> mu = Mockito.mockStatic(MiscUtil.class)) {
71+
filter.init(cfg);
72+
// second init call should reuse existing plugin and not throw
73+
filter.init(cfg);
74+
}
75+
}
76+
77+
@Test
78+
public void test02_doFilter_accessAllowed_callsChain() throws Exception {
79+
RangerPDPKnoxFilter filter = new RangerPDPKnoxFilter();
80+
81+
// prepare Subject with principals
82+
Subject subject = new Subject();
83+
subject.getPrincipals().add(new PrimaryPrincipal("primary"));
84+
subject.getPrincipals().add(new ImpersonatedPrincipal("impersonated"));
85+
subject.getPrincipals().add(new GroupPrincipal("g1"));
86+
subject.getPrincipals().add(new GroupPrincipal("g2"));
87+
88+
ServletRequest req = mock(HttpServletRequest.class);
89+
ServletResponse res = mock(HttpServletResponse.class);
90+
FilterChain chain = mock(FilterChain.class);
91+
92+
when(req.getAttribute(AbstractGatewayFilter.SOURCE_REQUEST_CONTEXT_URL_ATTRIBUTE_NAME))
93+
.thenReturn("/cluster/top1/path");
94+
when(req.getRemoteAddr()).thenReturn("10.0.0.1");
95+
96+
try (MockedStatic<AccessController> ac = Mockito.mockStatic(AccessController.class)) {
97+
ac.when(AccessController::getContext).thenReturn(null);
98+
// Return our subject for Subject.getSubject(AccessController.getContext())
99+
try (MockedStatic<javax.security.auth.Subject> sub = Mockito.mockStatic(javax.security.auth.Subject.class)) {
100+
sub.when(() -> javax.security.auth.Subject.getSubject(Mockito.any())).thenReturn(subject);
101+
102+
// mock plugin
103+
KnoxRangerPlugin plugin = Mockito.mock(KnoxRangerPlugin.class);
104+
105+
// install plugin via reflection
106+
Field f = RangerPDPKnoxFilter.class.getDeclaredField("plugin");
107+
f.setAccessible(true);
108+
f.set(null, plugin);
109+
110+
RangerAccessResult allow = Mockito.mock(RangerAccessResult.class);
111+
when(allow.getIsAllowed()).thenReturn(true);
112+
when(plugin.isAccessAllowed(Mockito.any(RangerAccessRequest.class))).thenReturn(allow);
113+
114+
filter.doFilter(req, res, chain);
115+
verify(chain, times(1)).doFilter(req, res);
116+
}
117+
}
118+
}
119+
120+
@Test
121+
public void test03_doFilter_accessDenied_sendsForbidden() throws Exception {
122+
RangerPDPKnoxFilter filter = new RangerPDPKnoxFilter();
123+
Subject subject = new Subject();
124+
subject.getPrincipals().add(new PrimaryPrincipal("primary"));
125+
ServletRequest req = mock(HttpServletRequest.class);
126+
HttpServletResponse res = mock(HttpServletResponse.class);
127+
FilterChain chain = mock(FilterChain.class);
128+
129+
when(req.getAttribute(AbstractGatewayFilter.SOURCE_REQUEST_CONTEXT_URL_ATTRIBUTE_NAME))
130+
.thenReturn("/cluster/top1/path");
131+
when(req.getRemoteAddr()).thenReturn("10.0.0.1");
132+
133+
try (MockedStatic<AccessController> ac = Mockito.mockStatic(AccessController.class)) {
134+
ac.when(AccessController::getContext).thenReturn(null);
135+
try (MockedStatic<javax.security.auth.Subject> sub = Mockito.mockStatic(javax.security.auth.Subject.class)) {
136+
sub.when(() -> javax.security.auth.Subject.getSubject(Mockito.any())).thenReturn(subject);
137+
138+
KnoxRangerPlugin plugin = Mockito.mock(KnoxRangerPlugin.class);
139+
Field f = RangerPDPKnoxFilter.class.getDeclaredField("plugin");
140+
f.setAccessible(true);
141+
f.set(null, plugin);
142+
143+
RangerAccessResult deny = Mockito.mock(RangerAccessResult.class);
144+
when(deny.getIsAllowed()).thenReturn(false);
145+
when(plugin.isAccessAllowed(Mockito.any(RangerAccessRequest.class))).thenReturn(deny);
146+
147+
filter.doFilter(req, res, chain);
148+
verify(res, times(1)).sendError(403);
149+
}
150+
}
151+
}
152+
153+
@Test
154+
public void test04_getInitParameter_lowercasesName() {
155+
RangerPDPKnoxFilter filter = new RangerPDPKnoxFilter();
156+
FilterConfig cfg = mock(FilterConfig.class);
157+
when(cfg.getInitParameter("resource.role")).thenReturn("WEBHDFS");
158+
Assertions.assertEquals("WEBHDFS", invokeGetInitParameter(filter, cfg, "RESOURCE.ROLE"));
159+
}
160+
161+
@Test
162+
public void test05_getForwardedAddresses_parsesHeader() {
163+
RangerPDPKnoxFilter filter = new RangerPDPKnoxFilter();
164+
HttpServletRequest req = mock(HttpServletRequest.class);
165+
when(req.getHeader("X-Forwarded-For")).thenReturn("1.1.1.1,2.2.2.2");
166+
List<String> addrs = invokeGetForwardedAddresses(filter, req);
167+
Assertions.assertEquals(Arrays.asList("1.1.1.1", "2.2.2.2"), addrs);
168+
169+
when(req.getHeader("X-Forwarded-For")).thenReturn(null);
170+
Assertions.assertNull(invokeGetForwardedAddresses(filter, req));
171+
}
172+
173+
@Test
174+
public void test06_getTopologyName_extractsThirdTokenOrNull() {
175+
RangerPDPKnoxFilter filter = new RangerPDPKnoxFilter();
176+
Assertions.assertNull(invokeGetTopologyName(filter, null));
177+
Assertions.assertNull(invokeGetTopologyName(filter, "/one"));
178+
Assertions.assertEquals("two", invokeGetTopologyName(filter, "/one/two/three"));
179+
}
180+
181+
private String invokeGetInitParameter(RangerPDPKnoxFilter filter, FilterConfig cfg, String name) {
182+
try {
183+
Method m = RangerPDPKnoxFilter.class.getDeclaredMethod("getInitParameter", FilterConfig.class, String.class);
184+
m.setAccessible(true);
185+
return (String) m.invoke(filter, cfg, name);
186+
} catch (Exception e) {
187+
throw new RuntimeException(e);
188+
}
189+
}
190+
191+
private List<String> invokeGetForwardedAddresses(RangerPDPKnoxFilter filter, ServletRequest req) {
192+
try {
193+
Method m = RangerPDPKnoxFilter.class.getDeclaredMethod("getForwardedAddresses", ServletRequest.class);
194+
m.setAccessible(true);
195+
@SuppressWarnings("unchecked")
196+
List<String> ret = (List<String>) m.invoke(filter, req);
197+
return ret;
198+
} catch (Exception e) {
199+
throw new RuntimeException(e);
200+
}
201+
}
202+
203+
private String invokeGetTopologyName(RangerPDPKnoxFilter filter, String url) {
204+
try {
205+
Method m = RangerPDPKnoxFilter.class.getDeclaredMethod("getTopologyName", String.class);
206+
m.setAccessible(true);
207+
return (String) m.invoke(filter, url);
208+
} catch (Exception e) {
209+
throw new RuntimeException(e);
210+
}
211+
}
212+
}

0 commit comments

Comments
 (0)