0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[LDAP][dex] dexidp で LDAP シンプル・バインド・モード接続

0
Posted at

前回の記事で、

AWS ALB の LDAP 認証連携の構築
https://qiita.com/batatch/items/1577d453944070c19365

dexidp による OIDC-LDAP変換で ALB 認証連携を実施したのですが、実は LDAPサーバとなる ADにはそのままでは連携できなかったので、dexidpに少し手入れが必要でした。

通常、Apache等で認証連携するときは、管理アカウントでバインドしてから、ユーザを検索/認証するという動きをするのですが、対象の ADでは、直接ユーザアカウントでバインドするというものでした。
そのため、Apacheなどの静的設定で利用されておらず、プログラムで独自に接続する形になっていました。

この対応についての記録になります。

LDAP方式の違い

この LDAPの方式の違いがどういうものか分からず、調べてみたところ、静的な設定ファイルで 2種類の方式に対応している例がありました。

PostgreSQL 文書 / 20.10. LDAP認証
https://www.postgresql.jp/document/11/html/auth-ldap.html

このマニュアルでは、2種類の LDAP方式を以下のように説明しています。

  1. シンプル・バインド・モード (simple bind mode)
  2. サーチ+バインド・モード (search+bind mode)

後者が Apache等の設定でよく見る管理者アカウントで事前にバインドするもの、
前者が今回の ADのようにユーザアカウントで直接バインドするものです。

設定ファイルには、ldapbinddn/ldapbindpasswd でバインド用の管理者アカウントを設定すれば「サーチ+バインド・モード」、
ldapprefix/ldapsuffix を設定すれば「シンプル・バインド・モード」となるようです。

シンプル・バインド・モードでは、prefix username suffix という形でユーザアカウントでバインドするようになります。

これを参考に、dexidp の LDAPコネクタに設定項目を追加できるようにしてみます。

dexidp へ LDAP シンプル・バインド・モードを追加

PostgreSQLを参考に、以下の形で設定できるようにします。
bindDNPrefixbindDNSuffix というパラメータで、シンプル・バインド・モードの場合に、ユーザアカウントの前後に追加するラベルを指定します。

/dex/config.yaml
issuer: https://oidc.example.com/dex
storage:
  type: sqlite3
  config:
    file: dex/dex.db
web:
  http: 0.0.0.0:5556
connectors:
- type: ldap
  name: OpenLDAP
  id: ldap
  config:
    host: ldap.example.com:389
    insecureNoSSL: true
#    bindDN: cn=admin,dc=example,dc=org
#    bindPW: admin
    bindDNPrefix: "cn="                           ★追加
    bindDNSuffix: ",ou=People,dc=example,dc=org"  ★追加
    usernamePrompt: User ID
    userSearch:
      baseDN: ou=People,dc=example,dc=com
      username: mail
      idAttr: DN
      emailAttr: mail
      nameAttr: cn
    groupSearch:
      baseDN: ou=Groups,dc=example,dc=com
      userAttr: DN
      groupAttr: member
      nameAttr: cn
staticClients:
- id: app-id
  redirectURIs:
  - 'https://app.example.com/oauth2/idpresponse'
  name: 'App'
  secret: ZXhhbXBsZS1hcHAtc2VjcmV0

ソースの変更内容は以下のとおり。

diff --git a/connector/ldap/ldap.go b/connector/ldap/ldap.go
index aed7319..f1ddf01 100644
--- a/connector/ldap/ldap.go
+++ b/connector/ldap/ldap.go
@@ -31,6 +31,9 @@ import (
 //       rootCA: /etc/dex/ldap.ca
 //       bindDN: uid=seviceaccount,cn=users,dc=example,dc=com
 //       bindPW: password
+//       # for ldap simple bind mode.
+//       bindDNPrefix: uid=
+//       bindDNSuffix: ,cn=users,dc=example,dc=com
 //       userSearch:
 //         # Would translate to the query "(&(objectClass=person)(uid=<username>))"
 //         baseDN: cn=users,dc=example,dc=com
@@ -81,6 +84,11 @@ type Config struct {
        BindDN string `json:"bindDN"`
        BindPW string `json:"bindPW"`

+       // BindDNPrefix and BindDNSuffix for LDAP Simple bind mode.
+       // The connector uses BindDNPrefix username BindDNSuffix as bind username.
+       BindDNPrefix string `json:"bindDNPrefix"`
+       BindDNSuffix string `json:"bindDNSuffix"`
+
        // UsernamePrompt allows users to override the username attribute (displayed
        // in the username/password prompt). If unset, the handler will use
        // "Username".
@@ -249,7 +257,7 @@ func (c *Config) openConnector(logger log.Logger) (*ldapConnector, error) {
        if !ok {
                return nil, fmt.Errorf("groupSearch.Scope unknown value %q", c.GroupSearch.Scope)
        }
-       return &ldapConnector{*c, userSearchScope, groupSearchScope, tlsConfig, logger}, nil
+       return &ldapConnector{*c, userSearchScope, groupSearchScope, tlsConfig, logger, "", []byte{}}, nil
 }

 type ldapConnector struct {
@@ -261,6 +269,9 @@ type ldapConnector struct {
        tlsConfig *tls.Config

        logger log.Logger
+
+       uid  string
+       pass []byte
 }

 var (
@@ -296,12 +307,26 @@ func (c *ldapConnector) do(ctx context.Context, f func(c *ldap.Conn) error) erro
        }
        defer conn.Close()

+       var (
+               bindDN string
+               bindPW string
+       )
+       bindDN = c.BindDN
+       bindPW = c.BindPW
+
+       if c.BindDNPrefix != "" || c.BindDNSuffix != "" {
+               bindDN = fmt.Sprintf("%s%s%s", c.BindDNPrefix, c.uid, c.BindDNSuffix)
+               bindPW = string(c.pass)
+       }
+
+       c.logger.Debugf("ldap: - bindDN=<%s>", bindDN)
+
        // If bindDN and bindPW are empty this will default to an anonymous bind.
-       if err := conn.Bind(c.BindDN, c.BindPW); err != nil {
-               if c.BindDN == "" && c.BindPW == "" {
+       if err := conn.Bind(bindDN, bindPW); err != nil {
+               if bindDN == "" && bindPW == "" {
                        return fmt.Errorf("ldap: initial anonymous bind failed: %v", err)
                }
-               return fmt.Errorf("ldap: initial bind for user %q failed: %v", c.BindDN, err)
+               return fmt.Errorf("ldap: initial bind for user %q failed: %v", bindDN, err)
        }

        return f(conn)
@@ -414,6 +439,10 @@ func (c *ldapConnector) userEntry(conn *ldap.Conn, username string) (user ldap.E
 }

 func (c *ldapConnector) Login(ctx context.Context, s connector.Scopes, username, password string) (ident connector.Identity, validPass bool, err error) {
+
+       c.uid = username
+       c.pass = []byte(password)
+
        // make this check to avoid unauthenticated bind to the LDAP server.
        if password == "" {
                return connector.Identity{}, false, nil

上記の差分を patch 適用して dockerビルドするには、前回の Dockerfileを以下のように変更します。

FROM golang:1.13-alpine AS build-env
RUN apk add --no-cache --update alpine-sdk
RUN mkdir -p /go/src/github.com/dexidp \
    && cd /go/src/github.com/dexidp \
    && git clone https://github.com/dexidp/dex.git -b v2.21.0 --depth 1
COPY ldap_simple_bind.patch /go/src/github.com/dexidp/dex                 ★追加
RUN cd /go/src/github.com/dexidp/dex && git apply ldap_simple_bind.patch  ★追加

RUN cd /go/src/github.com/dexidp/dex && make release-binary

FROM alpine:3.10
RUN apk add --update ca-certificates openssl sqlite
USER root
COPY --from=build-env /go/bin/dex /usr/local/bin/dex
COPY --from=build-env /go/src/github.com/dexidp/dex/web /web
VOLUME /dex
WORKDIR /
ENTRYPOINT ["dex"]

GitHubにもアップしました。
https://github.com/batatch/dex/tree/feature/ldap_simple_bind

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?