Skip to content

Commit 1e230d0

Browse files
authored
KNOX-3226 - Add RemoteAuthProivder Integration Test (#1125)
* KNOX-3226 - Add RemoteAuthProivder Integration Test
1 parent 73ddf02 commit 1e230d0

File tree

6 files changed

+175
-2
lines changed

6 files changed

+175
-2
lines changed

.github/workflows/build/Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ ADD master /knox-runtime/data/security/master
3737
ADD gateway-site.xml /knox-runtime/conf/gateway-site.xml
3838
ADD conf/topologies/knoxtoken.xml /knox-runtime/conf/topologies/knoxtoken.xml
3939
ADD conf/topologies/knoxldap.xml /knox-runtime/conf/topologies/knoxldap.xml
40+
ADD conf/topologies/remoteauth.xml /knox-runtime/conf/topologies/remoteauth.xml
41+
4042
ADD conf/topologies/health.xml /knox-runtime/conf/topologies/health.xml
4143

4244
RUN chown -R gateway /knox-runtime/

.github/workflows/build/Dockerfile.local

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ ADD gateway-site.xml /knox-runtime/conf/gateway-site.xml
5959
ADD conf/topologies/knoxtoken.xml /knox-runtime/conf/topologies/knoxtoken.xml
6060
ADD conf/topologies/health.xml /knox-runtime/conf/topologies/health.xml
6161
ADD conf/topologies/knoxldap.xml /knox-runtime/conf/topologies/knoxldap.xml
62+
ADD conf/topologies/remoteauth.xml /knox-runtime/conf/topologies/remoteauth.xml
63+
6264

6365
RUN chown -R gateway /knox-runtime/
6466

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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+
<topology>
19+
<gateway>
20+
<provider>
21+
<role>authentication</role>
22+
<name>RemoteAuthProvider</name>
23+
<enabled>true</enabled>
24+
<param>
25+
<name>remote.auth.url</name>
26+
<value>https://localhost:8443/gateway/knoxldap/auth/api/v1/pre</value>
27+
</param>
28+
<param>
29+
<name>remote.auth.include.headers</name>
30+
<value>Authorization</value>
31+
</param>
32+
<param>
33+
<name>remote.auth.expire.after</name>
34+
<value>5</value>
35+
</param>
36+
<param>
37+
<name>remote.auth.user.header</name>
38+
<value>x-knox-actor-username</value>
39+
</param>
40+
<param>
41+
<name>remote.auth.group.header</name>
42+
<value>x-knox-actor-groups-*</value>
43+
</param>
44+
<param>
45+
<name>remote.auth.truststore.path</name>
46+
<value></value>
47+
<!-- Empty path triggers fallback to gateway keystore/truststore which trusts the self-signed cert -->
48+
</param>
49+
</provider>
50+
<provider>
51+
<role>identity-assertion</role>
52+
<name>Default</name>
53+
<enabled>true</enabled>
54+
</provider>
55+
</gateway>
56+
<service>
57+
<role>KNOX-AUTH-SERVICE</role>
58+
<param>
59+
<name>ignore.additional.path</name>
60+
<value>true</value>
61+
</param>
62+
</service>
63+
</topology>

.github/workflows/publish-test-results.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
- name: Download and Extract Artifacts
3737
uses: actions/download-artifact@v4
3838
with:
39-
run_id: ${{ github.event.workflow_run.id }}
39+
run-id: ${{ github.event.workflow_run.id }}
4040
github-token: ${{ secrets.GITHUB_TOKEN }}
4141
path: artifacts
4242

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
requests==2.32.3
1+
requests==2.32.4
22
pytest==8.3.4
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one or more
2+
# contributor license agreements. See the NOTICE file distributed with
3+
# this work for additional information regarding copyright ownership.
4+
# The ASF licenses this file to you under the Apache License, Version 2.0
5+
# (the "License"); you may not use this file except in compliance with
6+
# the License. You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
import os
16+
import unittest
17+
import requests
18+
import urllib3
19+
from requests.auth import HTTPBasicAuth
20+
21+
########################################################
22+
# This test is verifying the behavior of the RemoteAuthProvider.
23+
# It is using the 'auth/api/v1/pre' endpoint to get the actor ID and group headers.
24+
# It is using the 'guest' user to get the guest user headers.
25+
# It is using the 'admin' user to get the admin user headers.
26+
# It is verifying that the actor ID and group headers are correct.
27+
# It is verifying that the actor ID and group headers are not empty.
28+
# It is verifying that the actor ID and group headers are not None.
29+
########################################################
30+
# Suppress InsecureRequestWarning
31+
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
32+
33+
class TestRemoteAuth(unittest.TestCase):
34+
def setUp(self):
35+
self.base_url = os.environ.get("KNOX_GATEWAY_URL", "https://localhost:8443/")
36+
if not self.base_url.endswith("/"):
37+
self.base_url += "/"
38+
self.topology_url = self.base_url + "gateway/remoteauth/auth/api/v1/pre"
39+
40+
def test_remote_auth_success(self):
41+
"""
42+
Verify that valid credentials result in successful authentication
43+
and correct identity assertion using knoxldap as remote auth.
44+
"""
45+
print(f"\nTesting remote auth success against {self.topology_url}")
46+
# The RemoteAuthFilter forwards Authorization header to knoxldap.
47+
# knoxldap accepts guest:guest-password
48+
response = requests.get(
49+
self.topology_url,
50+
auth=HTTPBasicAuth('guest', 'guest-password'),
51+
verify=False,
52+
timeout=30
53+
)
54+
print(f"Status Code: {response.status_code}")
55+
print(f"Headers: {response.headers}")
56+
self.assertEqual(response.status_code, 200)
57+
58+
# RemoteAuthFilter sets principal from x-knox-actor-username (guest)
59+
# KNOX-AUTH-SERVICE (pre endpoint) echoes principal in X-Knox-Actor-ID (default)
60+
self.assertIn('X-Knox-Actor-ID', response.headers)
61+
self.assertEqual(response.headers['X-Knox-Actor-ID'], 'guest')
62+
63+
def test_remote_auth_admin_groups(self):
64+
"""
65+
Verify admin user gets multiple groups from knoxldap mapping
66+
"""
67+
print(f"\nTesting remote auth admin against {self.topology_url}")
68+
response = requests.get(
69+
self.topology_url,
70+
auth=HTTPBasicAuth('admin', 'admin-password'),
71+
verify=False,
72+
timeout=30
73+
)
74+
self.assertEqual(response.status_code, 200)
75+
self.assertEqual(response.headers['X-Knox-Actor-ID'], 'admin')
76+
77+
# knoxldap maps admin to: longGroupName1,longGroupName2,longGroupName3,longGroupName4
78+
# RemoteAuthFilter picks these up from x-knox-actor-groups-*
79+
# And KNOX-AUTH-SERVICE echoes them back in X-Knox-Actor-Groups-*
80+
81+
group_headers = [h for h in response.headers if h.lower().startswith('x-knox-actor-groups')]
82+
all_groups = []
83+
for h in group_headers:
84+
all_groups.extend(response.headers[h].split(','))
85+
86+
print(f"Found groups: {all_groups}")
87+
self.assertIn('longGroupName1', all_groups)
88+
self.assertIn('longGroupName2', all_groups)
89+
90+
def test_remote_auth_failure(self):
91+
"""
92+
Verify invalid credentials result in 401
93+
"""
94+
print(f"\nTesting remote auth failure against {self.topology_url}")
95+
response = requests.get(
96+
self.topology_url,
97+
auth=HTTPBasicAuth('baduser', 'badpass'),
98+
verify=False,
99+
timeout=30
100+
)
101+
print(f"Status Code: {response.status_code}")
102+
# When remote auth fails (knoxldap returns 401), RemoteAuthFilter should return 401
103+
self.assertEqual(response.status_code, 401)
104+
105+
if __name__ == '__main__':
106+
unittest.main()

0 commit comments

Comments
 (0)