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

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

#LDAPパッケージのインストール
goコマンドでチャッチャとインストールです。

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

#サンプルコード
```go: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で指定された階層のみを検索します。<br/>ScopeSingleLevel  = BaseDNで指定された階層の1つ下の階層を検索します。<br/>ScopeWholeSubtree = BaseDNで指定された階層以下（サブツリー）すべてを検索します。 |
|  DerefAliases | エイリアスエントリの実名参照をどのように行うかを指定します。<br/>NeverDerefAliases   = 実名参照しない。<br/>DerefInSearching    = 検索の場合は実名参照する。<br/>DerefFindingBaseObj = BaseDNツリー配下に位置した場合は実名参照する。<br/>DerefAlways = 常に実名参照する。 |
|  SizeLimit | 検索結果に返されるエントリの最大数を指定します。<br/>0 = 無制限 |
|  TimeLimit | 検索結果のタイムリミットを指定します。<br/>0 = 無制限 |
|  TypesOnly | 検索結果に属性値を含めるか指定します。<br/>true = 属性値を含めない（属性IDだけが返される）<br/>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