3 # This script demonstrates using LDAP for Arvados user authentication.
5 # It configures pam_ldap(5) and arvados controller in a docker
6 # container, with pam_ldap configured to authenticate against an
7 # OpenLDAP server in a second docker container.
9 # After adding a "foo" user entry, it uses curl to check that the
10 # Arvados controller's login endpoint accepts the "foo" account
11 # username/password and rejects invalid credentials.
13 # It is intended to be run inside .../build/run-tests.sh (in
14 # interactive mode: "test lib/controller/localdb -tags=docker
15 # -check.f=LDAP -check.vv"). It assumes ARVADOS_TEST_API_HOST points
16 # to a RailsAPI server and the desired version of arvados-server is
17 # installed in $GOPATH/bin.
22 if [[ -n ${ARVADOS_DEBUG} ]]; then
27 hostname="$(hostname)"
32 for h in ${ldapctr} ${ctrlctr}; do
33 if [[ -n ${h} ]]; then
40 ldapctr=ldap-${RANDOM}
41 echo >&2 "Starting ldap server in docker container ${ldapctr}"
42 docker run --rm --detach \
46 docker logs --follow ${ldapctr} 2>$debug >$debug &
47 ldaphostport=$(docker port ${ldapctr} 389/tcp)
48 ldapport=${ldaphostport##*:}
49 ldapurl="ldap://${hostname}:${ldapport}"
50 passwordhash="$(docker exec -i ${ldapctr} slappasswd -s "secret")"
52 # These are the default admin credentials for osixia/openldap:1.3.0
56 cat >"${tmpdir}/zzzzz.yml" <<EOF
65 password: insecure_arvados_test
66 ManagementToken: e687950a23c3a9bceec28c6223a06c79
67 SystemRootToken: systemusertesttoken1234567890aoeuidhtnsqjkxbmwvzpy
73 BlobSigningKey: zfhgfenhffzltr9dixws36j1yhksjoll2grmku38mi7yxd66h5j4q9w4jzanezacp8s6q0ro3hxakfye02152hncy6zml2ed0uc
75 ForwardSlashNameSubstitution: /
79 "https://${hostname}:${ARVADOS_TEST_API_HOST##*:}/": {}
81 ExternalURL: http://0.0.0.0:9999/
83 "http://0.0.0.0:9999/": {}
90 cat >"${tmpdir}/pam_ldap.conf" <<EOF
91 base dc=example,dc=org
95 binddn cn=${adminuser},dc=example,dc=org
96 bindpw ${adminpassword}
99 cat >"${tmpdir}/add_example_user.ldif" <<EOF
100 dn: cn=bar,dc=example,dc=org
101 objectClass: posixGroup
105 description: "Example group 'bar'"
107 dn: uid=foo,dc=example,dc=org
112 mail: foobar@example.org
113 objectClass: inetOrgPerson
114 objectClass: posixAccount
116 objectClass: shadowAccount
120 shadowLastChange: 10701
121 loginShell: /bin/bash
124 homeDirectory: /home/foo
125 userPassword: ${passwordhash}
128 echo >&2 "Adding example user entry user=foo pass=secret (retrying until server comes up)"
129 docker run --rm --entrypoint= \
130 -v "${tmpdir}/add_example_user.ldif":/add_example_user.ldif:ro \
131 osixia/openldap:1.3.0 \
132 bash -c "for f in \$(seq 1 5); do if ldapadd -H '${ldapurl}' -D 'cn=${adminuser},dc=example,dc=org' -w '${adminpassword}' -f /add_example_user.ldif; then exit 0; else sleep 2; fi; done; echo 'failed to add user entry'; exit 1"
134 echo >&2 "Building arvados controller binary to run in container"
135 go build -o "${tmpdir}" ../../../cmd/arvados-server
137 ctrlctr=ctrl-${RANDOM}
138 echo >&2 "Starting arvados controller in docker container ${ctrlctr}"
139 docker run --detach --rm --name=${ctrlctr} \
141 -v "${tmpdir}/pam_ldap.conf":/etc/pam_ldap.conf:ro \
142 -v "${tmpdir}/arvados-server":/bin/arvados-server:ro \
143 -v "${tmpdir}/zzzzz.yml":/etc/arvados/config.yml:ro \
144 -v $(realpath "${PWD}/../../.."):/arvados:ro \
146 bash -c "apt update && DEBIAN_FRONTEND=noninteractive apt install -y ldap-utils libpam-ldap && pam-auth-update --package /usr/share/pam-configs/ldap && arvados-server controller"
147 docker logs --follow ${ctrlctr} 2>$debug >$debug &
148 ctrlhostport=$(docker port ${ctrlctr} 9999/tcp)
150 echo >&2 "Waiting for arvados controller to come up..."
151 for f in $(seq 1 20); do
152 if curl -s "http://${ctrlhostport}/arvados/v1/config" >/dev/null; then
160 echo >&2 "Arvados controller is up at http://${ctrlhostport}"
165 if ! echo "${resp}" | fgrep -q "${str}"; then
167 echo >&2 "FAIL: expected in response, but not found: ${str@Q}"
172 echo >&2 "Testing authentication failure"
173 resp="$(curl -s --include -H "X-Http-Method-Override: GET" -d username=foo -d password=nosecret "http://${ctrlhostport}/login" | tee $debug)"
174 check_contains "${resp}" "HTTP/1.1 401"
175 check_contains "${resp}" '{"errors":["Authentication failure"]}'
177 echo >&2 "Testing authentication success"
178 resp="$(curl -s --include -H "X-Http-Method-Override: GET" -d username=foo -d password=secret "http://${ctrlhostport}/login" | tee $debug)"
179 check_contains "${resp}" "HTTP/1.1 200"
180 check_contains "${resp}" '{"token":"v2/zzzzz-gj3su-'