|
| 1 | +- [LDAP](#ldap) |
| 2 | + * [Supported LDAP protocol](#supported-ldap-protocol) |
| 3 | + * [Authenticate Authgear as a LDAP client](#authenticate-authgear-as-a-ldap-client) |
| 4 | + * [Configuration of LDAP servers](#configuration-of-ldap-servers) |
| 5 | + * [The database schema of a LDAP identity](#the-database-schema-of-a-ldap-identity) |
| 6 | + * [Handling of a LDAP identity](#handling-of-a-ldap-identity) |
| 7 | + * [The UX of LDAP in Auth UI](#the-ux-of-ldap-in-auth-ui) |
| 8 | + |
| 9 | +# LDAP |
| 10 | + |
| 11 | +This document describes the LDAP support in Authgear. Authgear acts as a LDAP client, and connects to one or more LDAP servers. |
| 12 | + |
| 13 | +## Supported LDAP protocol |
| 14 | + |
| 15 | +The supported LDAP protocol is LDAPv3, which is specified in [RFC4511](https://datatracker.ietf.org/doc/html/rfc4511). |
| 16 | + |
| 17 | +Authgear MUST BE compatible with |
| 18 | + |
| 19 | +1. A LDAP server without TLS (i.e. ldap://) |
| 20 | +2. The non-standard ldaps:// |
| 21 | +3. The StartTLS operation, as defined in [Section 4.14 in RFC4511](https://datatracker.ietf.org/doc/html/rfc4511#section-4.14) |
| 22 | + |
| 23 | +When the connection URL starts with `ldap://`, StartTLS will be tried. |
| 24 | +If the LDAP server responds protocolError, as defined in [Section 4.14.1 in RFC4511](https://datatracker.ietf.org/doc/html/rfc4511#section-4.14.1), |
| 25 | +then Authgear will treat it as no TLS is required. |
| 26 | + |
| 27 | +When the connection URL starts with `ldaps://`, then Authgear will connect to the LDAP server with TLS directly, without using StartTLS. |
| 28 | + |
| 29 | +## Authenticate Authgear as a LDAP client |
| 30 | + |
| 31 | +It is very common that before a LDAP client can run any [Search Operation](https://datatracker.ietf.org/doc/html/rfc4511#section-4.5), |
| 32 | +the LDAP client must perform [Bind Operation](https://datatracker.ietf.org/doc/html/rfc4511#section-4.2) first. |
| 33 | + |
| 34 | +Authgear supports Simple Bind with username and password. |
| 35 | + |
| 36 | +## Configuration of LDAP servers |
| 37 | + |
| 38 | +The following example demonstrates how the developer should configure Authgear to connect to their LDAP servers. |
| 39 | + |
| 40 | +In `authgear.yaml` |
| 41 | + |
| 42 | +```yaml |
| 43 | +identity: |
| 44 | + ldap: |
| 45 | + servers: |
| 46 | + - name: ldap1 |
| 47 | + url: "ldap://localhost:389" |
| 48 | + base_distinguished_name: "dc=localhost" |
| 49 | + relative_distinguished_name_attribute: "uid" |
| 50 | + - name: ldap2 |
| 51 | + url: "ldap://mycompany.com:389" |
| 52 | + base_distinguished_name: "dc=mycompany,dc=com" |
| 53 | + relative_distinguished_name_attribute: "uid" |
| 54 | +``` |
| 55 | +
|
| 56 | +- `identity.ldap.servers.name`: A name that only exists in `authgear.yaml` and `authgear.secrets.yaml` for associating a LDAP server. It serves no other purpose. |
| 57 | +- `identity.ldap.servers.url`: The connection URL to the LDAP server. The scheme MUST be `ldap:` or `ldaps:`. The URL MUST contain `host`, and optionally a port. If the port is omitted, the default port of the scheme is assumed. The default port of `ldap:` is `389`, while the default port of `ldaps:` is `636`. The URL MUST NOT contain other elements, such as path, nor query. |
| 58 | + |
| 59 | +> Why does `identity.ldap.servers.url` allow scheme, host, and port? |
| 60 | +> The LDAP URL, defined in [Section 2 in RFC 4516](https://datatracker.ietf.org/doc/html/rfc4516#section-2), is syntactically different from the URL defined in [RFC3986](https://datatracker.ietf.org/doc/html/rfc3986). |
| 61 | +> In particular, a LDAP URL can contain multiple question mark characters. |
| 62 | +> To ease implementation, we do not support the LDAP URL, and require a RFC3986 URL (which is implemented by the standard library net/url package). |
| 63 | + |
| 64 | +- `identity.ldap.servers.base_distinguished_name`: The base distinguished name to construct a Search Request, as defined in [Section 4.5.1 in RFC4511](https://datatracker.ietf.org/doc/html/rfc4511#section-4.5.1). |
| 65 | +- `identity.ldap.servers.relative_distinguished_name_attribute`: The attribute name Authgear should use to construct the search request. For example, if the value is `uid`, and the end-user gives a username of `user1`, and the base distinguished name is `dc=example,dc=com`, then the relative distinguished name is `uid=user1`, and the distinguished name is `uid=user1,dc=example,dc=com`. |
| 66 | + |
| 67 | +> base_distinguished_name and relative_distinguished_name_attribute may not be sufficient if the developer needs to determine the DN in a more dynamic way. |
| 68 | +> In the future, we can support a new configuration, distinguished_name_template, which is a Go template that MUST return a DN. |
| 69 | +> It looks like |
| 70 | +> {{- if (hasSuffix $.Username "@mycompany.com") }} |
| 71 | +> {{- (ldapDN (ldapAttribute "uid" $.Username) (ldapParse "dc=mycompany,dc=com") ) }} |
| 72 | +> {{- else }} |
| 73 | +> {{- (ldapDN (ldapAttribute "uid" $.Username) (ldapParse "dc=anothercompany,dc=com") ) }} |
| 74 | +> {{- end }} |
| 75 | + |
| 76 | +> TODO: The current configuration is missing an important feature. The feature is allow the developer to specify what attributes they want to retrieve from the LDAP server, and |
| 77 | +> what attributes map to which standard attributes. |
| 78 | + |
| 79 | +In `authgear.secrets.yaml` |
| 80 | + |
| 81 | +```yaml |
| 82 | +secrets: |
| 83 | +- data: |
| 84 | + items: |
| 85 | + - name: ldap1 |
| 86 | + username: authgear |
| 87 | + password: secret1 |
| 88 | + - name: ldap2 |
| 89 | + username: authgear |
| 90 | + password: secret2 |
| 91 | + key: ldap |
| 92 | +``` |
| 93 | + |
| 94 | +- `items.name`: To associate a LDAP server in `authgear.yaml`. |
| 95 | +- `items.username`: Optional. The username Authgear uses to authenticate itself to the LDAP server. If it is not provided, then Authgear does not authenticates itself, and assumes the LDAP server allows anonymous requests. |
| 96 | +- `items.password`: Optional. The password Authgear uses to authenticate itself to the LDAP server. If `username` is provided, then `password` is required. |
| 97 | + |
| 98 | +## The database schema of a LDAP identity |
| 99 | + |
| 100 | +```sql |
| 101 | +CREATE TABLE _auth_identity_ldap |
| 102 | +( |
| 103 | + id text PRIMARY KEY REFERENCES _auth_identity (id), |
| 104 | + app_id text NOT NULL, |
| 105 | + server_url text NOT NULL, |
| 106 | + distinguished_name text NOT NULL, |
| 107 | + claims jsonb NOT NULL, |
| 108 | + raw_entry_json jsonb NOT NULL |
| 109 | +); |
| 110 | +
|
| 111 | +CREATE UNIQUE INDEX _auth_identity_ldap_unique ON _auth_identity_ldap (app_id, server_url, distinguished_name); |
| 112 | +``` |
| 113 | + |
| 114 | +- `id`: The primary key of this table. This is the same as other `_auth_identity_*` tables. |
| 115 | +- `app_id`: The app ID of this table for multi-tenant. This is the same as other `_auth_identity_*` tables. |
| 116 | +- `server_url`: The URL to the LDAP server when this identity was created. The value is taken from the configuration at that moment. It does not change even if the URL in `authgear.yaml` changes. |
| 117 | +- `distinguished_name`: The distinguished name of this LDAP entry. |
| 118 | +- `claims`: The standard claims extracted from this LDAP entry. |
| 119 | +- `raw_entry_json`: The raw LDAP entry encoded in JSON. It looks like `{ "dn": "uid=johndoe,dc=example,dc=com", "attr1": ["value1"] }`. |
| 120 | + |
| 121 | +## Handling of a LDAP identity |
| 122 | + |
| 123 | +- To look up a LDAP identity in Authgear, we use the tuple `(app_id, server_url, distinguished_name)`. |
| 124 | +- Similar to OAuth identity, we update an LDAP identity when it is used in login. |
| 125 | + |
| 126 | +## The UX of LDAP in Auth UI |
| 127 | + |
| 128 | +In the MVP phase (that is, now), sign in with LDAP is like sign in with an OAuth provider. |
| 129 | +Except that the enter-username-and-password page is hosted by Authgear as a integral part of Auth UI. |
| 130 | + |
| 131 | +In the future, we may consider an option to make LDAP "replaces" Login ID in the UX. |
0 commit comments