Help us understand the problem. What is going on with this article?

Go言語からActive Directoryにアクセスしてみる(検索編)

More than 3 years have passed since last update.

はじめに

Go言語からActive Directoryを利用したいと思いましたので、まずは検索からやってみました。
尚、使用したパッケージはLDAPv3用ですので、OpenLDAP等のLDAPサーバへのアクセスでも応用できると思います。
また投稿内容は、ある程度Active Directory、LDAPの知識を有していることを前提としています。

LDAPパッケージのインストール

goコマンドでチャッチャとインストールです。

>go get -v gopkg.in/ldap.v2

サンプルコード

ldapsearch.go
package main

import (
    "gopkg.in/ldap.v2"
    "fmt"
    "log"
)

const (
    LDAPSV = "dc1.mydomain.local"
    PROTO  = "tcp"
    PORTNO = 389
    BINDDN = "cn=Administrator,cn=Users,dc=MYDOMAIN,dc=local"
    BINDPW = "P@ssw0rd"
    BASEDN = "dc=MYDOMAIN,dc=local"
    FILTER = "(&(objectCategory=computer)(operatingSystem=*Windows*))"
)

func main() {
    // LDAPサーバへ接続
    l, err := ldap.Dial(PROTO, fmt.Sprintf("%s:%d", LDAPSV, PORTNO))
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Ldap server connected.")
    defer func() {
        l.Close()
        fmt.Println("Ldap server disconnected.")
    }()

    //LDAPサーバ認証(バインド)
    err = l.Bind(BINDDN, BINDPW)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Ldap server logged in.")

    /*
    検索リクエスト作成

        コンストラクタ関数の引数
        func NewSearchRequest(
            BaseDN          string,
            Scope           int,
            DerefAliases    int,
            SizeLimit       int,
            TimeLimit       int,
            TypesOnly       bool,
            Filter          string,
            Attributes      []string,
            Controls        []Control,
        ) *SearchRequest
    */
    searchRequest := ldap.NewSearchRequest(
        BASEDN,
        ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
        FILTER,
        []string{"dn", "cn"},
        nil,
    )

    //検索リクエストを基にディレクトリ内検索
    sr, err := l.Search(searchRequest)
    if err != nil {
        log.Fatal(err)
    }

    //検索結果のリスト出力
    for _, entry := range sr.Entries {
        fmt.Printf("%s: %v\n", entry.DN, entry.GetAttributeValue("cn"))
    }
}

Go言語に慣れている方であれば、上記コードの細かい説明は要らないんじゃないかと思います。
尚、肝となる点は検索リクエスト(SearchRequest)作成の箇所となりますが、NewSearchRequestに渡すパラメータの説明は、下表のような感じです。
(Unix系OSでのldapsearchコマンドを簡易にした感じです)

NewSearchRequestパラメータ

パラメータ 説明
BaseDN 指定されたDNを起点としたツリー配下の検索を行います。
Scope ScopeBaseObject = BaseDNで指定された階層のみを検索します。
ScopeSingleLevel = BaseDNで指定された階層の1つ下の階層を検索します。
ScopeWholeSubtree = BaseDNで指定された階層以下(サブツリー)すべてを検索します。
DerefAliases エイリアスエントリの実名参照をどのように行うかを指定します。
NeverDerefAliases = 実名参照しない。
DerefInSearching = 検索の場合は実名参照する。
DerefFindingBaseObj = BaseDNツリー配下に位置した場合は実名参照する。
DerefAlways = 常に実名参照する。
SizeLimit 検索結果に返されるエントリの最大数を指定します。
0 = 無制限
TimeLimit 検索結果のタイムリミットを指定します。
0 = 無制限
TypesOnly 検索結果に属性値を含めるか指定します。
true = 属性値を含めない(属性IDだけが返される)
false = 属性値を含む
Filter 検索条件を指定します。書式についてはLDAPの仕様に準じます。
Attributes 検索結果として返される属性をリストで指定します。
Controls LDAP要求の際の、LDAPコントロールを指定します。(RFC2251 - 4.1.12. Controls)

実行してみる

実行結果は、以下のようになったと思います。
サンプルコードでは、Active DirectoryサーバからobjectCategory属性がcomputer、且つoperatingSystem属性が*Windows*のエントリを検索し、識別子(DN)とcn属性値を取得して出力しています。

>go run ldapsearch.go
Ldap server connected.
Ldap server logged in.
CN=Client1,OU=Computers,DC=MYDOMAIN,DC=local: Client1
CN=Client2,OU=Computers,DC=MYDOMAIN,DC=local: Client2
CN=Client3,OU=Computers,DC=MYDOMAIN,DC=local: Client3
...
(省略)
...
CN=Client20,OU=Computers,DC=MYDOMAIN,DC=local: Client20
Ldap server disconnected.

参考

http://godoc.org/gopkg.in/ldap.v2

nagase
田舎のインフラ屋です。 最近はフルスタック屋です。 アラフィフのオッサンです。 良く使うもの:AWS、GCP、コンテナ、Python、IoT
https://kahomusen-holdings.co.jp
gooday
北部九州を中心に展開するホームセンター「GooDay(グッデイ)」の運営
https://www.gooday.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away