diff --git a/pbm-functional/pytest/Dockerfile b/pbm-functional/pytest/Dockerfile index 9dbff855..1aa20e95 100644 --- a/pbm-functional/pytest/Dockerfile +++ b/pbm-functional/pytest/Dockerfile @@ -56,6 +56,9 @@ RUN echo -e 'vaulttoken' > /etc/vault/token && \ chown -R mongodb /etc/vault && chmod 400 /etc/vault/token && \ chown -R mongodb /etc/x509 && chmod 400 /etc/x509/* && \ chown -R mongodb /etc/nginx-minio && \ + mkdir -p /etc/pki/ca-trust/source/anchors && \ + cp /etc/pykmip/ca.crt /etc/pki/ca-trust/source/anchors/ && \ + update-ca-trust extract && \ if [ -f "/usr/bin/mongosh" ] ; then \ ln -s /usr/bin/mongosh /usr/bin/mongo ; \ fi && \ diff --git a/pbm-functional/pytest/Dockerfile-easyrsa b/pbm-functional/pytest/Dockerfile-easyrsa index e9e35283..b3bbb4e4 100644 --- a/pbm-functional/pytest/Dockerfile-easyrsa +++ b/pbm-functional/pytest/Dockerfile-easyrsa @@ -33,3 +33,11 @@ RUN ./easyrsa --req-ou=server --subject-alt-name=DNS:nginx-minio --batch build-s cp pki/ca.crt /etc/nginx-minio/ && \ cp pki/issued/nginx-minio.crt /etc/nginx-minio/ && \ cp pki/private/nginx-minio.key /etc/nginx-minio/ + +#For keycloak +RUN ./easyrsa --batch build-server-full keycloak nopass && \ + mkdir -p /etc/keycloak && \ + cp pki/ca.crt /etc/keycloak/ && \ + cat pki/issued/keycloak.crt pki/private/keycloak.key > /etc/pykmip/keycloak.pem && \ + cp pki/issued/keycloak.crt /etc/keycloak/ && \ + cp pki/private/keycloak.key /etc/keycloak/ diff --git a/pbm-functional/pytest/Dockerfile-keycloak b/pbm-functional/pytest/Dockerfile-keycloak new file mode 100644 index 00000000..6cb3c561 --- /dev/null +++ b/pbm-functional/pytest/Dockerfile-keycloak @@ -0,0 +1,187 @@ +FROM easyrsa/local AS easyrsa + +FROM quay.io/keycloak/keycloak:latest + +ENV KEYCLOAK_ADMIN=admin +ENV KEYCLOAK_ADMIN_PASSWORD=admin + +COPY --from=easyrsa --chown=keycloak /etc/keycloak/keycloak.crt /opt/keycloak/conf/server.crt.pem +COPY --from=easyrsa --chown=keycloak /etc/keycloak/keycloak.key /opt/keycloak/conf/server.key.pem + +RUN mkdir -p /opt/keycloak/data/import +RUN cat > /opt/keycloak/data/import/test-realm.json <<'JSON' +{ + "realm": "test", + "enabled": true, + "sslRequired": "external", + + "roles": { + "realm": [ + { "name": "mongodb.readWrite", "description": "Sample realm role for MongoDB access" } + ] + }, + + "groups": [ + { + "name": "testers", + "realmRoles": [ "mongodb.readWrite" ] + } + ], + + "clients": [ + { + "clientId": "test-app", + "protocol": "openid-connect", + "publicClient": true, + "redirectUris": [ + "http://localhost:27097/redirect", + "https://localhost:*/*", + "https://keycloak:*/*", + "*" + ], + "webOrigins": ["*"], + "standardFlowEnabled": true, + "directAccessGrantsEnabled": true, + "attributes": { "pkce.code.challenge.method": "S256" }, + + "protocolMappers": [ + { + "name": "groups", + "protocol": "openid-connect", + "protocolMapper": "oidc-group-membership-mapper", + "consentRequired": false, + "config": { + "full.path": "false", + "access.token.claim": "true", + "id.token.claim": "true", + "userinfo.token.claim": "true", + "claim.name": "groups", + "jsonType.label": "String" + } + }, + { + "name": "email", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "user.attribute": "email", + "claim.name": "email", + "jsonType.label": "String", + "access.token.claim": "true", + "id.token.claim": "true", + "userinfo.token.claim": "true" + } + }, + { + "name": "preferred_username", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "user.attribute": "username", + "claim.name": "preferred_username", + "jsonType.label": "String", + "access.token.claim": "true", + "id.token.claim": "true", + "userinfo.token.claim": "true" + } + }, + { + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "claim.name": "realm_access.roles", + "jsonType.label": "String", + "multivalued": "true", + "access.token.claim": "true", + "id.token.claim": "false", + "userinfo.token.claim": "false" + } + } + ] + }, + + { + "clientId": "test-confidential", + "protocol": "openid-connect", + "publicClient": false, + "serviceAccountsEnabled": true, + "redirectUris": ["*"], + "webOrigins": ["*"], + "standardFlowEnabled": true, + "directAccessGrantsEnabled": true, + "secret": "test-secret" + }, + + { + "clientId": "pbmclient", + "protocol": "openid-connect", + "publicClient": false, + "serviceAccountsEnabled": true, + "redirectUris": ["*"], + "webOrigins": ["*"], + "standardFlowEnabled": false, + "directAccessGrantsEnabled": false, + "secret": "pbm-secret", + + "protocolMappers": [ + { + "name": "groups", + "protocol": "openid-connect", + "protocolMapper": "oidc-group-membership-mapper", + "consentRequired": false, + "config": { + "full.path": "false", + "access.token.claim": "true", + "id.token.claim": "false", + "userinfo.token.claim": "false", + "claim.name": "groups", + "jsonType.label": "String" + } + }, + { + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "claim.name": "realm_access.roles", + "jsonType.label": "String", + "multivalued": "true", + "access.token.claim": "true", + "id.token.claim": "false", + "userinfo.token.claim": "false" + } + } + ] + } + ], + + "users": [ + { + "username": "test", + "enabled": true, + "email": "test@example.test", + "emailVerified": true, + "groups": ["testers"], + "credentials": [ + { "type": "password", "value": "testpass", "temporary": false } + ] + }, + { + "username": "pbmuser", + "enabled": true, + "email": "pbmuser@example.test", + "emailVerified": true, + "credentials": [ + { "type": "password", "value": "pbmpass", "temporary": false } + ] + } + ] +} +JSON + +CMD ["start-dev","--https-certificate-file=/opt/keycloak/conf/server.crt.pem","--https-certificate-key-file=/opt/keycloak/conf/server.key.pem","--hostname=keycloak","--hostname-strict=false","--import-realm"] diff --git a/pbm-functional/pytest/cluster.py b/pbm-functional/pytest/cluster.py index 050000d3..0e86f72c 100644 --- a/pbm-functional/pytest/cluster.py +++ b/pbm-functional/pytest/cluster.py @@ -739,6 +739,12 @@ def setup_authorization(host,uri): '{"db":"admin","role":"clusterMonitor" },' + '{"db":"admin","role":"restore" },' + '{"db":"admin","role":"pbmAnyAction" }]});\'') + oidc_pbm_user = ('\'db.getSiblingDB("$external").runCommand({createUser:"keycloak/pbmclient","roles":[' + + '{"db":"admin","role":"readWrite","collection":""},' + + '{"db":"admin","role":"backup" },' + + '{"db":"admin","role":"clusterMonitor" },' + + '{"db":"admin","role":"restore" },' + + '{"db":"admin","role":"pbmAnyAction" }]});\'') logs = primary.check_output( "mongo -u root -p root --quiet --eval " + init_pbm_user) logs = primary.check_output( @@ -756,6 +762,10 @@ def setup_authorization(host,uri): logs = primary.check_output( "mongo -u root -p root --quiet --eval " + ldap_mongo_grp) #Cluster.log(logs) + if "authMechanism=MONGODB-OIDC" in uri: + logs = primary.check_output( + "mongo -u root -p root --quiet --eval " + oidc_pbm_user) + #Cluster.log(logs) def __setup_authorizations(self, replicasets): with concurrent.futures.ProcessPoolExecutor() as executor: diff --git a/pbm-functional/pytest/docker-compose.yaml b/pbm-functional/pytest/docker-compose.yaml index d27e991a..31afb38e 100644 --- a/pbm-functional/pytest/docker-compose.yaml +++ b/pbm-functional/pytest/docker-compose.yaml @@ -117,6 +117,19 @@ services: networks: - test + keycloak: + image: keycloak/local + build: + dockerfile: ./Dockerfile-keycloak + context: . + container_name: keycloak + hostname: keycloak + ports: + - "8443:8443" + - "8080:8080" + networks: + - test + build_member: image: replica_member/local build: diff --git a/pbm-functional/pytest/example_oidc_setup.py b/pbm-functional/pytest/example_oidc_setup.py new file mode 100644 index 00000000..d16e70e6 --- /dev/null +++ b/pbm-functional/pytest/example_oidc_setup.py @@ -0,0 +1,31 @@ +import signal +from cluster import Cluster + +#docker compose run -ti --rm test python3 -i example_oidc_setup.py + +config = { "_id": "rs1", "members": [{"host": "rs101"}]} +pbm_mongodb_uri = 'mongodb://127.0.0.1:27017/?authSource=%24external&authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:k8s' +mongod_extra_args = ('--setParameter authenticationMechanisms=SCRAM-SHA-1,MONGODB-OIDC --setParameter \'' + + 'oidcIdentityProviders=[ { ' + + '"issuer": "https://keycloak:8443/realms/test", ' + + '"clientId": "test-client", ' + + '"audience": "account", ' + + '"authNamePrefix": "keycloak", ' + + '"useAuthorizationClaim": false, ' + + '"supportsHumanFlows": false, ' + + '"principalName": "client_id" ' + + '} ]\'') +cluster = Cluster(config,pbm_mongodb_uri=pbm_mongodb_uri,mongod_extra_args=mongod_extra_args) + +def handler(signum,frame): + cluster.destroy() + exit(0) + +cluster.destroy() +cluster.create() +#cluster.setup_pbm() + +signal.signal(signal.SIGINT,handler) +print("\nCluster is prepared and ready to use") +print("\nPress CTRL-C to destroy and exit") +