github.com/tommi2day/gomodules@v1.13.2-0.20240423190010-b7d55d252a27/ldaplib/ldap_test.go (about)

     1  package ldaplib
     2  
     3  import (
     4  	"os"
     5  	"testing"
     6  
     7  	"github.com/tommi2day/gomodules/test"
     8  
     9  	"github.com/tommi2day/gomodules/common"
    10  
    11  	ldap "github.com/go-ldap/ldap/v3"
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  )
    15  
    16  const LdapDomain = "example.local"
    17  const LdapBaseDn = "dc=example,dc=local"
    18  const LdapAdminUser = "cn=admin," + LdapBaseDn
    19  const LdapAdminPassword = "admin"
    20  const LdapConfigPassword = "config"
    21  
    22  var ldapPort int
    23  var sslport int
    24  var lc *LdapConfigType
    25  var timeout = 20
    26  
    27  func TestLdapConfig(t *testing.T) {
    28  	t.Run("Ldap Config", func(t *testing.T) {
    29  		lc = NewConfig("ldap.test", 0, true, true, LdapBaseDn, timeout)
    30  		actual := lc
    31  		assert.Equal(t, "ldap.test", actual.Server, "Server not equal")
    32  		assert.Equal(t, 636, actual.Port, "with tls=true ldapPort should be 636")
    33  		assert.Equal(t, "ldaps://ldap.test:636", actual.URL, "with tls=true should be ldaps")
    34  	})
    35  }
    36  
    37  func TestBaseLdap(t *testing.T) {
    38  	var l *ldap.Conn
    39  	var err error
    40  	var ldapserver string
    41  	var entries []*ldap.Entry
    42  	var entry *ldap.Entry
    43  	if os.Getenv("SKIP_LDAP") != "" {
    44  		t.Skip("Skipping LDAP testing in CI environment")
    45  	}
    46  	test.Testinit(t)
    47  	ldapContainer, err = prepareLdapContainer()
    48  	require.NoErrorf(t, err, "Ldap Server not available")
    49  	require.NotNil(t, ldapContainer, "Prepare failed")
    50  	defer common.DestroyDockerContainer(ldapContainer)
    51  
    52  	ldapserver, ldapPort = common.GetContainerHostAndPort(ldapContainer, "1389/tcp")
    53  	base := LdapBaseDn
    54  
    55  	lc = NewConfig(ldapserver, ldapPort, false, false, LdapBaseDn, timeout)
    56  	t.Run("Anonymous Connect", func(t *testing.T) {
    57  		t.Logf("Connect anonymous plain on ldapPort %d", ldapPort)
    58  		err = lc.Connect("", "")
    59  		l = lc.Conn
    60  		require.NoErrorf(t, err, "anonymous Connect returned error: %v", err)
    61  		assert.NotNilf(t, l, "Ldap Connect is nil")
    62  		assert.IsType(t, &ldap.Conn{}, l, "returned object ist not ldap connection")
    63  		_ = l.Close()
    64  	})
    65  	// test container should not be validaed
    66  	ldapserver, sslport = common.GetContainerHostAndPort(ldapContainer, "1636/tcp")
    67  	lc = NewConfig(ldapserver, sslport, true, true, LdapBaseDn, timeout)
    68  	t.Run("Admin SSL Connect", func(t *testing.T) {
    69  		t.Logf("Connect Admin '%s' using SSL on ldapPort %d", LdapAdminUser, sslport)
    70  		err = lc.Connect(LdapAdminUser, LdapAdminPassword)
    71  		l = lc.Conn
    72  		require.NoErrorf(t, err, "admin Connect returned error %v", err)
    73  		assert.NotNilf(t, l, "Ldap Connect is nil")
    74  		assert.IsType(t, &ldap.Conn{}, l, "returned object ist not ldap connection")
    75  	})
    76  	t.Run("BaseDN Search", func(t *testing.T) {
    77  		entry, err = lc.RetrieveEntry(base, "", "DN")
    78  		require.NoErrorf(t, err, "Search returned error:%v", err)
    79  		require.NotNil(t, entry, "Should return vald entry")
    80  		if entry != nil {
    81  			dn := entry.DN
    82  			t.Logf("Base DN: %s", dn)
    83  			assert.Equal(t, base, dn, "DN not equal to base")
    84  		}
    85  	})
    86  	userDN := "cn=testuser," + LdapBaseDn
    87  	userPass := "testPass"
    88  
    89  	t.Run("Add Entry", func(t *testing.T) {
    90  		var attributes []ldap.Attribute
    91  		attributes = append(attributes, ldap.Attribute{Type: "objectClass", Vals: []string{"top", "iNetOrgPerson"}})
    92  		attributes = append(attributes, ldap.Attribute{Type: "cn", Vals: []string{"testuser"}})
    93  		attributes = append(attributes, ldap.Attribute{Type: "sn", Vals: []string{"User"}})
    94  		attributes = append(attributes, ldap.Attribute{Type: "gn", Vals: []string{"Test"}})
    95  		attributes = append(attributes, ldap.Attribute{Type: "mail", Vals: []string{"testuser@" + LdapDomain}})
    96  
    97  		err = lc.AddEntry(userDN, attributes)
    98  		assert.NoErrorf(t, err, "Add User failed")
    99  		_, err = lc.SetPassword(userDN, "", userPass)
   100  		require.NoErrorf(t, err, "Test Bind fix Pass returned error %v", err)
   101  	})
   102  	t.Run("Test HasObjectclass", func(t *testing.T) {
   103  		entry, err = lc.RetrieveEntry(userDN, "", "DN,objectclass")
   104  		require.NoErrorf(t, err, "search for %s returned error %v", userDN, err)
   105  		hasClass := HasObjectClass(entry, "iNetOrgPerson")
   106  		assert.Truef(t, hasClass, "Objectclass iNetOrgPerson should exists")
   107  		hasClass = HasObjectClass(entry, "ldapPublicKey")
   108  		assert.False(t, hasClass, "Objectclass ldapPublicKey should not exists")
   109  	})
   110  	t.Run("Test HasAttribute", func(t *testing.T) {
   111  		entry, err = lc.RetrieveEntry(userDN, "", "*")
   112  		require.NoErrorf(t, err, "search for %s returned error %v", userDN, err)
   113  		hasAttr := HasAttribute(entry, "mail")
   114  		assert.Truef(t, hasAttr, "Attribute mail should exists")
   115  		hasAttr = HasAttribute(entry, "sshPublicKey")
   116  		assert.False(t, hasAttr, "Attribute sshPublic should not exists")
   117  	})
   118  	t.Run("Modify Attribute", func(t *testing.T) {
   119  		newMail := "testmail@test.com"
   120  		err = lc.ModifyAttribute(userDN, "modify", "mail", []string{newMail})
   121  		require.NoErrorf(t, err, "Entry  mail was not modified and returned error %v", err)
   122  		// test change
   123  		entries, err = lc.Search(userDN, "(objectclass=*)", []string{"DN", "mail"}, ldap.ScopeBaseObject, ldap.DerefInSearching)
   124  		require.NoErrorf(t, err, "search for %s returned error %v", userDN, err)
   125  		require.Equalf(t, 1, len(entries), "Should return only one entry")
   126  		actMail := entries[0].GetAttributeValue("mail")
   127  		assert.Equal(t, newMail, actMail, "Mail Modify not visible")
   128  	})
   129  	t.Run("Delete Attribute", func(t *testing.T) {
   130  		err = lc.ModifyAttribute(userDN, "delete", "gn", nil)
   131  		// test change
   132  		entries, err = lc.Search(userDN, "(objectclass=*)", []string{"DN", "gn"}, ldap.ScopeBaseObject, ldap.DerefInSearching)
   133  		require.NoErrorf(t, err, "search for %s returned error %v", userDN, err)
   134  		require.Equalf(t, 1, len(entries), "Should return only one entry")
   135  		actAttr := entries[0].GetAttributeValue("gn")
   136  		assert.Emptyf(t, actAttr, "Attribute gn should not exists")
   137  	})
   138  	t.Run("Change User Password", func(t *testing.T) {
   139  		var genPass string
   140  		// connect to testuser with new pass
   141  		err = lc.Connect(userDN, userPass)
   142  		require.NoErrorf(t, err, "Test Bind with new password returned error %v", err)
   143  		genPass, err = lc.SetPassword("", userPass, "")
   144  		require.NoErrorf(t, err, "Generate Password returned Error: %v", err)
   145  		assert.NotEmptyf(t, genPass, "no password was generated")
   146  		t.Logf("generated Password: %s", genPass)
   147  		_ = l.Close()
   148  
   149  		// reconnect with new password
   150  		err = lc.Connect(userDN, genPass)
   151  		l = lc.Conn
   152  		assert.NoErrorf(t, err, "Test Bind with generated password returned error %v", err)
   153  		if l != nil {
   154  			_ = l.Close()
   155  		}
   156  	})
   157  
   158  	t.Run("Delete Entry", func(t *testing.T) {
   159  		err = lc.Connect(LdapAdminUser, LdapAdminPassword)
   160  		l = lc.Conn
   161  		require.NoErrorf(t, err, "admin Connect returned error %v", err)
   162  		assert.NotNilf(t, l, "Ldap Connect is nil")
   163  		err = lc.DeleteEntry(userDN)
   164  		assert.NoErrorf(t, err, "Deleting failed")
   165  
   166  		// check if we can find the dropped DN
   167  		entries, err = lc.Search(userDN, "(objectclass=*)", []string{"DN"}, ldap.ScopeBaseObject, ldap.DerefInSearching)
   168  		assert.NoErrorf(t, err, "Should not return any error as no data error was removed")
   169  		assert.Equalf(t, 0, len(entries), "Should return no one entry")
   170  	})
   171  }