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 }