diff --git a/tests/templates/kuttl/commons/ingestioncheck-tls.py b/tests/templates/kuttl/commons/ingestioncheck-tls.py index 9c8d5040..5d91c629 100755 --- a/tests/templates/kuttl/commons/ingestioncheck-tls.py +++ b/tests/templates/kuttl/commons/ingestioncheck-tls.py @@ -1,7 +1,9 @@ import urllib import requests +from requests.auth import HTTPBasicAuth import http +import os import sys import json import time @@ -11,6 +13,10 @@ class DruidClient: def __init__(self, cert, verify): self.session = requests.Session() self.session.headers.update({'Accept': 'application/json', 'Content-Type': 'application/json'}) + if os.environ['DRUID_OIDC'] == 'true': + if os.environ['DRUID_USER'] == '' or os.environ['DRUID_PASSWORD'] == '': + sys.exit("Need to provide basic auth user and password when OIDC is enabled.") + self.session.auth = HTTPBasicAuth(os.environ['DRUID_USER'], os.environ['DRUID_PASSWORD']) self.session.cert = cert self.session.verify = verify diff --git a/tests/templates/kuttl/oidc/09-keycloak-realm.yaml b/tests/templates/kuttl/oidc/09-keycloak-realm.yaml deleted file mode 100644 index 9d649fc9..00000000 --- a/tests/templates/kuttl/oidc/09-keycloak-realm.yaml +++ /dev/null @@ -1,69 +0,0 @@ ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: keycloak-realm -data: - keycloak-realm.json: |- - { - "realm": "stackable", - "enabled": true, - "users": [ - { - "username": "admin", - "enabled": true, - "credentials": [ - { - "type": "password", - "value": "admin" - } - ], - "realmRoles": [ - "admin" - ] - }, - { - "username": "test", - "enabled": true, - "credentials": [ - { - "type": "password", - "value": "test" - } - ], - "realmRoles": [ - "user" - ] - } - ], - "roles": { - "realm": [ - { - "name": "admin", - "description": "Admin privileges" - }, - { - "name": "user", - "description": "User privileges" - } - ] - }, - "clients": [ - { - "clientId": "stackable", - "enabled": true, - "clientAuthenticatorType": "client-secret", - "secret": "STACKABLE_CLIENT_SECRET", - "redirectUris": [ - "*" - ], - "webOrigins": [ - "*" - ], - "standardFlowEnabled": true, - "protocol": "openid-connect", - "directAccessGrantsEnabled": true, - "serviceAccountsEnabled": true - } - ] - } diff --git a/tests/templates/kuttl/oidc/10-assert.yaml.j2 b/tests/templates/kuttl/oidc/10-assert.yaml.j2 new file mode 100644 index 00000000..50b1d4c3 --- /dev/null +++ b/tests/templates/kuttl/oidc/10-assert.yaml.j2 @@ -0,0 +1,10 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +{% if lookup('env', 'VECTOR_AGGREGATOR') %} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: vector-aggregator-discovery +{% endif %} diff --git a/tests/templates/kuttl/oidc/10-install-vector-aggregator-discovery-configmap.yaml.j2 b/tests/templates/kuttl/oidc/10-install-vector-aggregator-discovery-configmap.yaml.j2 new file mode 100644 index 00000000..2d6a0df5 --- /dev/null +++ b/tests/templates/kuttl/oidc/10-install-vector-aggregator-discovery-configmap.yaml.j2 @@ -0,0 +1,9 @@ +{% if lookup('env', 'VECTOR_AGGREGATOR') %} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: vector-aggregator-discovery +data: + ADDRESS: {{ lookup('env', 'VECTOR_AGGREGATOR') }} +{% endif %} diff --git a/tests/templates/kuttl/oidc/10-keycloak.yaml.j2 b/tests/templates/kuttl/oidc/10-keycloak.yaml.j2 deleted file mode 100644 index 1424aa6e..00000000 --- a/tests/templates/kuttl/oidc/10-keycloak.yaml.j2 +++ /dev/null @@ -1,89 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: keycloak - labels: - app: keycloak -spec: - replicas: 1 - selector: - matchLabels: - app: keycloak - template: - metadata: - labels: - app: keycloak - spec: - serviceAccountName: keycloak - volumes: - - name: keycloak-import-dir - configMap: - name: keycloak-realm - containers: - - name: keycloak - image: quay.io/keycloak/keycloak:22.0.3 - # Keycloak is running in development mode: https://www.keycloak.org/server/configuration#_starting_keycloak - # production mode disables HTTP and requires a TLS configuration, which is currently very difficult to configure - # given that we're running on a NodePort - args: ["start-dev", "--import-realm"] - env: - - name: KEYCLOAK_ADMIN - value: admin - - name: KEYCLOAK_ADMIN_PASSWORD - value: admin - ports: - - name: http - containerPort: 8080 - readinessProbe: - httpGet: - path: /realms/master - port: 8080 - volumeMounts: - - name: keycloak-import-dir - mountPath: /opt/keycloak/data/import ---- -apiVersion: v1 -kind: Service -metadata: - name: keycloak - labels: - app: keycloak -spec: - type: NodePort - selector: - app: keycloak - ports: - - name: http - port: 8080 - targetPort: 8080 ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: keycloak - -{% if test_scenario['values']['openshift'] == 'true' %} ---- -kind: Role -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: keycloak -rules: -- apiGroups: ["security.openshift.io"] - resources: ["securitycontextconstraints"] - resourceNames: ["privileged"] - verbs: ["use"] ---- -kind: RoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: keycloak -subjects: - - kind: ServiceAccount - name: keycloak -roleRef: - kind: Role - name: keycloak - apiGroup: rbac.authorization.k8s.io -{% endif %} diff --git a/tests/templates/kuttl/oidc/30-assert.yaml b/tests/templates/kuttl/oidc/30-assert.yaml index 480a2794..5f3fae52 100644 --- a/tests/templates/kuttl/oidc/30-assert.yaml +++ b/tests/templates/kuttl/oidc/30-assert.yaml @@ -1,44 +1,14 @@ --- apiVersion: kuttl.dev/v1beta1 kind: TestAssert -timeout: 600 ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: druid-broker-default -status: - readyReplicas: 1 - replicas: 1 ---- -apiVersion: apps/v1 -kind: StatefulSet metadata: - name: druid-coordinator-default -status: - readyReplicas: 1 - replicas: 1 ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: druid-historical-default -status: - readyReplicas: 1 - replicas: 1 ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: druid-middlemanager-default -status: - readyReplicas: 1 - replicas: 1 + name: test-keycloak +timeout: 480 --- apiVersion: apps/v1 -kind: StatefulSet +kind: Deployment metadata: - name: druid-router-default + name: keycloak status: readyReplicas: 1 replicas: 1 diff --git a/tests/templates/kuttl/oidc/30-install-keycloak.yaml b/tests/templates/kuttl/oidc/30-install-keycloak.yaml new file mode 100644 index 00000000..9111e8cb --- /dev/null +++ b/tests/templates/kuttl/oidc/30-install-keycloak.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: | + INSTANCE_NAME=keycloak \ + REALM=test \ + USERNAME=jane.doe \ + FIRST_NAME=Jane \ + LAST_NAME=Doe \ + EMAIL=jane.doe@stackable.tech \ + PASSWORD=T8mn72D9 \ + CLIENT_ID=druid \ + CLIENT_SECRET=R1bxHUD569vHeQdw \ + envsubst < install-keycloak.yaml | kubectl apply -n $NAMESPACE -f - diff --git a/tests/templates/kuttl/oidc/40-assert.yaml b/tests/templates/kuttl/oidc/40-assert.yaml index 4683c3b5..480a2794 100644 --- a/tests/templates/kuttl/oidc/40-assert.yaml +++ b/tests/templates/kuttl/oidc/40-assert.yaml @@ -1,11 +1,44 @@ --- apiVersion: kuttl.dev/v1beta1 kind: TestAssert -timeout: 300 +timeout: 600 --- -apiVersion: batch/v1 -kind: Job +apiVersion: apps/v1 +kind: StatefulSet metadata: - name: login + name: druid-broker-default status: - succeeded: 1 + readyReplicas: 1 + replicas: 1 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: druid-coordinator-default +status: + readyReplicas: 1 + replicas: 1 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: druid-historical-default +status: + readyReplicas: 1 + replicas: 1 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: druid-middlemanager-default +status: + readyReplicas: 1 + replicas: 1 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: druid-router-default +status: + readyReplicas: 1 + replicas: 1 diff --git a/tests/templates/kuttl/oidc/40-install-druid.yaml b/tests/templates/kuttl/oidc/40-install-druid.yaml new file mode 100644 index 00000000..83ef7b71 --- /dev/null +++ b/tests/templates/kuttl/oidc/40-install-druid.yaml @@ -0,0 +1,5 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: envsubst < install-druid.yaml | kubectl apply -n $NAMESPACE -f - diff --git a/tests/templates/kuttl/oidc/40-login.yaml b/tests/templates/kuttl/oidc/40-login.yaml deleted file mode 100644 index 69ba3f07..00000000 --- a/tests/templates/kuttl/oidc/40-login.yaml +++ /dev/null @@ -1,27 +0,0 @@ ---- -apiVersion: kuttl.dev/v1beta1 -kind: TestStep -timeout: 600 -commands: -- script: kubectl create configmap login --namespace $NAMESPACE --from-file=login.py ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: login -spec: - template: - spec: - volumes: - - name: login - configMap: - name: login - containers: - - name: test - image: docker.stackable.tech/stackable/testing-tools:0.2.0-stackable0.0 - command: ["python", "/test/login.py", "https://druid-router:9088/unified-console.html"] - volumeMounts: - - name: login - mountPath: /test - restartPolicy: Never - backoffLimit: 4 diff --git a/tests/templates/kuttl/oidc/50-create-configmap.yaml.j2 b/tests/templates/kuttl/oidc/50-create-configmap.yaml.j2 new file mode 100644 index 00000000..f631e1b2 --- /dev/null +++ b/tests/templates/kuttl/oidc/50-create-configmap.yaml.j2 @@ -0,0 +1,6 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +metadata: + name: create-configmap +commands: + - script: kubectl create cm ingestion-check -n $NAMESPACE --from-file=../../../../templates/kuttl/commons/ingestioncheck-tls.py --from-file=../../../../templates/kuttl/commons/druid-quickstartimport.json diff --git a/tests/templates/kuttl/oidc/10-assert.yaml b/tests/templates/kuttl/oidc/51-assert.yaml similarity index 58% rename from tests/templates/kuttl/oidc/10-assert.yaml rename to tests/templates/kuttl/oidc/51-assert.yaml index 0487a520..58987778 100644 --- a/tests/templates/kuttl/oidc/10-assert.yaml +++ b/tests/templates/kuttl/oidc/51-assert.yaml @@ -1,13 +1,14 @@ --- apiVersion: kuttl.dev/v1beta1 kind: TestAssert +metadata: + name: install-test-container timeout: 300 --- apiVersion: apps/v1 -kind: Deployment +kind: StatefulSet metadata: - labels: - app: keycloak - name: keycloak + name: python status: readyReplicas: 1 + replicas: 1 diff --git a/tests/templates/kuttl/oidc/51-install-test-container.yaml.j2 b/tests/templates/kuttl/oidc/51-install-test-container.yaml.j2 new file mode 100644 index 00000000..82a1066b --- /dev/null +++ b/tests/templates/kuttl/oidc/51-install-test-container.yaml.j2 @@ -0,0 +1,93 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: python +--- +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: python +{% if test_scenario['values']['openshift'] == 'true' %} +rules: +- apiGroups: ["security.openshift.io"] + resources: ["securitycontextconstraints"] + resourceNames: ["privileged"] + verbs: ["use"] +{% endif %} +--- +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: python +subjects: + - kind: ServiceAccount + name: python +roleRef: + kind: Role + name: python + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +metadata: + name: install-test-container +timeout: 300 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: python + labels: + app: python +spec: + replicas: 1 + selector: + matchLabels: + app: python + template: + metadata: + labels: + app: python + spec: + serviceAccountName: python + securityContext: + fsGroup: 1000 + containers: + - name: python + image: docker.stackable.tech/stackable/testing-tools:0.2.0-stackable0.0.0-dev + stdin: true + tty: true + resources: + requests: + memory: "128Mi" + cpu: "512m" + limits: + memory: "128Mi" + cpu: "1" + volumeMounts: + - name: tls + mountPath: /stackable/tls + - name: ingestion-check + mountPath: /tmp + env: + - name: REQUESTS_CA_BUNDLE + value: /stackable/tls/ca.crt + - name: DRUID_OIDC + value: "true" + - name: DRUID_USER + value: druid_system + - name: DRUID_PASSWORD + value: druid-system-password + - name: OIDC_USE_TLS + value: "{{ test_scenario['values']['oidc-use-tls'] }}" + volumes: + - name: tls + csi: + driver: secrets.stackable.tech + volumeAttributes: + secrets.stackable.tech/class: tls + secrets.stackable.tech/scope: pod + - name: ingestion-check + configMap: + name: ingestion-check diff --git a/tests/templates/kuttl/oidc/60-assert.yaml b/tests/templates/kuttl/oidc/60-assert.yaml new file mode 100644 index 00000000..1c40ba09 --- /dev/null +++ b/tests/templates/kuttl/oidc/60-assert.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +metadata: + name: login +timeout: 300 +commands: + - script: kubectl exec -n $NAMESPACE python-0 -- python /stackable/login.py $NAMESPACE diff --git a/tests/templates/kuttl/oidc/60-login.yaml b/tests/templates/kuttl/oidc/60-login.yaml new file mode 100644 index 00000000..0745bc4b --- /dev/null +++ b/tests/templates/kuttl/oidc/60-login.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +metadata: + name: login +commands: + - script: > + envsubst '$NAMESPACE' < login.py | + kubectl exec -n $NAMESPACE -i python-0 -- tee /stackable/login.py > /dev/null diff --git a/tests/templates/kuttl/oidc/70-assert.yaml.j2 b/tests/templates/kuttl/oidc/70-assert.yaml.j2 new file mode 100644 index 00000000..18010193 --- /dev/null +++ b/tests/templates/kuttl/oidc/70-assert.yaml.j2 @@ -0,0 +1,8 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +metadata: + name: ingestion-check +timeout: 300 +commands: + - script: kubectl exec python-0 -n $NAMESPACE -- python /tmp/ingestioncheck-tls.py $NAMESPACE druid internal-and-server-tls true diff --git a/tests/templates/kuttl/oidc/30-druid.yaml.j2 b/tests/templates/kuttl/oidc/install-druid.yaml.j2 similarity index 65% rename from tests/templates/kuttl/oidc/30-druid.yaml.j2 rename to tests/templates/kuttl/oidc/install-druid.yaml.j2 index 40888c6d..46065bda 100644 --- a/tests/templates/kuttl/oidc/30-druid.yaml.j2 +++ b/tests/templates/kuttl/oidc/install-druid.yaml.j2 @@ -74,25 +74,31 @@ spec: # basic authenticator needed for internal authentication among Druid processes # Trying to use the pac4j authenticator in the escalator below leads to 302 errors, # it seems like the Druid processes cannot handle the OIDC authentication flow. - druid.auth.authenticator.MyBasicMetadataAuthenticator.type: basic - druid.auth.authenticator.MyBasicMetadataAuthenticator.initialInternalClientPassword: 'druid-system-password' - druid.auth.authenticator.MyBasicMetadataAuthenticator.skipOnFailure: "true" # for any non system user, skip to the pac4j authenticator + druid.auth.authenticator.DruidInternal.type: basic + druid.auth.authenticator.DruidInternal.initialInternalClientPassword: 'druid-system-password' + druid.auth.authenticator.DruidInternal.skipOnFailure: "true" # for any non system user, skip to the pac4j authenticator # pac4j authenticator druid.auth.authenticator.pac4j.type: pac4j # pac4j common config - druid.auth.pac4j.cookiePassphrase: 'ziemlichirrelevant' + druid.auth.pac4j.cookiePassphrase: 'cookie-passphrase' # OIDC common config - druid.auth.pac4j.oidc.clientID: stackable - druid.auth.pac4j.oidc.clientSecret: STACKABLE_CLIENT_SECRET - druid.auth.pac4j.oidc.discoveryURI: 'http://keycloak:8080/realms/stackable/.well-known/openid-configuration' + druid.auth.pac4j.oidc.clientID: druid + druid.auth.pac4j.oidc.clientSecret: R1bxHUD569vHeQdw +{% if test_scenario['values']['oidc-use-tls'] == 'true' %} + druid.auth.pac4j.oidc.discoveryURI: 'https://keycloak.$NAMESPACE.svc.cluster.local:8443/realms/test/.well-known/openid-configuration' +{% else %} + druid.auth.pac4j.oidc.discoveryURI: 'http://keycloak.$NAMESPACE.svc.cluster.local:8080/realms/test/.well-known/openid-configuration' +{% endif %} druid.auth.pac4j.oidc.oidcClaim: preferred_username - druid.auth.authenticatorChain: '["MyBasicMetadataAuthenticator","pac4j"]' + druid.auth.authenticatorChain: '["DruidInternal","pac4j"]' druid.escalator.type: basic druid.escalator.internalClientUsername: druid_system druid.escalator.internalClientPassword: 'druid-system-password' + jvm.config: + -Djavax.net.ssl.trustStore: /stackable/tls/truststore.p12 coordinators: roleGroups: default: @@ -110,7 +116,14 @@ spec: default: replicas: 1 configOverrides: - runtime.properties: *runtime-properties + runtime.properties: + druid.auth.authenticator.DruidInternal.type: basic + druid.auth.authenticator.DruidInternal.initialInternalClientPassword: 'druid-system-password' # Default password for internal 'druid_system' user + druid.auth.authenticator.DruidInternal.skipOnFailure: "true" # for any non system user, skip to the pac4j authenticator + druid.auth.authenticatorChain: '["DruidInternal"]' + druid.escalator.type: basic + druid.escalator.internalClientUsername: druid_system + druid.escalator.internalClientPassword: 'druid-system-password' routers: roleGroups: default: diff --git a/tests/templates/kuttl/oidc/install-keycloak.yaml.j2 b/tests/templates/kuttl/oidc/install-keycloak.yaml.j2 new file mode 100644 index 00000000..7a52415d --- /dev/null +++ b/tests/templates/kuttl/oidc/install-keycloak.yaml.j2 @@ -0,0 +1,195 @@ +# The environment variables must be replaced. +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: $INSTANCE_NAME-realms +data: + test-realm.json: | + { + "realm": "$REALM", + "enabled": true, + "users": [ + { + "enabled": true, + "username": "$USERNAME", + "firstName" : "$FIRST_NAME", + "lastName" : "$LAST_NAME", + "email" : "$EMAIL", + "credentials": [ + { + "type": "password", + "value": "$PASSWORD" + } + ], + "realmRoles": [ + "user" + ] + } + ], + "roles": { + "realm": [ + { + "name": "user", + "description": "User privileges" + } + ] + }, + "clients": [ + { + "clientId": "$CLIENT_ID", + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "$CLIENT_SECRET", + "redirectUris": [ + "*" + ], + "webOrigins": [ + "*" + ], + "standardFlowEnabled": true, + "protocol": "openid-connect" + } + ] + } +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: $INSTANCE_NAME + labels: + app: $INSTANCE_NAME +spec: + replicas: 1 + selector: + matchLabels: + app: $INSTANCE_NAME + template: + metadata: + labels: + app: $INSTANCE_NAME + spec: + serviceAccountName: keycloak + containers: + - name: keycloak + image: quay.io/keycloak/keycloak:23.0.4 + args: + - start-dev + - --import-realm +{% if test_scenario['values']['oidc-use-tls'] == 'true' %} + - --https-certificate-file=/tls/tls.crt + - --https-certificate-key-file=/tls/tls.key +{% endif %} + env: + - name: KEYCLOAK_ADMIN + value: admin + - name: KEYCLOAK_ADMIN_PASSWORD + value: admin + ports: +{% if test_scenario['values']['oidc-use-tls'] == 'true' %} + - name: https + containerPort: 8443 +{% else %} + - name: http + containerPort: 8080 +{% endif %} + volumeMounts: + - name: realms + mountPath: /opt/keycloak/data/import + - name: tls + mountPath: /tls + readinessProbe: + httpGet: + path: /realms/$REALM +{% if test_scenario['values']['oidc-use-tls'] == 'true' %} + port: 8443 + scheme: HTTPS +{% else %} + port: 8080 + scheme: HTTP +{% endif %} + volumes: + - name: realms + configMap: + name: $INSTANCE_NAME-realms + - ephemeral: + volumeClaimTemplate: + metadata: + annotations: + secrets.stackable.tech/class: tls + secrets.stackable.tech/scope: service=$INSTANCE_NAME + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: "1" + storageClassName: secrets.stackable.tech + volumeMode: Filesystem + name: tls +--- +apiVersion: v1 +kind: Service +metadata: + name: $INSTANCE_NAME +spec: + selector: + app: $INSTANCE_NAME + ports: + - protocol: TCP +{% if test_scenario['values']['oidc-use-tls'] == 'true' %} + port: 8443 +{% else %} + port: 8080 +{% endif %} +--- +apiVersion: authentication.stackable.tech/v1alpha1 +kind: AuthenticationClass +metadata: + name: $INSTANCE_NAME-$NAMESPACE +spec: + provider: + oidc: + hostname: $INSTANCE_NAME.$NAMESPACE.svc.cluster.local + port: 8443 + rootPath: /realms/$REALM + scopes: + - email + - openid + - profile + principalClaim: preferred_username + providerHint: Keycloak + tls: + verification: + server: + caCert: + secretClass: tls +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: keycloak +--- +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: keycloak +{% if test_scenario['values']['openshift'] == 'true' %} +rules: +- apiGroups: ["security.openshift.io"] + resources: ["securitycontextconstraints"] + resourceNames: ["privileged"] + verbs: ["use"] +{% endif %} +--- +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: keycloak +subjects: + - kind: ServiceAccount + name: keycloak +roleRef: + kind: Role + name: keycloak + apiGroup: rbac.authorization.k8s.io diff --git a/tests/templates/kuttl/oidc/login.py b/tests/templates/kuttl/oidc/login.py index c256847b..fd9a4c96 100644 --- a/tests/templates/kuttl/oidc/login.py +++ b/tests/templates/kuttl/oidc/login.py @@ -1,83 +1,36 @@ -"""Perform the OpenID Connect authentication flow to access a given page. +# $NAMESPACE will be replaced with the namespace of the test case. -This script opens a given URL and expects to be redirected to a -Keycloak login page. It extracts the login action from the HTML content -of the Keycloak page and posts the credentials of a test user to it. -Finally it tests that Keycloak redirects back to the original page. -""" import logging +import os import requests -import urllib3 -from html.parser import HTMLParser import sys - - -class KCLoginParser(HTMLParser): - """ Extract the Keycloak url to perform the user login - and be redirected to Druid. - """ - - kc_action: str = "" - - def __init__(self): - HTMLParser.__init__(self) - - def handle_starttag(self, tag, attrs): - if "form" == tag: - for name, value in attrs: - if "action" == name: - logging.debug(f"found redirect action {value}") - self.kc_action = value - - -def test_login_flow(login_url): - session = requests.Session() - - result = session.get( - login_url, - verify=False, - allow_redirects=True, - ) - - result.raise_for_status() - - kcLoginParser = KCLoginParser() - kcLoginParser.feed(result.text) - - if not kcLoginParser.kc_action: - raise ValueError("Failed to extract Keycloak action URL") - - result = session.post(kcLoginParser.kc_action, - data={ - "username": "test", - "password": "test", - }, - verify=False, - allow_redirects=True, - ) - - result.raise_for_status() - - location = result.url - code = result.status_code - if not (code == 200 and location == login_url): - raise ValueError( - f"Expected to land on the Druid console but ended at [{location}]") - - -def main(): - logging.basicConfig(level=logging.DEBUG) - # disable a warning (InsecureRequestWarning) because it's just noise here - urllib3.disable_warnings() - - login_url = sys.argv[1] - - assert len(login_url) > 0 - - test_login_flow(login_url) - - logging.info("Success!") - - -if __name__ == "__main__": - main() +from bs4 import BeautifulSoup + +logging.basicConfig( + level='DEBUG', + format="%(asctime)s %(levelname)s: %(message)s", + stream=sys.stdout) + +namespace = sys.argv[1] +tls = os.environ['OIDC_USE_TLS'] + +session = requests.Session() + +# Open Druid web UI which will redirect to OIDC login +login_page = session.get("https://druid-router-default:9088/unified-console.html", verify=False, headers={'Content-type': 'application/json'}) +keycloak_base_url = f"https://keycloak.{namespace}.svc.cluster.local:8443" if tls == 'true' else f"http://keycloak.{namespace}.svc.cluster.local:8080" +assert login_page.ok, "Redirection from Druid to Keycloak failed" +assert login_page.url.startswith(f"{keycloak_base_url}/realms/test/protocol/openid-connect/auth?scope=openid+profile+email&response_type=code&redirect_uri=https%3A%2F%2Fdruid-router-default%3A9088%2Fdruid-ext%2Fdruid-pac4j%2Fcallback&state="), \ + "Redirection to Keycloak expected" + +# Login to keycloak with test user +login_page_html = BeautifulSoup(login_page.text, 'html.parser') +authenticate_url = login_page_html.form['action'] +welcome_page = session.post(authenticate_url, data={ + 'username': "jane.doe", + 'password': "T8mn72D9" +}) + +assert welcome_page.ok, "Login failed" +assert welcome_page.url == "https://druid-router-default:9088/unified-console.html", \ + "Redirection to the Druid web UI expected" diff --git a/tests/test-definition.yaml b/tests/test-definition.yaml index 8c1ee28f..73d037dc 100644 --- a/tests/test-definition.yaml +++ b/tests/test-definition.yaml @@ -54,6 +54,10 @@ dimensions: - name: openshift values: - "false" + - name: oidc-use-tls + values: + # - "true" # Disabled as pac4j can currently not be configured to trust Keycloak's CA cert (will be fixed by official OIDC support for Druid) + - "false" tests: - name: smoke dimensions: @@ -136,6 +140,7 @@ tests: - zookeeper-latest - s3-use-tls - openshift + - oidc-use-tls suites: - name: nightly patch: