Skip to content

Commit 55b79f8

Browse files
author
Agent
committed
Add OIDC authentication to integration tests
Deploys Dex (OIDC provider) and GLAuth (LDAP) alongside CTS in the EaaS pipeline and exercises the full mod_auth_openidc → load_openidc_user → get_user_info → query_ldap_groups → has_role auth stack end-to-end. Pipeline changes (.tekton/integration-test-eaas.yaml): - New deploy-glauth task (parallel with deploy-dex, after provision-environment): creates a ConfigMap with a GLAuth config defining two users (builder/readonly) and one group (cts-builders), then deploys GLAuth on port 3893. - New deploy-dex task (parallel with deploy-glauth): creates a ConfigMap with a Dex config using the password connector and a static OAuth2 client (cts-integration), then deploys Dex on port 5556. - Updated deploy-cts: runAfter now includes deploy-glauth and deploy-dex. The cts-config ConfigMap sets AUTH_BACKEND=openidc, AUTH_OPENIDC_USERINFO_URI, AUTH_LDAP_SERVER, AUTH_LDAP_GROUPS, ADMINS, and ALLOWED_BUILDERS. The httpd.conf uses AuthType oauth20 (Resource Server mode) so that OIDCOAuthVerifyJwksUri validates Bearer tokens as JWTs locally against Dex's JWKS endpoint (http://dex:5556/keys) and populates OIDC_access_token and OIDC_CLAIM_* in the WSGI environ — the variables required by load_openidc_user. OIDCOAuthSSLValidateServer Off and OIDCSSLValidateServer Off allow the HTTP-only Dex endpoint. OIDCOAuthUnAuthAction pass lets unauthenticated requests through to Apache's authz phase; the <RequireAny> block then allows unauthenticated GET requests (for the readiness probe and read endpoints) while the Require valid-user directive rejects unauthenticated POSTs with 401. AuthType openid-connect was replaced with AuthType oauth20 because the OIDCOAuth* family of directives (including OIDCOAuthVerifyJwksUri) only activates under the oauth20 auth type; under openid-connect, bearer tokens are not validated via JWKS and OIDC_access_token is never set. - Updated run-tests: installs requests alongside pytest and passes AUTH_BACKEND=openidc so the auth tests are not skipped. Test changes (tests/test_integration_api.py): - AuthHTTPClient: HTTPClient subclass that injects Authorization: Bearer on every request. - _get_oidc_token(): obtains a real access token from Dex via the ROPC grant. - write_http_client fixture: returns an AuthHTTPClient (builder token) under OIDC or a plain HTTPClient in noauth mode; used by the five pre-existing workflow tests so they continue to pass in both modes. - Four new test functions (skipped when AUTH_BACKEND != openidc): test_auth_unauthenticated_write_returns_401, test_auth_builder_can_post_compose, test_auth_unauthorized_user_returns_403, test_auth_get_endpoints_accessible_without_token. Generated-By: OpenCode (google-vertex-anthropic/claude-sonnet-4-6@default)
1 parent 6552ee2 commit 55b79f8

2 files changed

Lines changed: 534 additions & 32 deletions

File tree

.tekton/integration-test-eaas.yaml

Lines changed: 318 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,293 @@ spec:
7777
- name: ownerUid
7878
value: $(context.pipelineRun.uid)
7979

80+
- name: deploy-glauth
81+
runAfter:
82+
- provision-environment
83+
taskSpec:
84+
params:
85+
- name: kubeconfig-secret
86+
type: string
87+
steps:
88+
- name: create-glauth
89+
image: quay.io/konflux-ci/appstudio-utils:latest
90+
script: |
91+
#!/usr/bin/env bash
92+
set -euo pipefail
93+
94+
KUBECONFIG=/tmp/kubeconfig
95+
kubectl get secret $(params.kubeconfig-secret) -o jsonpath='{.data.kubeconfig}' | base64 -d > $KUBECONFIG
96+
export KUBECONFIG
97+
98+
echo "=========================================="
99+
echo "Deploying GLAuth LDAP Server"
100+
echo "=========================================="
101+
102+
kubectl apply -f - <<'EOFYAML'
103+
apiVersion: v1
104+
kind: ConfigMap
105+
metadata:
106+
name: glauth-config
107+
data:
108+
glauth.cfg: |
109+
[ldap]
110+
enabled = true
111+
listen = "0.0.0.0:3893"
112+
113+
[ldaps]
114+
enabled = false
115+
116+
[backend]
117+
datastore = "config"
118+
baseDN = "dc=example,dc=com"
119+
120+
[[users]]
121+
name = "builder"
122+
unixid = 5001
123+
primarygroup = 5501
124+
passsha256 = "6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a"
125+
[[users.capabilities]]
126+
action = "search"
127+
object = "*"
128+
129+
[[users]]
130+
name = "readonly"
131+
unixid = 5002
132+
primarygroup = 5502
133+
passsha256 = "6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a"
134+
[[users.capabilities]]
135+
action = "search"
136+
object = "*"
137+
138+
[[groups]]
139+
name = "cts-builders"
140+
unixid = 5501
141+
includegroups = []
142+
143+
[[groups]]
144+
name = "readonly-users"
145+
unixid = 5502
146+
includegroups = []
147+
EOFYAML
148+
149+
kubectl apply -f - <<'EOFYAML'
150+
apiVersion: apps/v1
151+
kind: Deployment
152+
metadata:
153+
name: glauth
154+
labels:
155+
app: glauth
156+
spec:
157+
replicas: 1
158+
selector:
159+
matchLabels:
160+
app: glauth
161+
template:
162+
metadata:
163+
labels:
164+
app: glauth
165+
spec:
166+
containers:
167+
- name: glauth
168+
image: docker.io/glauth/glauth:v2.3.2
169+
command: ["/app/glauth"]
170+
args: ["-c", "/etc/glauth/glauth.cfg"]
171+
ports:
172+
- containerPort: 3893
173+
name: ldap
174+
readinessProbe:
175+
tcpSocket:
176+
port: 3893
177+
initialDelaySeconds: 3
178+
periodSeconds: 5
179+
failureThreshold: 12
180+
resources:
181+
requests:
182+
memory: "64Mi"
183+
cpu: "50m"
184+
limits:
185+
memory: "128Mi"
186+
cpu: "200m"
187+
volumeMounts:
188+
- name: glauth-config
189+
mountPath: /etc/glauth
190+
readOnly: true
191+
volumes:
192+
- name: glauth-config
193+
configMap:
194+
name: glauth-config
195+
---
196+
apiVersion: v1
197+
kind: Service
198+
metadata:
199+
name: glauth
200+
labels:
201+
app: glauth
202+
spec:
203+
ports:
204+
- port: 3893
205+
targetPort: 3893
206+
name: ldap
207+
selector:
208+
app: glauth
209+
EOFYAML
210+
211+
echo "Waiting for GLAuth to be ready..."
212+
if ! kubectl wait --for=condition=available --timeout=120s deployment/glauth; then
213+
echo "GLAuth deployment failed! Debug info:"
214+
kubectl describe deployment glauth
215+
kubectl describe pod -l app=glauth
216+
kubectl logs -l app=glauth --tail=50 || echo "No logs available"
217+
exit 1
218+
fi
219+
echo "✓ GLAuth is ready"
220+
params:
221+
- name: kubeconfig-secret
222+
value: $(tasks.provision-environment.results.secretRef)
223+
224+
- name: deploy-dex
225+
runAfter:
226+
- provision-environment
227+
taskSpec:
228+
params:
229+
- name: kubeconfig-secret
230+
type: string
231+
steps:
232+
- name: create-dex
233+
image: quay.io/konflux-ci/appstudio-utils:latest
234+
script: |
235+
#!/usr/bin/env bash
236+
set -euo pipefail
237+
238+
KUBECONFIG=/tmp/kubeconfig
239+
kubectl get secret $(params.kubeconfig-secret) -o jsonpath='{.data.kubeconfig}' | base64 -d > $KUBECONFIG
240+
export KUBECONFIG
241+
242+
echo "=========================================="
243+
echo "Deploying Dex OIDC Provider"
244+
echo "=========================================="
245+
246+
kubectl apply -f - <<'EOFYAML'
247+
apiVersion: v1
248+
kind: ConfigMap
249+
metadata:
250+
name: dex-config
251+
data:
252+
config.yaml: |
253+
issuer: http://dex:5556
254+
255+
storage:
256+
type: memory
257+
258+
web:
259+
http: 0.0.0.0:5556
260+
261+
logger:
262+
level: debug
263+
264+
enablePasswordDB: true
265+
266+
staticPasswords:
267+
- email: builder@example.com
268+
hash: "$2y$10$6cZyh42YBb2Q5.fE9nj3mu3UHs21NUmVP2fpU63EM3/ecJuHVscEC"
269+
username: builder
270+
userID: "builder-id"
271+
- email: readonly@example.com
272+
hash: "$2y$10$6cZyh42YBb2Q5.fE9nj3mu3UHs21NUmVP2fpU63EM3/ecJuHVscEC"
273+
username: readonly
274+
userID: "readonly-id"
275+
276+
staticClients:
277+
- id: cts-integration
278+
secret: cts-integration-secret
279+
name: CTS Integration
280+
redirectURIs:
281+
- http://cts:8080/redirect_uri
282+
grantTypes:
283+
- password
284+
- authorization_code
285+
286+
oauth2:
287+
skipApprovalScreen: true
288+
passwordConnector: local
289+
EOFYAML
290+
291+
kubectl apply -f - <<'EOFYAML'
292+
apiVersion: apps/v1
293+
kind: Deployment
294+
metadata:
295+
name: dex
296+
labels:
297+
app: dex
298+
spec:
299+
replicas: 1
300+
selector:
301+
matchLabels:
302+
app: dex
303+
template:
304+
metadata:
305+
labels:
306+
app: dex
307+
spec:
308+
containers:
309+
- name: dex
310+
image: ghcr.io/dexidp/dex:v2.41.1
311+
args: ["dex", "serve", "/etc/dex/config.yaml"]
312+
ports:
313+
- containerPort: 5556
314+
name: http
315+
resources:
316+
requests:
317+
memory: "64Mi"
318+
cpu: "50m"
319+
limits:
320+
memory: "256Mi"
321+
cpu: "500m"
322+
readinessProbe:
323+
httpGet:
324+
path: /.well-known/openid-configuration
325+
port: 5556
326+
initialDelaySeconds: 5
327+
periodSeconds: 5
328+
timeoutSeconds: 5
329+
failureThreshold: 12
330+
volumeMounts:
331+
- name: dex-config
332+
mountPath: /etc/dex
333+
readOnly: true
334+
volumes:
335+
- name: dex-config
336+
configMap:
337+
name: dex-config
338+
---
339+
apiVersion: v1
340+
kind: Service
341+
metadata:
342+
name: dex
343+
labels:
344+
app: dex
345+
spec:
346+
ports:
347+
- port: 5556
348+
targetPort: 5556
349+
name: http
350+
selector:
351+
app: dex
352+
EOFYAML
353+
354+
echo "Waiting for Dex to be ready..."
355+
if ! kubectl wait --for=condition=available --timeout=180s deployment/dex; then
356+
echo "Dex deployment failed! Debug info:"
357+
kubectl describe deployment dex
358+
kubectl describe pod -l app=dex
359+
kubectl logs -l app=dex --tail=50 || echo "No logs available"
360+
exit 1
361+
fi
362+
echo "✓ Dex is ready"
363+
params:
364+
- name: kubeconfig-secret
365+
value: $(tasks.provision-environment.results.secretRef)
366+
80367
- name: deploy-database
81368
runAfter:
82369
- provision-environment
@@ -215,6 +502,8 @@ spec:
215502
- name: deploy-cts
216503
runAfter:
217504
- deploy-database
505+
- deploy-glauth
506+
- deploy-dex
218507
taskSpec:
219508
params:
220509
- name: kubeconfig-secret
@@ -241,7 +530,7 @@ spec:
241530
echo "Image: $IMAGE"
242531
243532
# Create ConfigMap with production configuration and httpd config for CTS
244-
kubectl apply -f - <<EOF
533+
kubectl apply -f - <<'EOFYAML'
245534
apiVersion: v1
246535
kind: ConfigMap
247536
metadata:
@@ -251,8 +540,16 @@ spec:
251540
from conf.config import BaseConfiguration
252541
253542
class ProdConfiguration(BaseConfiguration):
254-
AUTH_BACKEND = "noauth"
543+
AUTH_BACKEND = "openidc"
255544
SQLALCHEMY_DATABASE_URI = "postgresql://cts:cts-test@cts-db:5432/cts"
545+
AUTH_OPENIDC_USERINFO_URI = "http://dex:5556/userinfo"
546+
AUTH_OPENIDC_REQUIRED_SCOPES = ["openid"]
547+
AUTH_LDAP_SERVER = "ldap://glauth:3893"
548+
AUTH_LDAP_GROUPS = [
549+
("ou=groups,dc=example,dc=com", "(&(objectClass=posixGroup)(memberUid={0}))"),
550+
]
551+
ADMINS = {"groups": [], "users": ["builder"]}
552+
ALLOWED_BUILDERS = {"groups": [], "users": ["builder"]}
256553
httpd.conf: |
257554
ServerRoot "/etc/httpd"
258555
PidFile /tmp/httpd.pid
@@ -268,15 +565,30 @@ spec:
268565
269566
Include conf.modules.d/*.conf
270567
568+
OIDCProviderMetadataURL http://dex:5556/.well-known/openid-configuration
569+
OIDCSSLValidateServer Off
570+
OIDCOAuthVerifyJwksUri http://dex:5556/keys
571+
OIDCOAuthSSLValidateServer Off
572+
OIDCOAuthRemoteUserClaim preferred_username
573+
OIDCOAuthUnAuthAction pass
574+
271575
WSGISocketPrefix /tmp/wsgi
272576
WSGIDaemonProcess cts threads=5 home=/usr/share/cts
273577
WSGIScriptAlias / /usr/share/cts/cts.wsgi
274578
275579
<Directory /usr/share/cts>
276580
WSGIProcessGroup cts
277581
WSGIApplicationGroup %{GLOBAL}
582+
AuthType oauth20
583+
<RequireAny>
584+
<RequireAll>
585+
Require expr %{REQUEST_URI} !~ /userinfo/
586+
Require method GET
587+
</RequireAll>
588+
Require valid-user
589+
</RequireAny>
278590
</Directory>
279-
EOF
591+
EOFYAML
280592
281593
# Deploy CTS
282594
kubectl apply -f - <<EOF
@@ -478,9 +790,9 @@ spec:
478790
set -ex
479791
export HOME=/tmp
480792
481-
echo 'Installing pytest...'
793+
echo 'Installing pytest and requests...'
482794
python3 -m ensurepip
483-
python3 -m pip install --user pytest
795+
python3 -m pip install --user pytest requests
484796
485797
echo ''
486798
echo 'Cloning repository...'
@@ -492,7 +804,7 @@ spec:
492804
493805
echo ''
494806
echo 'Running pytest...'
495-
CTS_URL=http://cts:8080 python3 -m pytest tests/test_integration_api.py -v -s -o addopts=
807+
CTS_URL=http://cts:8080 AUTH_BACKEND=openidc python3 -m pytest tests/test_integration_api.py -v -s -o addopts=
496808
"
497809
TEST_RESULT=$?
498810
set -e

0 commit comments

Comments
 (0)