From 50f2905cac50a25441752748e014c06c1db641f0 Mon Sep 17 00:00:00 2001 From: Eric Chiang Date: Tue, 22 Aug 2017 10:36:16 -0700 Subject: [PATCH] *: add standup script for LDAP --- Documentation/dev-integration-tests.md | 13 +++- Documentation/getting-started.md | 3 + Documentation/ldap-connector.md | 26 +++++++ examples/config-ldap.ldif | 42 +++++++++++ examples/config-ldap.yaml | 51 ++++++++++++++ scripts/slapd.sh | 98 ++++++++++++++++++++++++++ 6 files changed, 231 insertions(+), 2 deletions(-) create mode 100644 examples/config-ldap.ldif create mode 100644 examples/config-ldap.yaml create mode 100755 scripts/slapd.sh diff --git a/Documentation/dev-integration-tests.md b/Documentation/dev-integration-tests.md index 38d90c89..366b4ae3 100644 --- a/Documentation/dev-integration-tests.md +++ b/Documentation/dev-integration-tests.md @@ -50,9 +50,16 @@ $ sudo ./storage/sql/standup.sh destroy postgres ## LDAP -To run LDAP tests locally, you require a container running OpenLDAP. +The LDAP integration tests require [OpenLDAP][openldap] installed on the host machine. To run them, use `go test`: -Run OpenLDAP docker image: +``` +export DEX_LDAP_TESTS=1 +go test -v ./connector/ldap/ +``` + +To quickly stand up a LDAP server for development, see the LDAP [_"Getting started"_][ldap-getting-started] example. This also requires OpenLDAP installed on the host. + +To stand up a containerized LDAP server run the OpenLDAP docker image: ``` $ sudo docker run --hostname ldap.example.org --name openldap-container --detach osixia/openldap:1.1.6 @@ -136,3 +143,5 @@ connectors: Start both dex and the example app, and try logging in (requires not requesting a refresh token). [okta-sign-up]: https://www.okta.com/developer/signup/ +[openldap]: https://www.openldap.org/ +[ldap-getting-started]: ldap-connector.md#getting-started diff --git a/Documentation/getting-started.md b/Documentation/getting-started.md index 5633135d..da54f835 100644 --- a/Documentation/getting-started.md +++ b/Documentation/getting-started.md @@ -42,9 +42,12 @@ Login to dex through the example app using the following steps. Dex is generally used as a building block to drive authentication for other apps. See [_"Writing apps that use dex"_][using-dex] for an overview of instrumenting apps to work with dex. +For a primer on using LDAP to back dex's user store, see the OpenLDAP [_"Getting started"_][ldap-getting-started] example. + Check out the Documentation directory for further reading on setting up different storages, interacting with the dex API, intros for OpenID Connect, and logging in through other identity providers such as Google, GitHub, or LDAP. [go-setup]: https://golang.org/doc/install [example-config]: ../examples/config-dev.yaml [oidc-discovery]: https://openid.net/specs/openid-connect-discovery-1_0-17.html#ProviderMetadata [using-dex]: using-dex.md +[ldap-getting-started]: ldap-connector.md#getting-started diff --git a/Documentation/ldap-connector.md b/Documentation/ldap-connector.md index b04eabad..761d87d5 100644 --- a/Documentation/ldap-connector.md +++ b/Documentation/ldap-connector.md @@ -9,6 +9,30 @@ The connector executes two primary queries: 1. Finding the user based on the end user's credentials. 2. Searching for groups using the user entry. +## Getting started + +The dex repo contains a basic LDAP setup using [OpenLDAP][openldap]. + +First start the LDAP server using the example script. This will run the OpenLDAP daemon and seed it with a initial set of users. + +``` +./scripts/slapd.sh +``` + +This script sets the LDAP daemon to debug mode, and is expected to print several error messages which are normal. Once the server is up, run dex. + +``` +./bin/dex serve examples/config-ldap.yaml +``` + +Then run the OAuth client in another terminal. + +``` +./bin/example-app +``` + +Go to [http://localhost:5555](http://localhost:5555), login and enter the username and password of the LDAP user: `janedoe@example.com`/`foo`. Add the "groups" scope as part of the initial redirect to add group information from the LDAP server. + ## Security considerations Dex attempts to bind with the backing LDAP server using the end user's _plain text password_. Though some LDAP implementations allow passing hashed passwords, dex doesn't support hashing and instead _strongly recommends that all administrators just use TLS_. This can often be achieved by using port 636 instead of 389, and administrators that choose 389 are actively leaking passwords. @@ -252,3 +276,5 @@ connectors: ``` If the search finds an entry, it will attempt to use the provided password to bind as that user entry. + +[openldap]: https://www.openldap.org/ diff --git a/examples/config-ldap.ldif b/examples/config-ldap.ldif new file mode 100644 index 00000000..55cc81f9 --- /dev/null +++ b/examples/config-ldap.ldif @@ -0,0 +1,42 @@ +dn: dc=example,dc=org +objectClass: dcObject +objectClass: organization +o: Example Company +dc: example + +dn: ou=People,dc=example,dc=org +objectClass: organizationalUnit +ou: People + +dn: cn=jane,ou=People,dc=example,dc=org +objectClass: person +objectClass: inetOrgPerson +sn: doe +cn: jane +mail: janedoe@example.com +userpassword: foo + +dn: cn=john,ou=People,dc=example,dc=org +objectClass: person +objectClass: inetOrgPerson +sn: doe +cn: john +mail: johndoe@example.com +userpassword: bar + +# Group definitions. + +dn: ou=Groups,dc=example,dc=org +objectClass: organizationalUnit +ou: Groups + +dn: cn=admins,ou=Groups,dc=example,dc=org +objectClass: groupOfNames +cn: admins +member: cn=john,ou=People,dc=example,dc=org +member: cn=jane,ou=People,dc=example,dc=org + +dn: cn=developers,ou=Groups,dc=example,dc=org +objectClass: groupOfNames +cn: developers +member: cn=jane,ou=People,dc=example,dc=org diff --git a/examples/config-ldap.yaml b/examples/config-ldap.yaml new file mode 100644 index 00000000..513a0005 --- /dev/null +++ b/examples/config-ldap.yaml @@ -0,0 +1,51 @@ +issuer: http://127.0.0.1:5556/dex +storage: + type: sqlite3 + config: + file: examples/dex.db +web: + http: 0.0.0.0:5556 + +connectors: +- type: ldap + name: OpenLDAP + id: ldap + config: + host: localhost:10389 + + # No TLS for this setup. + insecureNoSSL: true + + # This would normally be a read-only user. + bindDN: cn=admin,dc=example,dc=org + bindPW: admin + + userSearch: + baseDN: ou=People,dc=example,dc=org + filter: "(objectClass=person)" + username: mail + # "DN" (case sensitive) is a special attribute name. It indicates that + # this value should be taken from the entity's DN not an attribute on + # the entity. + idAttr: DN + emailAttr: mail + nameAttr: cn + + groupSearch: + baseDN: ou=Groups,dc=example,dc=org + filter: "(objectClass=groupOfNames)" + + # A user is a member of a group when their DN matches + # the value of a "member" attribute on the group entity. + userAttr: DN + groupAttr: member + + # The group name should be the "cn" value. + nameAttr: cn + +staticClients: +- id: example-app + redirectURIs: + - 'http://127.0.0.1:5555/callback' + name: 'Example App' + secret: ZXhhbXBsZS1hcHAtc2VjcmV0 diff --git a/scripts/slapd.sh b/scripts/slapd.sh new file mode 100755 index 00000000..36a9cbbc --- /dev/null +++ b/scripts/slapd.sh @@ -0,0 +1,98 @@ +#!/bin/bash -e + +if ! [[ "$0" =~ "scripts/slapd.sh" ]]; then + echo "This script must be run in a toplevel dex directory" + exit 255 +fi + +command -v slapd >/dev/null 2>&1 || { + echo >&2 "OpenLDAP not installed. Install using one of the following commands: + + brew install openldap + + sudo dnf -y install openldap-servers openldap-clients + + sudo apt-get install slapd ldap-utils +"; exit 1; +} + +TEMPDIR=$( mktemp -d ) + +trap "{ rm -r $TEMPDIR ; exit 255; }" EXIT + +CONFIG_DIR=$PWD/connector/ldap/testdata + +# Include the schema files in the connector test directory. Installing OpenLDAP installs +# these in /etc somewhere, but the path isn't reliable across installs. Easier to ship +# the schema files directly. +for config in $( ls $CONFIG_DIR/*.schema ); do + echo "include $config" >> $TEMPDIR/config +done + +DATA_DIR=$TEMPDIR/data +mkdir $DATA_DIR + +# Config template copied from: +# http://www.zytrax.com/books/ldap/ch5/index.html#step1-slapd +cat << EOF >> $TEMPDIR/config +# MODULELOAD definitions +# not required (comment out) before version 2.3 +moduleload back_bdb.la + +database bdb +suffix "dc=example,dc=org" + +# root or superuser +rootdn "cn=admin,dc=example,dc=org" +rootpw admin +# The database directory MUST exist prior to running slapd AND +# change path as necessary +directory $DATA_DIR + +# Indices to maintain for this directory +# unique id so equality match only +index uid eq +# allows general searching on commonname, givenname and email +index cn,gn,mail eq,sub +# allows multiple variants on surname searching +index sn eq,sub +# sub above includes subintial,subany,subfinal +# optimise department searches +index ou eq +# if searches will include objectClass uncomment following +# index objectClass eq +# shows use of default index parameter +index default eq,sub +# indices missing - uses default eq,sub +index telephonenumber + +# other database parameters +# read more in slapd.conf reference section +cachesize 10000 +checkpoint 128 15 +EOF + +SLAPD_PID="" +trap "kill $SLAPD_PID" SIGINT + +# Background the LDAP daemon so we can run an LDAP add command. +slapd \ + -d any \ + -h "ldap://localhost:10389/" \ + -f $TEMPDIR/config & +SLAPD_PID=$! + +# Wait for server to come up. +time sleep 1 + +# Seed the initial set of users. Edit these values to change the initial +# set of users. +ldapadd \ + -x \ + -D "cn=admin,dc=example,dc=org" \ + -w admin \ + -H ldap://localhost:10389/ \ + -f $PWD/examples/config-ldap.ldif + +# Wait for slapd to exit. +wait $SLAPD_PID