diff --git a/.gitleaks.toml b/.gitleaks.toml index be72ba7d..510e41db 100644 --- a/.gitleaks.toml +++ b/.gitleaks.toml @@ -180,5 +180,6 @@ tags = ["key", "twilio"] files = [ '''(.*?)(jpg|gif|doc|pdf|bin)$''', '''(.*?)conjur.key$''', - '''.gitleaks.toml''' + '''.gitleaks.toml''', + '''ldap-server.key.pem''' ] diff --git a/CHANGELOG.md b/CHANGELOG.md index 89907116..1b3d6336 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,3 +28,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. [cybeark/conjur-openapi-spec#68](https://github.com/cyberark/conjur-openapi-spec/issues/68) - The roles `graph` query parameter is now included in the spec file. Allows for viewing a role as a graph/tree. [cyberark/conjur-openapi-spec#69](https://github.com/cyberark/conjur-openapi-spec/issues/69) +- Generic authenticator endpoint that covers most Conjur platform authenticators. + [cyberark/conjur-openapi-spec#74](https://github.com/cyberark/conjur-openapi-spec/issues/74) + [cyberark/conjur-openapi-spec#70](https://github.com/cyberark/conjur-openapi-spec/issues/70) + [cyberark/conjur-openapi-spec#75](https://github.com/cyberark/conjur-openapi-spec/issues/75) +- Endpoint to configure enabled Conjur authenticators via the API. + [cyberark/conjur-openapi-spec#66](https://github.com/cyberark/conjur-openapi-spec/issues/66) diff --git a/Jenkinsfile b/Jenkinsfile index 80f2ca16..fcdeaa96 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -20,7 +20,7 @@ pipeline { post { always { junit 'nose2-junit.xml' - cobertura autoUpdateHealth: false, autoUpdateStability: true, coberturaReportFile: 'coverage.xml', conditionalCoverageTargets: '75, 0, 75', failUnhealthy: true, failUnstable: true, lineCoverageTargets: '75, 0, 75', maxNumberOfBuilds: 0, methodCoverageTargets: '75, 0, 75', onlyStable: false, sourceEncoding: 'ASCII', zoomCoverageChart: false + cobertura autoUpdateHealth: false, autoUpdateStability: false, coberturaReportFile: 'coverage.xml', conditionalCoverageTargets: '75, 0, 75', failUnhealthy: true, failUnstable: false, lineCoverageTargets: '75, 0, 75', maxNumberOfBuilds: 0, methodCoverageTargets: '75, 0, 75', onlyStable: false, sourceEncoding: 'ASCII', zoomCoverageChart: false sh """ if [[ -x cc-test-reporter ]]; then echo "cc-test-reporter binary found, reporting coverage data to code climate" diff --git a/bin/cli b/bin/cli index 3e1b0b7c..bd433a36 100755 --- a/bin/cli +++ b/bin/cli @@ -1,4 +1,7 @@ #!/bin/bash +./bin/get_conjur_admin_key + docker-compose up -d cli +docker-compose exec cli bash -c "conjur init -u http://conjur -a dev" docker-compose exec cli bash diff --git a/bin/get_conjur_admin_key b/bin/get_conjur_admin_key new file mode 100755 index 00000000..069b97a9 --- /dev/null +++ b/bin/get_conjur_admin_key @@ -0,0 +1,12 @@ +#!/bin/bash + +admin_api_key=$(docker-compose exec -T conjur conjurctl role retrieve-key dev:user:admin | tr -d '\r') +export CONJUR_AUTHN_API_KEY=$admin_api_key + +echo "Conjur admin api key $admin_api_key" + +# Docker-compose will pick this file up when starting containers +# so we will have these variables in the container +cat < .env +CONJUR_AUTHN_API_KEY=$admin_api_key +ENV diff --git a/bin/integration_tests b/bin/integration_tests index 8cddca95..3aff046d 100755 --- a/bin/integration_tests +++ b/bin/integration_tests @@ -13,15 +13,7 @@ fi bin/generate_client bin/start_conjur -echo "Configuring Conjur..." -admin_api_key=$(docker-compose exec -T conjur conjurctl role retrieve-key dev:user:admin | tr -d '\r') -export CONJUR_AUTHN_API_KEY=$admin_api_key - -# Docker-compose will pick this file up when starting containers -# so we will have these variables in the container -cat < .env -CONJUR_AUTHN_API_KEY=$admin_api_key -ENV +bin/get_conjur_admin_key echo "Building and starting test env..." docker-compose build test-python @@ -37,4 +29,4 @@ fi docker-compose run \ --no-deps \ test-python \ - nose2 --plugin nose2.plugins.junitxml --with-coverage --coverage-report xml -X -v -s test/python/ + nose2 --plugin nose2.plugins.junitxml --with-coverage --coverage-report xml -X -v -s test/python diff --git a/docker-compose.yml b/docker-compose.yml index 905f85ef..e08ae860 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,12 +12,19 @@ services: CONJUR_DATA_KEY: 'OyXV68Mip14xj33huGaQKewmmS+gKtDlp6ECZ2iATpU=' DATABASE_URL: postgres://postgres@pg/postgres RAILS_ENV: development + CONJUR_AUTHENTICATORS: authn-ldap/test,authn + LDAP_URI: ldap://ldap-server:389 + LDAP_BASE: dc=conjur,dc=net + LDAP_BINDDN: cn=admin,dc=conjur,dc=net + LDAP_BINDPW: ldapsecret + LDAP_FILTER: (uid=%s) ports: - "80:80" volumes: - ./test/config:/policy:ro depends_on: - pg + - ldap-server conjur-https: image: nginx:alpine @@ -50,6 +57,7 @@ services: - conjur-https volumes: - .:/opt/conjur-openapi-spec + - ./test/config/ldap/certs:/ldap-certs:ro test-api: build: @@ -85,7 +93,29 @@ services: CONJUR_HTTPS_APPLIANCE_URL: https://conjur-https CONJUR_ACCOUNT: dev CONJUR_AUTHN_LOGIN: admin - CONJUR_AUTHN_API_KEY: Null CONJUR_CA_BUNDLE: /opt/conjur-openapi-spec/config/https/ca.crt + CONJUR_AUTHN_API_KEY: Null volumes: - ./:/src + depends_on: + - conjur + - conjur-https + + ldap-server: + image: osixia/openldap + command: --copy-service --loglevel debug + hostname: ldap-server + environment: + LDAP_ORGANIZATION: CyberArk + LDAP_DOMAIN: conjur.net + LDAP_ADMIN_PASSWORD: ldapsecret + LDAP_TLS_CA_CRT_FILENAME: "ca-chain.cert.pem" + LDAP_TLS_CRT_FILENAME: "ldap-server.cert.pem" + LDAP_TLS_KEY_FILENAME: "ldap-server.key.pem" + LDAP_TLS_DH_PARAM_FILENAME: 'dhparam.pem' + LDAP_TLS_VERIFY_CLIENT: try + ports: + - "389:389" + volumes: + - ./test/config/ldap:/container/service/slapd/assets/config/bootstrap/ldif/custom + - ./test/config/ldap/certs:/container/service/slapd/assets/certs:ro diff --git a/spec/authentication.yaml b/spec/authentication.yaml index 69de084b..45f9ea55 100644 --- a/spec/authentication.yaml +++ b/spec/authentication.yaml @@ -5,6 +5,27 @@ components: minLength: 1 example: "admin" + ExternalAuthenticators: + type: string + enum: + - authn-iam + - authn-oidc + - authn-ldap + - authn-k8s + - authn-gcp + - authn-azure + + Authenticators: + type: string + enum: + - authn + - authn-iam + - authn-oidc + - authn-ldap + - authn-k8s + - authn-gcp + - authn-azure + paths: Login: get: @@ -20,6 +41,14 @@ components: Note that machine roles (Hosts) do not have passwords and do not need to login." operationId: "login" parameters: + - name: "authenticator" + in: "path" + description: "The Authenticator" + required: true + schema: + $ref: "#/components/schemas/Authenticators" + example: "authn" + - name: "account" in: "path" description: "Organization account name" @@ -34,8 +63,6 @@ components: $ref: 'openapi.yml#/components/responses/BadRequest' "401": $ref: 'openapi.yml#/components/responses/UnauthorizedError' - "422": - $ref: 'openapi.yml#/components/responses/UnprocessableEntity' "500": $ref: 'openapi.yml#/components/responses/InternalServerError' @@ -58,6 +85,19 @@ components: For API usage, the access token is ordinarily passed as an HTTP Authorization `Token` header." operationId: "authenticate" parameters: + - name: "authenticator" + in: "path" + description: "The authenticator" + required: true + schema: + type: string + enum: + - authn + - authn-iam + - authn-ldap + - authn-k8s + - authn-azure + example: "authn" - name: "account" in: "path" description: "Organization account name" @@ -96,6 +136,80 @@ components: security: - conjurAuth: [] + AuthenticateService: + post: + tags: + - "authn" + summary: "Gets a short-lived access token, which can be used to authenticate requests to (most of) the rest of the Conjur API." + description: "A client can obtain an access token by presenting a valid login name and API key. + + The login must be URL encoded. For example, `alice@devops` must be encoded as `alice%40devops`. + + For host authentication, the login is the host ID with the prefix `host/`. For example, + the host webserver would login as `host/webserver`, and would be encoded as `host%2Fwebserver`. + + For API usage, the access token is ordinarily passed as an HTTP Authorization `Token` header." + operationId: "authenticateService" + parameters: + - name: "authenticator" + in: "path" + description: "The authenticator" + required: true + schema: + type: string + enum: + - authn-iam + - authn-ldap + - authn-k8s + - authn-azure + example: "authn-iam" + - name: "service_id" + in: "path" + description: "The authenticator service" + required: true + schema: + type: string + example: "okta" + - name: "account" + in: "path" + description: "Organization account name" + required: true + schema: + $ref: 'openapi.yml#/components/schemas/AccountName' + - name: "login" + in: "path" + description: "Login name of the client. For users, it’s the user id. For hosts, the login name is `host/`" + required: true + schema: + $ref: '#/components/schemas/LoginName' + - name: "Accept-Encoding" + in: "header" + description: "Setting the Accept-Encoding header to base64 will return a pre-encoded access token" + schema: + type: "string" + requestBody: + description: "API Key" + required: true + content: + text/plain: + schema: + $ref: 'openapi.yml#/components/schemas/ApiKey' + + responses: + "200": + $ref: 'openapi.yml#/components/responses/AccessTokenGeneric' + "400": + $ref: 'openapi.yml#/components/responses/BadRequest' + "401": + $ref: 'openapi.yml#/components/responses/UnauthorizedError' + "404": + $ref: 'openapi.yml#/components/responses/ResourceNotFound' + "500": + $ref: 'openapi.yml#/components/responses/InternalServerError' + + security: + - conjurAuth: [] + ChangePassword: put: tags: @@ -134,7 +248,7 @@ components: "401": $ref: 'openapi.yml#/components/responses/UnauthorizedError' "404": - description: "The user was not found" + $ref: 'openapi.yml#/components/responses/ResourceNotFound' "422": $ref: 'openapi.yml#/components/responses/UnprocessableEntity' "500": @@ -150,13 +264,18 @@ components: summary: "Rotates a user’s API key." description: "Any role can rotate its own API key. The name and password or current API key of the role must be provided via HTTP Basic Authorization. - Your HTTP/REST client probably provides HTTP basic authentication support. For example, curl and all of the Conjur client libraries provide this. - Note that the body of the request must be the empty string." operationId: "rotateApiKey" parameters: + - name: "authenticator" + in: "path" + description: "The authenticator" + required: true + schema: + $ref: '#/components/schemas/Authenticators' + example: "authn" - name: "account" in: "path" description: "Organization account name" @@ -167,8 +286,9 @@ components: in: "query" description: "(**Optional**) role specifier in `{kind}:{identifier}` format - ##### Permissions required: - `update` privilege on the role whose API key is being rotated." + ##### Permissions required + + `update` privilege on the role whose API key is being rotated." schema: $ref: 'openapi.yml#/components/schemas/Role' @@ -179,11 +299,122 @@ components: $ref: 'openapi.yml#/components/responses/BadRequest' "401": $ref: 'openapi.yml#/components/responses/UnauthorizedError' - "422": - $ref: 'openapi.yml#/components/responses/UnprocessableEntity' "500": $ref: 'openapi.yml#/components/responses/InternalServerError' security: - basicAuth: [] conjurAuth: [] + + UpdateAuthenticatorConfig: + patch: + tags: + - "authn" + summary: "Updates the authenticators configuration" + description: "Allows you to either enable or disable a given authenticator + + > This endpoint is part of an early implementation of support for enabling Conjur + > authenticators via the API, and is currently available at the Community (or early alpha) level. + > This endpoint is still subject to breaking changes in the future. + " + operationId: "updateAuthenticatorConfig" + parameters: + - name: "authenticator" + in: "path" + description: "The authenticator to update" + required: true + schema: + $ref: '#/components/schemas/ExternalAuthenticators' + example: "authn-oidc" + - name: "service_id" + in: "path" + description: "The service id of the authenticator" + required: true + schema: + type: string + example: "oidc" + - name: "account" + in: "path" + description: "Organization account name" + required: true + schema: + type: string + example: "dev" + requestBody: + description: "either `enabled=true` or `enabled=false` to enable or disable an authenticator" + required: true + content: + application/x-www-form-urlencoded: + schema: + type: object + properties: + enabled: + type: boolean + + responses: + "204": + description: "The config was updated properly" + "400": + $ref: 'openapi.yml#/components/responses/BadRequest' + "401": + $ref: 'openapi.yml#/components/responses/UnauthorizedError' + "404": + $ref: 'openapi.yml#/components/responses/ResourceNotFound' + "500": + $ref: 'openapi.yml#/components/responses/InternalServerError' + + security: + - conjurAuth: [] + + ServiceLogin: + get: + tags: + - "authn" + summary: "Login with the given authenticator" + description: "Passwords are stored in the Conjur database using `bcrypt` with a work factor of 12. + Therefore, login is a fairly expensive operation. However, once the API key is obtained, it may be + used to inexpensively obtain access tokens by calling the Authenticate method. An access token is + required to use most other parts of the Conjur API. + + Your HTTP/REST client probably provides HTTP basic authentication support. For example, curl and + all of the Conjur client libraries provide this. + + Note that machine roles (Hosts) do not have passwords and do not need to login." + operationId: "serviceLogin" + parameters: + - name: "authenticator" + in: "path" + description: "The authenticator to login with" + required: true + schema: + $ref: '#/components/schemas/ExternalAuthenticators' + example: "authn-oidc" + - name: "service_id" + in: "path" + description: "The service id of the authenticator" + required: true + schema: + type: string + example: "authn-oidc" + - name: "account" + in: "path" + description: "Organization account name" + required: true + schema: + type: string + example: "dev" + + responses: + "200": + $ref: 'openapi.yml#/components/responses/ApiKey' + "400": + $ref: 'openapi.yml#/components/responses/BadRequest' + "401": + $ref: 'openapi.yml#/components/responses/UnauthorizedError' + "404": + $ref: 'openapi.yml#/components/responses/ResourceNotFound' + "500": + $ref: 'openapi.yml#/components/responses/InternalServerError' + + security: + - basicAuth: [] diff --git a/spec/openapi.yml b/spec/openapi.yml index 18c4ccb6..f4048e4f 100644 --- a/spec/openapi.yml +++ b/spec/openapi.yml @@ -203,18 +203,27 @@ security: - conjurAuth: [] paths: - '/authn/{account}/login': + '/{authenticator}/{account}/login': $ref: 'authentication.yaml#/components/paths/Login' - '/authn/{account}/{login}/authenticate': + '/{authenticator}/{service_id}/{account}/login': + $ref: 'authentication.yaml#/components/paths/ServiceLogin' + + '/{authenticator}/{account}/{login}/authenticate': $ref: 'authentication.yaml#/components/paths/Authenticate' + '/{authenticator}/{service_id}/{account}/{login}/authenticate': + $ref: 'authentication.yaml#/components/paths/AuthenticateService' + '/authn/{account}/password': $ref: 'authentication.yaml#/components/paths/ChangePassword' - '/authn/{account}/api_key': + '/{authenticator}/{account}/api_key': $ref: 'authentication.yaml#/components/paths/RotateApiKey' + '/{authenticator}/{service_id}/{account}': + $ref: 'authentication.yaml#/components/paths/UpdateAuthenticatorConfig' + # ========== STATUS =========== '/whoami': diff --git a/spec/status.yml b/spec/status.yml index d4e11113..5535ba36 100644 --- a/spec/status.yml +++ b/spec/status.yml @@ -1,6 +1,6 @@ components: schemas: - Authenticators: + AuthenticatorsResponse: type: object properties: installed: @@ -169,9 +169,12 @@ components: in: path schema: type: string + enum: + - oidc + - azure required: true description: "The type of authenticator" - example: "authn-oidc" + example: "oidc" - name: account in: path @@ -229,4 +232,4 @@ components: content: application/json: schema: - $ref: '#/components/schemas/Authenticators' + $ref: '#/components/schemas/AuthenticatorsResponse' diff --git a/test/config/ldap/certs/ca-chain.cert.pem b/test/config/ldap/certs/ca-chain.cert.pem new file mode 100644 index 00000000..8d863bb8 --- /dev/null +++ b/test/config/ldap/certs/ca-chain.cert.pem @@ -0,0 +1,134 @@ +-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwWzELMAkGA1UEBhMCVVMx +FjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxETAPBgNVBAoMCEN5YmVyQXJrMQ8wDQYD +VQQLDAZDb25qdXIxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcNMjAxMjAzMjMzMTI5WhcN +MzAxMjAxMjMzMTI5WjB2MQswCQYDVQQGEwJVUzEWMBQGA1UECAwNTWFzc2FjaHVz +ZXR0czEPMA0GA1UEBwwGTmV3dG9uMREwDwYDVQQKDAhDeWJlckFyazEPMA0GA1UE +CwwGQ29uanVyMRowGAYDVQQDDBFJbnRlcm1lZGlhdGUgQ0EgMTCCAiIwDQYJKoZI +hvcNAQEBBQADggIPADCCAgoCggIBAOhWDb/3GKJMeNmJWz5IBrRpVWqVOnUULtg7 +zoojPE54iwNZXIqAcmewVgI0QLNGs5FFecXECimKuiaQvh90AJpS4XX0oHKuq/c5 +M6poJEKD7tdPSrhoaAIbfDK5rBTAOwxhlcnsMGeJZCwJIfLowsSrYZ2DWpCZIOB5 +9HGWsTYU8fOArUjoKtiZRUlQCf5Z5CUf1zODxgSMwjUPDmDBLv0J43/wZESTtODi +Y6c7IVEQhgNnwb2E1mFmyWl52Z0/pLdiKIRoD4xMA9lvcLEqD3DsU5IB2hfZldd3 +eg/0L5ZtpVQZrRWL8xh/Eyc/h00vIwoh5fVp47xfjxvLzlvuc6sFozk30JxbtjYy +qV50MTxIBpBofdS69UMZetTsAPJoCM0eQtyq+jvvfm7P2cxik1H68cAkvizXOxKd +LZDkYS+eTerx7MvOINog/uGr/nPlUJpEAO7y6KjpYDUmM8xLrX3UVgjOQwop5gam +NmurdaDBd1r0pfzV8memW4FfHQkNPHKwzyfdNk3GFdCsBj1EPq2b/hPNXirKu2Lt +6LFGCTUfaw73v2rJ0y8YXgb2XWHYJebaTOBGfSxzDupygw8gQStXqChxviFDTg/a +/7ebxcaciPlH1bwc0WJl1+uN/PVibYGTzmvJAtiy9HRJaAgXQx2tsZVE/q89cMG2 +yzzFp/SBAgMBAAGjZjBkMB0GA1UdDgQWBBTisle+y9fUkfNzRGExLXDqdCrV3zAf +BgNVHSMEGDAWgBTpbzOrstTLiOeVgEY/p4WdzwbH1DASBgNVHRMBAf8ECDAGAQH/ +AgEUMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAdxdk6fIxJSwW +MDXuY0wgHKcLRERCWaGNoCdwgQoZQN+IL9haipjAfnZi/tq1YM95bOQgaQfqzfl8 +SYH8BnUrZmHI0TmF5+e1Dbcs3x7vRAV4HcWGkpXPIoL/9wXVvwffkNHkW9YseZMd +iicAQU5yuhO5usnfggLm4xTYDRCOm+R9wO+2r6ASN+3JzTpPy1UOB+i16tTacY8L +qo/T7ENM9stAM/xhSHEtC0ZNj1enPVdRQnMDK44c1HDCkqfYYWkmMS090RncAgDq +d6gVXjDQV1KR2l+3FkUKbhqSOnTi1MfFvvkJmByDpC5srkSw9XTlomlfzObYLpbp +oQi4HS6RWUCUG7Y92F09cWox6BzXP80h48JE4b3eERnOw7/XbNbT6XZcgNklJe5a +vFphquVOcjpuPRnNblV8BnLbt9CLVa3MSwemnpWmKcT6n9gUazKnQ4j0aWrOZJ4w +c71ddoRoUw2ITF4SgK2OpD1ref5n79AmxEyMiKiXvZeVIYE8EujH4SHG2tptiwEZ +WS1poa5HBEG44D0eYOukYSFmsPGhDZSKdN79X5n5eaBvTzW6MnWqSoH2fhyc3D+W +FYz3Dj+h+B4Pb/t7W/crsrcGDL7+Hy89yqUygU2LypVU+TTl5CpVTbqKAW8+gBxu +dJqOl4AP4R8kwea5IoEEgTvhdbibl3s= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFzjCCA7agAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwdjELMAkGA1UEBhMCVVMx +FjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxDzANBgNVBAcMBk5ld3RvbjERMA8GA1UE +CgwIQ3liZXJBcmsxDzANBgNVBAsMBkNvbmp1cjEaMBgGA1UEAwwRSW50ZXJtZWRp +YXRlIENBIDEwHhcNMjAxMjAzMjMzMTM2WhcNMzAxMjAxMjMzMTM2WjB2MQswCQYD +VQQGEwJVUzEWMBQGA1UECAwNTWFzc2FjaHVzZXR0czEPMA0GA1UEBwwGTmV3dG9u +MREwDwYDVQQKDAhDeWJlckFyazEPMA0GA1UECwwGQ29uanVyMRowGAYDVQQDDBFJ +bnRlcm1lZGlhdGUgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +ALhYMF8IESESDY1nrUoNNS2C088ROxFyixoGg1XtiduqcU9f2eCFrucoe9Xa+9n0 +4oRiaBPt/tmJX5dQUxWdASGzUV9kKMWMSMU5MSwr33K8gRf5/dIn/uoYRpJb+GAC +udDsggRBHB29Ba9ez/SD9Kz5pdu30V5PYYB0Vc0/PJ95CccTWCRvYJsLDWHx8xt2 +zAyaSJbwSnw3ZoFTih0oNTUvWzLf1hQAE4LM/crvYCeuyxOBs6go7tGUX4ioTazC +AWvNMv79zrZKMJCQqueTfSEjg00vrp2TMnTzYWFQDeKNX5y2fYjTTxgHwDsnqy0v +Yhq72aFlh4bzIPcX7WIOlGq3QV5onbJ6uX313lxbM6yxJNhGQsZ6+qN0fMnsZIAb +JRH+BFVECWnOuL4j4bGL3v0EfR0pFpi0AS83HDp8UdT3kT1ol5UpcTfJLeXhckII +Rx/z/nMYRvvIuY8Z/Jtq46hzRPtzJHirbezS5IPALccAhq74tCbHBOO0pZZUfb8x +xy3bWEfdlz+gvtPHoY7J1ieOQnZePvZcwHBYdUkRtAF8LcLESzCU2fR9Lj5VsvQ3 +BB4hDLhIzwhu2AVHSjjrpeMDVRoOr+38eToikEaurFgmp5zt/zQufb/Y0M62m7HC +YzwYLz+1xZ4TSyaIt9va/VIvbeLeDN6lmLZpO6enJtatAgMBAAGjZjBkMB0GA1Ud +DgQWBBSylc+odK4I5IV+q3EATNBXnMly8jAfBgNVHSMEGDAWgBTisle+y9fUkfNz +RGExLXDqdCrV3zASBgNVHRMBAf8ECDAGAQH/AgEUMA4GA1UdDwEB/wQEAwIBhjAN +BgkqhkiG9w0BAQsFAAOCAgEAjjYKha+HWl16XsL749Mf7pUqdxABsMqzAZopmYx0 +MFXH5rfbjEe53DPXM9YqvaifYW7VJjot5EK4OMu3c6mnXeFxzqXs/i9crP84888W +J+2cZfHYPbaiRSAbjulyGZAnfozJl7wF+T1q+w9gT4Bl74r/jkPB/yL7NO8RwCdH +CM61rrrGnglD6UIg0QTqHIwt9L1UIvWv8tholF2nTgRFSECnE/1oilqgegMya2HE +QfqGs7Fgbfugl93UF7NYD5qN6OMIWHhidmJBjR9j+mTubiD+dT2tq68KMA0U4g67 +JH4Ss6ThkwU8rGxUcPUBI3GoeSyefOJjSnh3vlRqnnfMGXFcK819Ek43ob/32mSy +MDkRESlUZ6ZP7/ALeB+JNqnZE77VeRisM5FTjl6eECGlrwmdtM45uVZ8adSGSOCH +5MlyBp0aA8ghABYnHxMLR6xt5mrorZQv73buHcZwd5lZZFXJjjylzy2mhrIBW60v +uBggcBEHKDlPHxAqfTF/QAJjPGDgVcSdBnR97ovXECwk4uQQ6n6nfIq+S2w5PPEQ +poHSFPcbnkKQMbyEaPcuFLkpgk5wCZtVjc9o0JFst3tTy3lt9oD4yZHz/wkbgmb+ +rJ0xKvIPwHRritN7We8gJoFUMyx6QnX6ArwrEvSW65uH4Yr+shXDlCJn0IZ8f6q7 +j0I= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFzjCCA7agAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwdjELMAkGA1UEBhMCVVMx +FjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxDzANBgNVBAcMBk5ld3RvbjERMA8GA1UE +CgwIQ3liZXJBcmsxDzANBgNVBAsMBkNvbmp1cjEaMBgGA1UEAwwRSW50ZXJtZWRp +YXRlIENBIDIwHhcNMjAxMjAzMjMzMTQzWhcNMzAxMjAxMjMzMTQzWjB2MQswCQYD +VQQGEwJVUzEWMBQGA1UECAwNTWFzc2FjaHVzZXR0czEPMA0GA1UEBwwGTmV3dG9u +MREwDwYDVQQKDAhDeWJlckFyazEPMA0GA1UECwwGQ29uanVyMRowGAYDVQQDDBFJ +bnRlcm1lZGlhdGUgQ0EgMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AMDd4iS4mAG3DRGRSHz/n1FRxa39S00Zt/cEQk0hgO6d0s1xQctiuCk1SA27kj/x +PS5HOlYS6RwtTZsA63MNf7JULUU+zfN/blUabk2OLclP77VgUn5n6wdpMKkf72+r +pYJ/alMiFXC22IWEU1apQCavyvidQn+tntbrni9LNf/l09frzROkzQRGR56+n4Fd +bHC4HDHMiXoKhoodigooq1Qqup6rQdldpL+TsQNhHSQ7XrUSYYJazEfQBaPRiSl+ +1AS/Kbpjyo4G+Ip9YgJGR8n6OURGcWIs05sjy5iQu/x1D7RbKR5ptnk75kSSqOp3 +fP7XYRKLb2MfI1rHLAP66dnHMqOmFdnJ7XLfswjglMFI4pxenrHr8xOoN1MP6gK8 +xFHSmDaGK47PARtA8pDWRo6/qpyj90IvrDwOMT0qnncitQ+3a4PO8eLLghkvL+hG +C9Z92LNgJftkkhRKVg08xh3Y4BhCqHoyvwCvHKVoXfPul17cjYBeF4A+P+qYwb5R +RC39+ozPEfqxJ2TmMJovdEQdxOLopuJn5z7G/6wE0pk8lAgOs78FoTgwhTlCQyiH +HLFqwWc2nwsEETkyfETFe7pT1mWHbbhpPDODkATPA57L9pTw0SiVMRp+/gRDies7 +3IPkQSxGqg6Ev+Qa8mZYpxRW2un6+mEwStJu9ri3CjN9AgMBAAGjZjBkMB0GA1Ud +DgQWBBRIFyjrsDHsnj+jG8GDw36cAYmuITAfBgNVHSMEGDAWgBSylc+odK4I5IV+ +q3EATNBXnMly8jASBgNVHRMBAf8ECDAGAQH/AgEUMA4GA1UdDwEB/wQEAwIBhjAN +BgkqhkiG9w0BAQsFAAOCAgEAJCusLFhO9O5jtTWp8k7kFZEOGE42w9zuT7/GL7+n +4mGDuNTjqqSEgXyV9bh89rUXjO7H45PBcgfu7H4hMVbomciA7QLpvQ0NzNbfSJMY +QgeVi0gKVVOuYODpKqiXDQZ/fyG1+0gxBegycQ5yBiWp36vclbZ9i1NtB0bMiZLR +Rbcrtgh16Y3qZzzXFjyVjj2dZHme7nfcMsLuFAZ6md8VxYoIdUa2hExAiE9Gj+jo +L2+PflC3giaWd1ufFAFIfeaZEArA11pOM6qu9Qd1nce5+BtvDbaTNbNGDRAjbPfX +Nxth20/1mJko8V/0/BGQeRxtLuemsEazkZaUkVxk0NtiOT5TdqLia518k0Xam56p +M6ZUNIYxvLacGlaugjhA8aKizGNGyQVT6W7JlK6eRp5eK0Hdp9EOR2yQ7ODzekkh +5YFSgB7tsp2T3iWDP7WUyfgMLeAcuReTQ6QSl5H3IEXhi8tgf/dVYPvborqWFpf0 +S5yOmB4oWb45z2/6dIToSVSx8FaHT31REk8+dFoLmZ1b0JTLKmS/A+ZI4JH8Hi9p +U+hlni06SESoYwM5VO1jaawPef8lhGh20ZoW7uiavSqF7bM4NpqmINr5OmDqwOMr +7QVpFhoZHLw/wq7VqY11uhNChldum1ZuZsILeIDoHr0RWub1XtBVL0MOn9uknzW0 +b6A= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFpzCCA4+gAwIBAgIUB1GKLDjTo4BfXEAj9gnWEPAN1gkwDQYJKoZIhvcNAQEL +BQAwWzELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxETAPBgNV +BAoMCEN5YmVyQXJrMQ8wDQYDVQQLDAZDb25qdXIxEDAOBgNVBAMMB1Jvb3QgQ0Ew +HhcNMjAxMjAzMjMzMTI0WhcNNDAxMTI4MjMzMTI0WjBbMQswCQYDVQQGEwJVUzEW +MBQGA1UECAwNTWFzc2FjaHVzZXR0czERMA8GA1UECgwIQ3liZXJBcmsxDzANBgNV +BAsMBkNvbmp1cjEQMA4GA1UEAwwHUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBANiIZg75PyCCBLYDNHox/d6UPkjcYki/1jk2a5q9VD8g/s8D +JXHEkmWbHyQroehJNA/0R8WOeaeNAUj0Pa4QmYKbur2476edgV1SF7iwuHTYPGcK +qHX0U3u1cfbIjzZFICUnavU9dJzX8qejjtULxWIQdjLp09U5oFKKMBUgs+hr+d1L +UuY7BAc+dnd2cTmf4WFSeukT7eIWk7wGXJLUrLXRKYZCOTJDbd4TkPt+ch/3I5vW +Z4QRVjy2abKH4+MWzfwj4gsnI/N/Uqec7dqtV8q8GeEyViYkUPhDKy9ZnwgJvPPn +KH8yhdyKswcXD0XibfpAH8Yl//ysJbn2AF8hAV87dX2s0Wn/adQ3RcraeFEnQ7Xs +JvD95nxDB+fSSThbds5/EI3KZ6hW3YOHQRjqbMbexNE9RUlKfiSx+El8XKiVO6df +aq5wLw/5QrjET0RGln3UtXyXByZjb50IkLdg5FqNmYpMUi3/6qVTHZ2QkoN5+x7u +AxLtRgYhViR5qoLuQ8y1s0Mm8S+CSl7GZVN4rAhXblIBiGkqP7X9x3BeTOsNk5Hk +LNxAHYgGcWPpIzgRaQK3f2Pf1NyHRMWb02WfWBi0EMRbdojylMeKkceBKkMcmK4F +x9mGaedqmu94ujQJ4/Xk6ys6J3AJ6Sef1cIb+5ZRvBVOv+rU9xzgPSa2Z9I/AgMB +AAGjYzBhMB0GA1UdDgQWBBTpbzOrstTLiOeVgEY/p4WdzwbH1DAfBgNVHSMEGDAW +gBTpbzOrstTLiOeVgEY/p4WdzwbH1DAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB +/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAwTI7ULrg2Zkc73f0g+d1xUBXJAem +t7s69I0XI//BDIuIfohgMAcdPEiwpPcqiOEO7lUGgPpMAMr7Nbe+ageNrrgx+XUr +rksGKhME0vkIOllNj6HTz6p8CdA4OsRVUNG9vi7l5VpdW4+gQo8ecd53Rhgdep+N +qwZCdf6WjbUjrzWKYh48aPBO1q4s9SOHu2c5B5JpfzcKiJWEsP8N46oIqtqntmlE +t/ErfDCfb1GbLKToPxDKAXp3v8JligCyVoXeMFpQebqlqkZKm8yJpCxEM2R0HDEa +nkbMwECQndRDZi2b/FrbGCoeN08JnC2rUbohapdXHQnrUi3/QbxJX3NcsTkYZhqe +knZSO3taeDGv3zJ0lOf6eXslFXdz5skcmcGuuB5HPN6pS8yvDcTwJFkrnNFqFEf7 +izSByqIu6mf9vhemNM9ZKGUK+5GMFvnYaJpT7T8L4qKKRoXG15SbE7rv1x7Uee/n +TfzI49brMUSOVMpqOT5lV2Nhmu0cHLoBraCVuSuA07wIgh2N9L/LP40Leryrf68q +TDig4Xfmzf0FGkoRHqVQj+l24xompRZI75aFDIz5q/ZcZVz072j8dKfbKizXHem0 +FjN3K2g2Lk5vNRCFe6sAKaALdb3PqWyPO3ZQuI0r8BF485K9+FNuN8UpZNnxNT4x +WAC3fSL+koywUnk= +-----END CERTIFICATE----- diff --git a/test/config/ldap/certs/dhparam.pem b/test/config/ldap/certs/dhparam.pem new file mode 100644 index 00000000..d963fc1f --- /dev/null +++ b/test/config/ldap/certs/dhparam.pem @@ -0,0 +1,8 @@ +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEAqtJnSpSax/oGFs7LnFsQ3m6oshC9la+uu53+aHBzT2XElLhVzFRe +e91P87ezsE0R6frF45zzznYzfwRg/UDfBptbywa5mW6e2SJMWSggn43RA1rBezY2 +sYc8692HUX+opsMNBZMPqs7hN7cD1EbBo5fHDyRyhVlhHUZgavvDLIbjuSSVdGVw +f6goxhkvBy6ft65rULzzZV/CidS6Y/KFi7NV0fwfi/Uog8wdQOH/4vu6GgsQwyJn +/a2k/x4R3N5oBvs15MUSNuZcDmFooqZxdC+9FyjLL9/J3bdmnJpC20oaxr6Ul7/Q +JQBPS9oag6saT7UAaaycejFkrhsGwKJt+wIBAg== +-----END DH PARAMETERS----- diff --git a/test/config/ldap/certs/ldap-server.cert.pem b/test/config/ldap/certs/ldap-server.cert.pem new file mode 100644 index 00000000..435a2145 --- /dev/null +++ b/test/config/ldap/certs/ldap-server.cert.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFmTCCA4GgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwdjELMAkGA1UEBhMCVVMx +FjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxDzANBgNVBAcMBk5ld3RvbjERMA8GA1UE +CgwIQ3liZXJBcmsxDzANBgNVBAsMBkNvbmp1cjEaMBgGA1UEAwwRSW50ZXJtZWRp +YXRlIENBIDMwHhcNMjAxMjAzMjMzMTQ5WhcNMjExMjAzMjMzMTQ5WjBwMQswCQYD +VQQGEwJVUzEWMBQGA1UECAwNTWFzc2FjaHVzZXR0czEPMA0GA1UEBwwGTmV3dG9u +MREwDwYDVQQKDAhDeWJlckFyazEPMA0GA1UECwwGQ29uanVyMRQwEgYDVQQDDAts +ZGFwLXNlcnZlcjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMq4bM2M +Bshn0GvUNKBMCWjNR/iLoMXPecSUmDeG149jHD5z11CJ2BaIs77y18UUZvh3tZXv +b4zNKf3m3qu4Cr/g6RdDi8Fq7BQDIPlEIArZuD7mGWnnusDe0WsXK8vk6qRPIXv8 +x1kv6R6ZSBK9KPEeQze0GduwFNieuI9BcVbhhfagfw9UBIM7cHcgulgx17jyzDR0 +98fKmDKiTALwcdGLUzrjJ/xRbXcbApvRKkCpeiF+Cq90TPhi6Xd58Usb17ivZyuz +5qweEJ0LJaD+1gjBRn3A2cxF0lWaAtmmPueAlF+xOMu0g17kfPPac4dRQUDmWDaz +oRsI6AppGsXuV4cdLMHknS27yvhHBLgQfN2uIW1JB9AjP9tHDK/JDVm6MKKcY97r +0f1v9LHQpdoh8uOA69Y9lhgEz6EBOz9PuzesistTc+yxSDsllPIfi8oPZFb/elhs +rEn3l5bF5eSrQMogj77uscmZn+9Abt3tHzJ39MRrthjdYliahUPScQNC+LZ580f6 +2Svg4SpQqsuu7uXs2TuA4U8X3TdeetPB3hV2vJmFhZeOOvAxIrpwUbwiWmlBx7X5 +/xoEI5VceQqJL1bRbDRVWZGg7MGaHNPbnmtz5xdDjuSSiKdc5foJAvaoC1N9aYGH ++jpMi0d93/oSQPh75sRp879RKqGVmabYIg9XAgMBAAGjNzA1MDMGA1UdEQQsMCqC +C2xkYXAtc2VydmVyghtsZGFwLXNlcnZlci5teWNvbXBhbnkubG9jYWwwDQYJKoZI +hvcNAQELBQADggIBAHgFQWm9DcWy0/RZ/uLZH4REn6EeDiymSeDV7VIvv5Jdn4jQ +dURHvZ0/puXKvb02o1ByfCXtmLH/5gJb0zs8MqvV7BbQuxeiE5MGF3WPbGN2pMbt +UrkTrsjlBDG7N19dBEfo/c6P5QG/Ugi0ZCWVciznBROGPHoDK9ddWmdTXRKmkX7K +ctkqU47x80iGEdTNegdpVjFpT6t4w6zNpgRotCWFrIdxew3LA5AAL1k0P9ua2VWO +4KIyPj441rnRMJ+bCvm7CAPqn5fprx+iO0W09a4gx65WrsB3x3hGlGO70ztb9uxi +jSPxmYO+CLfGyiTYi0hdCvZIJTDyPBRWLlnHXX2dYq5rdLcjgxQuUU/dw63pRv9z +502ZqVlv5YUWHDhMFjrfN2HrAM52IgNt9hA5jVvrS+StmngMhpkQfiToOAjYWSoF +s+lTGh0SSw9r/YEkz2KR3PWDVtIahEOHIJfc2BNqex1Jyz88SggaHEuHH113c2Ka +6Jl9ZvodGCXgbf+770VlEnTwPo1CngoD8hYGHKSKXA/0JDYKuJeVkYKwu5ubDx1r +nXcOmEd4QaFmZDu0Q+g5Tpzgyu1oJxNaptYqbv34+VtDEQcvYQKDVmujn9y7ubtZ +J6MmFg55A+8hPdcmHl80mp3HAy+gnDyYUUHLdrW/Lwt9ihu4letVc+t+ibql +-----END CERTIFICATE----- diff --git a/test/config/ldap/certs/ldap-server.key.pem b/test/config/ldap/certs/ldap-server.key.pem new file mode 100644 index 00000000..05b7644d --- /dev/null +++ b/test/config/ldap/certs/ldap-server.key.pem @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff --git a/test/config/ldap/certs/root.cert.pem b/test/config/ldap/certs/root.cert.pem new file mode 100644 index 00000000..acaa6aae --- /dev/null +++ b/test/config/ldap/certs/root.cert.pem @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +MIIFpzCCA4+gAwIBAgIUB1GKLDjTo4BfXEAj9gnWEPAN1gkwDQYJKoZIhvcNAQEL +BQAwWzELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxETAPBgNV +BAoMCEN5YmVyQXJrMQ8wDQYDVQQLDAZDb25qdXIxEDAOBgNVBAMMB1Jvb3QgQ0Ew +HhcNMjAxMjAzMjMzMTI0WhcNNDAxMTI4MjMzMTI0WjBbMQswCQYDVQQGEwJVUzEW +MBQGA1UECAwNTWFzc2FjaHVzZXR0czERMA8GA1UECgwIQ3liZXJBcmsxDzANBgNV +BAsMBkNvbmp1cjEQMA4GA1UEAwwHUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBANiIZg75PyCCBLYDNHox/d6UPkjcYki/1jk2a5q9VD8g/s8D +JXHEkmWbHyQroehJNA/0R8WOeaeNAUj0Pa4QmYKbur2476edgV1SF7iwuHTYPGcK +qHX0U3u1cfbIjzZFICUnavU9dJzX8qejjtULxWIQdjLp09U5oFKKMBUgs+hr+d1L +UuY7BAc+dnd2cTmf4WFSeukT7eIWk7wGXJLUrLXRKYZCOTJDbd4TkPt+ch/3I5vW +Z4QRVjy2abKH4+MWzfwj4gsnI/N/Uqec7dqtV8q8GeEyViYkUPhDKy9ZnwgJvPPn +KH8yhdyKswcXD0XibfpAH8Yl//ysJbn2AF8hAV87dX2s0Wn/adQ3RcraeFEnQ7Xs +JvD95nxDB+fSSThbds5/EI3KZ6hW3YOHQRjqbMbexNE9RUlKfiSx+El8XKiVO6df +aq5wLw/5QrjET0RGln3UtXyXByZjb50IkLdg5FqNmYpMUi3/6qVTHZ2QkoN5+x7u +AxLtRgYhViR5qoLuQ8y1s0Mm8S+CSl7GZVN4rAhXblIBiGkqP7X9x3BeTOsNk5Hk +LNxAHYgGcWPpIzgRaQK3f2Pf1NyHRMWb02WfWBi0EMRbdojylMeKkceBKkMcmK4F +x9mGaedqmu94ujQJ4/Xk6ys6J3AJ6Sef1cIb+5ZRvBVOv+rU9xzgPSa2Z9I/AgMB +AAGjYzBhMB0GA1UdDgQWBBTpbzOrstTLiOeVgEY/p4WdzwbH1DAfBgNVHSMEGDAW +gBTpbzOrstTLiOeVgEY/p4WdzwbH1DAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB +/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAwTI7ULrg2Zkc73f0g+d1xUBXJAem +t7s69I0XI//BDIuIfohgMAcdPEiwpPcqiOEO7lUGgPpMAMr7Nbe+ageNrrgx+XUr +rksGKhME0vkIOllNj6HTz6p8CdA4OsRVUNG9vi7l5VpdW4+gQo8ecd53Rhgdep+N +qwZCdf6WjbUjrzWKYh48aPBO1q4s9SOHu2c5B5JpfzcKiJWEsP8N46oIqtqntmlE +t/ErfDCfb1GbLKToPxDKAXp3v8JligCyVoXeMFpQebqlqkZKm8yJpCxEM2R0HDEa +nkbMwECQndRDZi2b/FrbGCoeN08JnC2rUbohapdXHQnrUi3/QbxJX3NcsTkYZhqe +knZSO3taeDGv3zJ0lOf6eXslFXdz5skcmcGuuB5HPN6pS8yvDcTwJFkrnNFqFEf7 +izSByqIu6mf9vhemNM9ZKGUK+5GMFvnYaJpT7T8L4qKKRoXG15SbE7rv1x7Uee/n +TfzI49brMUSOVMpqOT5lV2Nhmu0cHLoBraCVuSuA07wIgh2N9L/LP40Leryrf68q +TDig4Xfmzf0FGkoRHqVQj+l24xompRZI75aFDIz5q/ZcZVz072j8dKfbKizXHem0 +FjN3K2g2Lk5vNRCFe6sAKaALdb3PqWyPO3ZQuI0r8BF485K9+FNuN8UpZNnxNT4x +WAC3fSL+koywUnk= +-----END CERTIFICATE----- diff --git a/test/config/ldap/ldap.ldif b/test/config/ldap/ldap.ldif new file mode 100644 index 00000000..2ce2514d --- /dev/null +++ b/test/config/ldap/ldap.ldif @@ -0,0 +1,12 @@ +dn: uid=alice,dc=conjur,dc=net +cn: Alice +sn: Smith +uid: alice +givenName: alice +mail: alice@conjur.net +objectClass: person +objectClass: uidObject +objectClass: organizationalPerson +objectClass: inetOrgPerson +objectClass: top +userPassword: alice diff --git a/test/config/policy.yaml b/test/config/policy.yaml index 2c090874..b7f1dc25 100644 --- a/test/config/policy.yaml +++ b/test/config/policy.yaml @@ -2,3 +2,20 @@ - !variable testSecret - !user alice +- !user charles + +- !policy + id: conjur/authn-ldap/test + body: + - !webservice + + - !group users + + - !permit + role: !group users + privilege: [ read, authenticate ] + resource: !webservice + +- !grant + role: !group conjur/authn-ldap/test/users + member: !user alice diff --git a/test/python/api_config.py b/test/python/api_config.py index 76830ca1..411f6ba3 100644 --- a/test/python/api_config.py +++ b/test/python/api_config.py @@ -15,12 +15,27 @@ CONJUR_AUTHN_LOGIN = 'CONJUR_AUTHN_LOGIN' CONJUR_ACCOUNT = 'CONJUR_ACCOUNT' +WEBSERVICE_POLICY = pathlib.Path('test/config/webservice.yml') + +def get_webservice_policy(): + """Gets the text for the webservice testing policy""" + with open(WEBSERVICE_POLICY, 'r') as policy: + return policy.read() + + def get_default_policy(): """Gets the default testing policy""" with open(pathlib.Path('.').resolve() / 'test/config/policy.yaml', 'r') as default_policy: return default_policy.read() -def get_api_config(): +def get_bad_auth_api_config(username='admin'): + """Gets a default API config to be used with the testsing setup with no password + specified""" + config = get_api_config(username=username) + config.password = None + return config + +def get_api_config(username='admin'): """Gets a default API config to be used with the testsing setup""" config = openapi_client.Configuration( host='https://conjur-https', @@ -29,7 +44,7 @@ def get_api_config(): config.ssl_ca_cert = CERT_DIR.joinpath(SSL_CERT_FILE) config.cert_file = CERT_DIR.joinpath(CONJUR_CERT_FILE) config.key_file = CERT_DIR.joinpath(CONJUR_KEY_FILE) - config.username = os.environ[CONJUR_AUTHN_LOGIN] + config.username = username return config def get_api_key(username): @@ -37,7 +52,7 @@ def get_api_key(username): if username == 'admin': return os.environ[CONJUR_AUTHN_API_KEY] auth_api = openapi_client.api.authn_api.AuthnApi(get_api_client()) - api_key = auth_api.rotate_api_key(os.environ[CONJUR_ACCOUNT], role=f'user:{username}') + api_key = auth_api.rotate_api_key('authn', os.environ[CONJUR_ACCOUNT], role=f'user:{username}') return api_key def get_api_client(username='admin'): @@ -53,6 +68,7 @@ def get_api_client(username='admin'): client = openapi_client.ApiClient(config) auth = openapi_client.api.AuthnApi(client) api_token = auth.authenticate( + 'authn', account, username, api_key, diff --git a/test/python/test_authn_api.py b/test/python/test_authn_api.py index 6944261c..64c87d61 100644 --- a/test/python/test_authn_api.py +++ b/test/python/test_authn_api.py @@ -7,16 +7,14 @@ import openapi_client from . import api_config -from .api_config import CONJUR_AUTHN_API_KEY, CONJUR_ACCOUNT +from .api_config import CONJUR_AUTHN_API_KEY class TestAuthnApi(api_config.ConfiguredTest): """AuthnApi integration tests. Ensures that authentication with a Conjur server is working""" - @classmethod def setUpClass(cls): super().setUpClass() cls.api_key = os.environ[CONJUR_AUTHN_API_KEY] - cls.account = os.environ[CONJUR_ACCOUNT] @classmethod def tearDownClass(cls): @@ -32,6 +30,8 @@ def setUp(self): self.client = openapi_client.ApiClient(self.config) self.api = openapi_client.api.authn_api.AuthnApi(self.client) + self.bad_auth_api = openapi_client.api.authn_api.AuthnApi(self.bad_auth_client) + def tearDown(self): self.client.close() @@ -44,7 +44,7 @@ def test_authenticate(self): login = self.config.username body = self.api_key - response = self.api.authenticate(self.account, login, body).replace("\'","\"") + response = self.api.authenticate('authn', self.account, login, body).replace("\'","\"") response_json = json.loads(response) response_keys = response_json.keys() @@ -58,13 +58,13 @@ def test_login(self): Gets the API key of a user given the username and password via HTTP Basic Authentication. """ # Attempt to login - self.api.login(self.account) + self.api.login('authn', self.account) # Ensure we cannot login with a bad password self.config.password = "FakePassword123" with self.assertRaises(openapi_client.exceptions.ApiException): - self.api.login(self.account) + self.api.login('authn', self.account) def test_rotate_api_key(self): """Test case for rotate_api_key @@ -72,11 +72,11 @@ def test_rotate_api_key(self): Rotates a user’s API key. """ # Rotate the key and attempt to login with it - new_key = self.api.rotate_api_key(self.account) + new_key = self.api.rotate_api_key('authn', self.account) self.config.password = new_key - self.api.login(self.account) + self.api.login('authn', self.account) # We rotated the API key so we have to update the class variable self.__class__.api_key = new_key @@ -85,20 +85,19 @@ def test_set_password(self): """Test case for set_password Changes a user’s password. - """ - # Set a new password and try to authenticate with it + """ # Set a new password and try to authenticate with it test_password = "PAssword!234" self.api.set_password(self.account, body=test_password) self.config.password = test_password - self.api.login(self.account) + self.api.login('authn', self.account) # Attempt to change password with bad auth info self.config.password = "BadPassword" with self.assertRaises(openapi_client.exceptions.ApiException): - self.api.login(self.account) + self.api.login('authn', self.account) self.config.password = test_password @@ -108,5 +107,117 @@ def test_set_password(self): with self.assertRaises(openapi_client.exceptions.ApiException): self.api.set_password(self.account, body=invalid_pass) + +class TestExternalAuthnApi(api_config.ConfiguredTest): + """Class tests api functions relating to external authenticators + + Separate from the Authn tests to avoid issues with changing api keys/paswords + """ + def setUp(self): + self.api = openapi_client.api.authn_api.AuthnApi(self.client) + self.bad_auth_api = openapi_client.api.authn_api.AuthnApi(self.bad_auth_client) + + def test_update_authenticator_config_204(self): + """Test case for update_authenticator_config 204 response + + Updates the authenticators configuration + """ + _, status, _ = self.api.update_authenticator_config_with_http_info( + 'authn-ldap', + 'test', + self.account, + enabled=True + ) + + self.assertEqual(status, 204) + + def test_update_authenticator_config_401(self): + """Test case for update_authenticator_config 401 response""" + with self.assertRaises(openapi_client.exceptions.ApiException) as context: + self.bad_auth_api.update_authenticator_config( + 'oidc', + 'okta', + self.account, + enabled=False + ) + + self.assertEqual(context.exception.status, 401) + + def test_update_authenticator_config_404(self): + """Test case for update_authenticator_config 404 response""" + with self.assertRaises(openapi_client.exceptions.ApiException) as context: + self.api.update_authenticator_config( + 'oidc', + 'okta', + self.account, + enabled=False + ) + + self.assertEqual(context.exception.status, 404) + + def test_service_login_200(self): + """Test case for service_login 200 response + + Login with the given authenticator + """ + alice_config = api_config.get_api_config(username='alice') + alice_config.password = 'alice' + alice_client = openapi_client.ApiClient(alice_config) + alice_api = openapi_client.api.authn_api.AuthnApi(alice_client) + + _, status, _ = alice_api.service_login_with_http_info('authn-ldap', 'test', self.account) + + self.assertEqual(status, 200) + + def test_service_login_401(self): + """Test case for service_login 401 response""" + with self.assertRaises(openapi_client.exceptions.ApiException) as context: + self.bad_auth_api.service_login('iam', 'aws', self.account) + + self.assertEqual(context.exception.status, 401) + + def test_authenticate_service_200(self): + """Test case for service_login 200 response + + Login with the given authenticator + """ + alice_config = api_config.get_api_config(username='alice') + alice_client = openapi_client.ApiClient(alice_config) + alice_api = openapi_client.api.authn_api.AuthnApi(alice_client) + + _, status, _ = alice_api.authenticate_service_with_http_info( + 'authn-ldap', + 'test', + self.account, + 'alice', + 'alice' + ) + + self.assertEqual(status, 200) + + def test_authenticate_service_401(self): + """Test case for authenticate_service 401 response + + Login with the given authenticator + """ + with self.assertRaises(openapi_client.exceptions.ApiException) as context: + self.api.authenticate_service( + 'authn-ldap', + 'test', + self.account, + 'admin', + 'test' + ) + + self.assertEqual(context.exception.status, 401) + + def test_authenticate_service_404(self): + """Test case for authenticate_service 404 response""" + with self.assertRaises(openapi_client.exceptions.ApiException) as context: + self.api.authenticate_service('nonexist', 'nonexist', self.account, 'admin', 'badpass') + + self.assertEqual(context.exception.status, 404) + + if __name__ == '__main__': unittest.main() diff --git a/test/python/test_host_factory_api.py b/test/python/test_host_factory_api.py index 85a60803..027b176b 100644 --- a/test/python/test_host_factory_api.py +++ b/test/python/test_host_factory_api.py @@ -58,7 +58,7 @@ def test_create_host(self): # Make sure the new host can authenticate authn = openapi_client.api.authn_api.AuthnApi(self.client) - authn.authenticate(self.account, f'host/{TEST_HOST}', new_host['api_key']) + authn.authenticate('authn', self.account, f'host/{TEST_HOST}', new_host['api_key']) def test_create_host_token(self): """Test case for create_host_token diff --git a/test/python/test_status_api.py b/test/python/test_status_api.py index f263aec8..ba75cb33 100644 --- a/test/python/test_status_api.py +++ b/test/python/test_status_api.py @@ -1,7 +1,6 @@ from __future__ import absolute_import import unittest -import pathlib import openapi_client @@ -21,13 +20,6 @@ "token_issued_at", ] -WEBSERVICE_POLICY = pathlib.Path('test/config/webservice.yml') - -def get_webservice_policy(): - """Gets the text for the webservice testing policy""" - with open(WEBSERVICE_POLICY, 'r') as policy: - return policy.read() - class TestStatusApi(api_config.ConfiguredTest): """StatusApi unit test stubs""" @classmethod @@ -35,7 +27,7 @@ def setup_webservice(cls): """loads the webservice policy into conjur and gets it setup""" policies_api = openapi_client.api.policies_api.PoliciesApi(cls.client) secrets_api = openapi_client.api.secrets_api.SecretsApi(cls.client) - policies_api.modify_policy(cls.account, 'root', get_webservice_policy()) + policies_api.modify_policy(cls.account, 'root', api_config.get_webservice_policy()) secrets_api.create_variable( cls.account, "variable", @@ -161,7 +153,10 @@ def test_authenticators_index_200(self): authenticators, status, _ = self.api.authenticators_index_with_http_info() self.assertEqual(status, 200) - self.assertIsInstance(authenticators, openapi_client.models.authenticators.Authenticators) + self.assertIsInstance( + authenticators, + openapi_client.models.authenticators_response.AuthenticatorsResponse + ) for i in AUTHENTICATOR_FIELDS: lst = getattr(authenticators, i)