...

Source file src/github.com/go-ldap/ldap/v3/examples_test.go

Documentation: github.com/go-ldap/ldap/v3

     1  package ldap
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"crypto/x509"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"log"
    10  	"time"
    11  )
    12  
    13  // This example demonstrates how to bind a connection to an ldap user
    14  // allowing access to restricted attributes that user has access to
    15  func ExampleConn_Bind() {
    16  	l, err := DialURL("ldap://ldap.example.com:389")
    17  	if err != nil {
    18  		log.Fatal(err)
    19  	}
    20  	defer l.Close()
    21  
    22  	err = l.Bind("cn=read-only-admin,dc=example,dc=com", "password")
    23  	if err != nil {
    24  		log.Fatal(err)
    25  	}
    26  }
    27  
    28  // This example demonstrates how to use the search interface
    29  func ExampleConn_Search() {
    30  	l, err := DialURL("ldap://ldap.example.com:389")
    31  	if err != nil {
    32  		log.Fatal(err)
    33  	}
    34  	defer l.Close()
    35  
    36  	searchRequest := NewSearchRequest(
    37  		"dc=example,dc=com", // The base dn to search
    38  		ScopeWholeSubtree, NeverDerefAliases, 0, 0, false,
    39  		"(&(objectClass=organizationalPerson))", // The filter to apply
    40  		[]string{"dn", "cn"},                    // A list attributes to retrieve
    41  		nil,
    42  	)
    43  
    44  	sr, err := l.Search(searchRequest)
    45  	if err != nil {
    46  		log.Fatal(err)
    47  	}
    48  
    49  	for _, entry := range sr.Entries {
    50  		fmt.Printf("%s: %v\n", entry.DN, entry.GetAttributeValue("cn"))
    51  	}
    52  }
    53  
    54  // This example demonstrates how to search asynchronously
    55  func ExampleConn_SearchAsync() {
    56  	l, err := DialURL(fmt.Sprintf("%s:%d", "ldap.example.com", 389))
    57  	if err != nil {
    58  		log.Fatal(err)
    59  	}
    60  	defer l.Close()
    61  
    62  	searchRequest := NewSearchRequest(
    63  		"dc=example,dc=com", // The base dn to search
    64  		ScopeWholeSubtree, NeverDerefAliases, 0, 0, false,
    65  		"(&(objectClass=organizationalPerson))", // The filter to apply
    66  		[]string{"dn", "cn"},                    // A list attributes to retrieve
    67  		nil,
    68  	)
    69  
    70  	ctx, cancel := context.WithCancel(context.Background())
    71  	defer cancel()
    72  
    73  	r := l.SearchAsync(ctx, searchRequest, 64)
    74  	for r.Next() {
    75  		entry := r.Entry()
    76  		fmt.Printf("%s has DN %s\n", entry.GetAttributeValue("cn"), entry.DN)
    77  	}
    78  	if err := r.Err(); err != nil {
    79  		log.Fatal(err)
    80  	}
    81  }
    82  
    83  // This example demonstrates how to do syncrepl (persistent search)
    84  func ExampleConn_Syncrepl() {
    85  	l, err := DialURL(fmt.Sprintf("%s:%d", "ldap.example.com", 389))
    86  	if err != nil {
    87  		log.Fatal(err)
    88  	}
    89  	defer l.Close()
    90  
    91  	searchRequest := NewSearchRequest(
    92  		"dc=example,dc=com", // The base dn to search
    93  		ScopeWholeSubtree, NeverDerefAliases, 0, 0, false,
    94  		"(&(objectClass=organizationalPerson))", // The filter to apply
    95  		[]string{"dn", "cn"},                    // A list attributes to retrieve
    96  		nil,
    97  	)
    98  
    99  	ctx, cancel := context.WithCancel(context.Background())
   100  	defer cancel()
   101  
   102  	mode := SyncRequestModeRefreshAndPersist
   103  	var cookie []byte = nil
   104  	r := l.Syncrepl(ctx, searchRequest, 64, mode, cookie, false)
   105  	for r.Next() {
   106  		entry := r.Entry()
   107  		if entry != nil {
   108  			fmt.Printf("%s has DN %s\n", entry.GetAttributeValue("cn"), entry.DN)
   109  		}
   110  		controls := r.Controls()
   111  		if len(controls) != 0 {
   112  			fmt.Printf("%s", controls)
   113  		}
   114  	}
   115  	if err := r.Err(); err != nil {
   116  		log.Fatal(err)
   117  	}
   118  }
   119  
   120  // This example demonstrates how to start a TLS connection
   121  func ExampleConn_StartTLS() {
   122  	l, err := DialURL("ldap://ldap.example.com:389")
   123  	if err != nil {
   124  		log.Fatal(err)
   125  	}
   126  	defer l.Close()
   127  
   128  	// Reconnect with TLS
   129  	err = l.StartTLS(&tls.Config{InsecureSkipVerify: true})
   130  	if err != nil {
   131  		log.Fatal(err)
   132  	}
   133  
   134  	// Operations via l are now encrypted
   135  }
   136  
   137  // This example demonstrates how to compare an attribute with a value
   138  func ExampleConn_Compare() {
   139  	l, err := DialURL("ldap://ldap.example.com:389")
   140  	if err != nil {
   141  		log.Fatal(err)
   142  	}
   143  	defer l.Close()
   144  
   145  	matched, err := l.Compare("cn=user,dc=example,dc=com", "uid", "someuserid")
   146  	if err != nil {
   147  		log.Fatal(err)
   148  	}
   149  
   150  	fmt.Println(matched)
   151  }
   152  
   153  func ExampleConn_PasswordModify_admin() {
   154  	l, err := DialURL("ldap://ldap.example.com:389")
   155  	if err != nil {
   156  		log.Fatal(err)
   157  	}
   158  	defer l.Close()
   159  
   160  	err = l.Bind("cn=admin,dc=example,dc=com", "password")
   161  	if err != nil {
   162  		log.Fatal(err)
   163  	}
   164  
   165  	passwordModifyRequest := NewPasswordModifyRequest("cn=user,dc=example,dc=com", "", "NewPassword")
   166  	_, err = l.PasswordModify(passwordModifyRequest)
   167  
   168  	if err != nil {
   169  		log.Fatalf("Password could not be changed: %s", err.Error())
   170  	}
   171  }
   172  
   173  func ExampleConn_PasswordModify_generatedPassword() {
   174  	l, err := DialURL("ldap://ldap.example.com:389")
   175  	if err != nil {
   176  		log.Fatal(err)
   177  	}
   178  	defer l.Close()
   179  
   180  	err = l.Bind("cn=user,dc=example,dc=com", "password")
   181  	if err != nil {
   182  		log.Fatal(err)
   183  	}
   184  
   185  	passwordModifyRequest := NewPasswordModifyRequest("", "OldPassword", "")
   186  	passwordModifyResponse, err := l.PasswordModify(passwordModifyRequest)
   187  	if err != nil {
   188  		log.Fatalf("Password could not be changed: %s", err.Error())
   189  	}
   190  
   191  	generatedPassword := passwordModifyResponse.GeneratedPassword
   192  	log.Printf("Generated password: %s\n", generatedPassword)
   193  }
   194  
   195  func ExampleConn_PasswordModify_setNewPassword() {
   196  	l, err := DialURL("ldap://ldap.example.com:389")
   197  	if err != nil {
   198  		log.Fatal(err)
   199  	}
   200  	defer l.Close()
   201  
   202  	err = l.Bind("cn=user,dc=example,dc=com", "password")
   203  	if err != nil {
   204  		log.Fatal(err)
   205  	}
   206  
   207  	passwordModifyRequest := NewPasswordModifyRequest("", "OldPassword", "NewPassword")
   208  	_, err = l.PasswordModify(passwordModifyRequest)
   209  
   210  	if err != nil {
   211  		log.Fatalf("Password could not be changed: %s", err.Error())
   212  	}
   213  }
   214  
   215  func ExampleConn_Modify() {
   216  	l, err := DialURL("ldap://ldap.example.com:389")
   217  	if err != nil {
   218  		log.Fatal(err)
   219  	}
   220  	defer l.Close()
   221  
   222  	// Add a description, and replace the mail attributes
   223  	modify := NewModifyRequest("cn=user,dc=example,dc=com", nil)
   224  	modify.Add("description", []string{"An example user"})
   225  	modify.Replace("mail", []string{"user@example.org"})
   226  
   227  	err = l.Modify(modify)
   228  	if err != nil {
   229  		log.Fatal(err)
   230  	}
   231  }
   232  
   233  // Example_userAuthentication shows how a typical application can verify a login attempt
   234  // Refer to https://github.com/go-ldap/ldap/issues/93 for issues revolving around unauthenticated binds, with zero length passwords
   235  func Example_userAuthentication() {
   236  	// The username and password we want to check
   237  	username := "someuser"
   238  	password := "userpassword"
   239  
   240  	bindusername := "readonly"
   241  	bindpassword := "password"
   242  
   243  	l, err := DialURL("ldap://ldap.example.com:389")
   244  	if err != nil {
   245  		log.Fatal(err)
   246  	}
   247  	defer l.Close()
   248  
   249  	// Reconnect with TLS
   250  	err = l.StartTLS(&tls.Config{InsecureSkipVerify: true})
   251  	if err != nil {
   252  		log.Fatal(err)
   253  	}
   254  
   255  	// First bind with a read only user
   256  	err = l.Bind(bindusername, bindpassword)
   257  	if err != nil {
   258  		log.Fatal(err)
   259  	}
   260  
   261  	// Search for the given username
   262  	searchRequest := NewSearchRequest(
   263  		"dc=example,dc=com",
   264  		ScopeWholeSubtree, NeverDerefAliases, 0, 0, false,
   265  		fmt.Sprintf("(&(objectClass=organizationalPerson)(uid=%s))", EscapeFilter(username)),
   266  		[]string{"dn"},
   267  		nil,
   268  	)
   269  
   270  	sr, err := l.Search(searchRequest)
   271  	if err != nil {
   272  		log.Fatal(err)
   273  	}
   274  
   275  	if len(sr.Entries) != 1 {
   276  		log.Fatal("User does not exist or too many entries returned")
   277  	}
   278  
   279  	userdn := sr.Entries[0].DN
   280  
   281  	// Bind as the user to verify their password
   282  	err = l.Bind(userdn, password)
   283  	if err != nil {
   284  		log.Fatal(err)
   285  	}
   286  
   287  	// Rebind as the read only user for any further queries
   288  	err = l.Bind(bindusername, bindpassword)
   289  	if err != nil {
   290  		log.Fatal(err)
   291  	}
   292  }
   293  
   294  func Example_beherappolicy() {
   295  	l, err := DialURL("ldap://ldap.example.com:389")
   296  	if err != nil {
   297  		log.Fatal(err)
   298  	}
   299  	defer l.Close()
   300  
   301  	controls := []Control{}
   302  	controls = append(controls, NewControlBeheraPasswordPolicy())
   303  	bindRequest := NewSimpleBindRequest("cn=admin,dc=example,dc=com", "password", controls)
   304  
   305  	r, err := l.SimpleBind(bindRequest)
   306  	ppolicyControl := FindControl(r.Controls, ControlTypeBeheraPasswordPolicy)
   307  
   308  	var ppolicy *ControlBeheraPasswordPolicy
   309  	if ppolicyControl != nil {
   310  		ppolicy = ppolicyControl.(*ControlBeheraPasswordPolicy)
   311  	} else {
   312  		log.Printf("ppolicyControl response not available.\n")
   313  	}
   314  	if err != nil {
   315  		errStr := "ERROR: Cannot bind: " + err.Error()
   316  		if ppolicy != nil && ppolicy.Error >= 0 {
   317  			errStr += ":" + ppolicy.ErrorString
   318  		}
   319  		log.Print(errStr)
   320  	} else {
   321  		logStr := "Login Ok"
   322  		if ppolicy != nil {
   323  			if ppolicy.Expire >= 0 {
   324  				logStr += fmt.Sprintf(". Password expires in %d seconds\n", ppolicy.Expire)
   325  			} else if ppolicy.Grace >= 0 {
   326  				logStr += fmt.Sprintf(". Password expired, %d grace logins remain\n", ppolicy.Grace)
   327  			}
   328  		}
   329  		log.Print(logStr)
   330  	}
   331  }
   332  
   333  func Example_vchuppolicy() {
   334  	l, err := DialURL("ldap://ldap.example.com:389")
   335  	if err != nil {
   336  		log.Fatal(err)
   337  	}
   338  	defer l.Close()
   339  	l.Debug = true
   340  
   341  	bindRequest := NewSimpleBindRequest("cn=admin,dc=example,dc=com", "password", nil)
   342  
   343  	r, err := l.SimpleBind(bindRequest)
   344  
   345  	passwordMustChangeControl := FindControl(r.Controls, ControlTypeVChuPasswordMustChange)
   346  	var passwordMustChange *ControlVChuPasswordMustChange
   347  	if passwordMustChangeControl != nil {
   348  		passwordMustChange = passwordMustChangeControl.(*ControlVChuPasswordMustChange)
   349  	}
   350  
   351  	if passwordMustChange != nil && passwordMustChange.MustChange {
   352  		log.Printf("Password Must be changed.\n")
   353  	}
   354  
   355  	passwordWarningControl := FindControl(r.Controls, ControlTypeVChuPasswordWarning)
   356  
   357  	var passwordWarning *ControlVChuPasswordWarning
   358  	if passwordWarningControl != nil {
   359  		passwordWarning = passwordWarningControl.(*ControlVChuPasswordWarning)
   360  	} else {
   361  		log.Printf("ppolicyControl response not available.\n")
   362  	}
   363  	if err != nil {
   364  		log.Print("ERROR: Cannot bind: " + err.Error())
   365  	} else {
   366  		logStr := "Login Ok"
   367  		if passwordWarning != nil {
   368  			if passwordWarning.Expire >= 0 {
   369  				logStr += fmt.Sprintf(". Password expires in %d seconds\n", passwordWarning.Expire)
   370  			}
   371  		}
   372  		log.Print(logStr)
   373  	}
   374  }
   375  
   376  // This example demonstrates how to use ControlPaging to manually execute a
   377  // paginated search request instead of using SearchWithPaging.
   378  func ExampleControlPaging_manualPaging() {
   379  	conn, err := DialURL("ldap://ldap.example.com:389")
   380  	if err != nil {
   381  		log.Fatal(err)
   382  	}
   383  	defer conn.Close()
   384  
   385  	var pageSize uint32 = 32
   386  	searchBase := "dc=example,dc=com"
   387  	filter := "(objectClass=group)"
   388  	pagingControl := NewControlPaging(pageSize)
   389  	attributes := []string{}
   390  	controls := []Control{pagingControl}
   391  
   392  	for {
   393  		request := NewSearchRequest(searchBase, ScopeWholeSubtree, DerefAlways, 0, 0, false, filter, attributes, controls)
   394  		response, err := conn.Search(request)
   395  		if err != nil {
   396  			log.Fatalf("Failed to execute search request: %s", err.Error())
   397  		}
   398  
   399  		// [do something with the response entries]
   400  
   401  		// In order to prepare the next request, we check if the response
   402  		// contains another ControlPaging object and a not-empty cookie and
   403  		// copy that cookie into our pagingControl object:
   404  		updatedControl := FindControl(response.Controls, ControlTypePaging)
   405  		if ctrl, ok := updatedControl.(*ControlPaging); ctrl != nil && ok && len(ctrl.Cookie) != 0 {
   406  			pagingControl.SetCookie(ctrl.Cookie)
   407  			continue
   408  		}
   409  		// If no new paging information is available or the cookie is empty, we
   410  		// are done with the pagination.
   411  		break
   412  	}
   413  }
   414  
   415  // This example demonstrates how to use DirSync to manually execute a
   416  // DirSync search request
   417  func ExampleConn_DirSync() {
   418  	conn, err := Dial("tcp", "ad.example.org:389")
   419  	if err != nil {
   420  		log.Fatalf("Failed to connect: %s\n", err)
   421  	}
   422  	defer conn.Close()
   423  
   424  	_, err = conn.SimpleBind(&SimpleBindRequest{
   425  		Username: "cn=Some User,ou=people,dc=example,dc=org",
   426  		Password: "MySecretPass",
   427  	})
   428  	if err != nil {
   429  		log.Fatalf("failed to bind: %s", err)
   430  	}
   431  
   432  	req := &SearchRequest{
   433  		BaseDN:     `DC=example,DC=org`,
   434  		Filter:     `(&(objectClass=person)(!(objectClass=computer)))`,
   435  		Attributes: []string{"*"},
   436  		Scope:      ScopeWholeSubtree,
   437  	}
   438  	// This is the initial sync with all entries matching the filter
   439  	doMore := true
   440  	var cookie []byte
   441  	for doMore {
   442  		res, err := conn.DirSync(req, DirSyncObjectSecurity, 1000, cookie)
   443  		if err != nil {
   444  			log.Fatalf("failed to search: %s", err)
   445  		}
   446  		for _, entry := range res.Entries {
   447  			entry.Print()
   448  		}
   449  		ctrl := FindControl(res.Controls, ControlTypeDirSync)
   450  		if ctrl == nil || ctrl.(*ControlDirSync).Flags == 0 {
   451  			doMore = false
   452  		}
   453  		cookie = ctrl.(*ControlDirSync).Cookie
   454  	}
   455  	// We're done with the initial sync. Now pull every 15 seconds for the
   456  	// updated entries - note that you get just the changes, not a full entry.
   457  	for {
   458  		res, err := conn.DirSync(req, DirSyncObjectSecurity, 1000, cookie)
   459  		if err != nil {
   460  			log.Fatalf("failed to search: %s", err)
   461  		}
   462  		for _, entry := range res.Entries {
   463  			entry.Print()
   464  		}
   465  		time.Sleep(15 * time.Second)
   466  	}
   467  }
   468  
   469  // This example demonstrates how to use DirSync search asynchronously
   470  func ExampleConn_DirSyncAsync() {
   471  	conn, err := Dial("tcp", "ad.example.org:389")
   472  	if err != nil {
   473  		log.Fatalf("Failed to connect: %s\n", err)
   474  	}
   475  	defer conn.Close()
   476  
   477  	_, err = conn.SimpleBind(&SimpleBindRequest{
   478  		Username: "cn=Some User,ou=people,dc=example,dc=org",
   479  		Password: "MySecretPass",
   480  	})
   481  	if err != nil {
   482  		log.Fatalf("failed to bind: %s", err)
   483  	}
   484  
   485  	req := &SearchRequest{
   486  		BaseDN:     `DC=example,DC=org`,
   487  		Filter:     `(&(objectClass=person)(!(objectClass=computer)))`,
   488  		Attributes: []string{"*"},
   489  		Scope:      ScopeWholeSubtree,
   490  	}
   491  
   492  	ctx, cancel := context.WithCancel(context.Background())
   493  	defer cancel()
   494  
   495  	var cookie []byte = nil
   496  	r := conn.DirSyncAsync(ctx, req, 64, DirSyncObjectSecurity, 1000, cookie)
   497  	for r.Next() {
   498  		entry := r.Entry()
   499  		if entry != nil {
   500  			entry.Print()
   501  		}
   502  		controls := r.Controls()
   503  		if len(controls) != 0 {
   504  			fmt.Printf("%s", controls)
   505  		}
   506  	}
   507  	if err := r.Err(); err != nil {
   508  		log.Fatal(err)
   509  	}
   510  }
   511  
   512  // This example demonstrates how to use EXTERNAL SASL with TLS client certificates.
   513  func ExampleConn_ExternalBind() {
   514  	ldapCert := "/path/to/cert.pem"
   515  	ldapKey := "/path/to/key.pem"
   516  	ldapCAchain := "/path/to/ca_chain.pem"
   517  
   518  	// Load client cert and key
   519  	cert, err := tls.LoadX509KeyPair(ldapCert, ldapKey)
   520  	if err != nil {
   521  		log.Fatal(err)
   522  	}
   523  
   524  	// Load CA chain
   525  	caCert, err := ioutil.ReadFile(ldapCAchain)
   526  	if err != nil {
   527  		log.Fatal(err)
   528  	}
   529  	caCertPool := x509.NewCertPool()
   530  	caCertPool.AppendCertsFromPEM(caCert)
   531  
   532  	// Setup TLS with ldap client cert
   533  	tlsConfig := &tls.Config{
   534  		Certificates:       []tls.Certificate{cert},
   535  		RootCAs:            caCertPool,
   536  		InsecureSkipVerify: true,
   537  	}
   538  
   539  	// connect to ldap server
   540  	l, err := DialURL("ldap://ldap.example.com:389")
   541  	if err != nil {
   542  		log.Fatal(err)
   543  	}
   544  	defer l.Close()
   545  
   546  	// reconnect using tls
   547  	err = l.StartTLS(tlsConfig)
   548  	if err != nil {
   549  		log.Fatal(err)
   550  	}
   551  
   552  	// sasl external bind
   553  	err = l.ExternalBind()
   554  	if err != nil {
   555  		log.Fatal(err)
   556  	}
   557  
   558  	// Conduct ldap queries
   559  }
   560  
   561  // ExampleConn_WhoAmI demonstrates how to run a whoami request according to https://tools.ietf.org/html/rfc4532
   562  func ExampleConn_WhoAmI() {
   563  	conn, err := DialURL("ldap.example.org:389")
   564  	if err != nil {
   565  		log.Fatalf("Failed to connect: %s\n", err)
   566  	}
   567  
   568  	_, err = conn.SimpleBind(&SimpleBindRequest{
   569  		Username: "uid=someone,ou=people,dc=example,dc=org",
   570  		Password: "MySecretPass",
   571  	})
   572  	if err != nil {
   573  		log.Fatalf("Failed to bind: %s\n", err)
   574  	}
   575  
   576  	res, err := conn.WhoAmI(nil)
   577  	if err != nil {
   578  		log.Fatalf("Failed to call WhoAmI(): %s\n", err)
   579  	}
   580  	fmt.Printf("I am: %s\n", res.AuthzID)
   581  }
   582  

View as plain text