github.com/tommi2day/pwcli@v0.0.0-20240317203041-4d1177a5ab91/cmd/ldap_test.go (about) 1 package cmd 2 3 import ( 4 "fmt" 5 "os" 6 "testing" 7 "time" 8 9 "github.com/go-ldap/ldap/v3" 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 "github.com/tommi2day/gomodules/common" 13 "github.com/tommi2day/gomodules/ldaplib" 14 "github.com/tommi2day/pwcli/test" 15 ) 16 17 const LdapBaseDn = "dc=example,dc=local" 18 const LdapAdminUser = "cn=admin," + LdapBaseDn 19 const LdapAdminPassword = "admin" 20 const LdapConfigPassword = "config" 21 const LdapTestUserDN = "cn=test,ou=Users," + LdapBaseDn 22 const LdapTestUserPassword = "test" 23 const LdapTestUser2DN = "cn=test2,ou=Users," + LdapBaseDn 24 const LdapTestUser2Password = "test2" 25 const LdapNewPassword = "newpassword" 26 27 var sshkey = `ssh-rsa AAAAB3NzaC1yc2EAABBDAQABAFFBAQDX9uIBEySOR6tASa4RIgUo6TTOi+o3hIWkxJGlfajHQY9f73LONotAPKgDfEdvrvY+0 28 pW3zXe3pmr4GhQzP2c1EMYmwVdkkQLtn/FHFICLHCyihN2byMe14v4iv1em6XXLqVB7cbxi2XKHHfa50tqgeEJTIRVbFVht9WCdHQ9VUvwnCUda6wDt3E1q+ 29 tAaUOldrfFl3KR4LQThOUOEOtaG1eU2Q/fk1j5qLMH2sDtzYnTp2MgLVAElC7XH9QDWz4+I3uxeYOweUhvBnBx+Ti2ZkzZjchRbkawa4v/woySmWove7nzp 30 BPYWJ8mBdRecVfcY+/jZDSe2Phgfzgf3cRTvs3tF test@ldap` 31 var sshkey2 = `ssh-rsa AAAAB3NzaC1yc2EAABBDAQABAFFBAQDX9uIBEySOR6tASa4RIgUo6TTOi+o3hIWkxJGlfajHQY9f73LONotAPKgDfEdvrvY+0 32 pW3zXe3pmr4GhQzP2c1EMYmwVdkkQLtn/FHFICLHCyihN2byMe14v4iv1em6XXLqVB7cbxi2XKHHfa50tqgeEJTIRVbFVht9WCdHQ9VUvwnCUda6wDt3E1q+ 33 tAaUOldrfFl3KR4LQThOUOEOtaG1eU2Q/fk1j5qLMH2sDtzYnTp2MgLVAElC7XH9QDWz4+I3uxeYOweUhvBnBx+Ti2ZkzZjchRbkawa4v/woySmWove7nzp 34 BPYWJ8mBdRecVfcY+/jZDSe2Phgfzgf3cRTvs3tF test2@ldap` 35 var lc *ldaplib.LdapConfigType 36 37 func TestLdap(t *testing.T) { 38 var err error 39 var server string 40 var sslport int 41 var out string 42 43 test.Testinit(t) 44 err = os.Chdir(test.TestDir) 45 require.NoErrorf(t, err, "ChDir failed") 46 ldapAdmin := test.TestData 47 sshkeyfile := ldapAdmin + "/id_rsa.pub" 48 sshkeyfile2 := ldapAdmin + "/id_rsa2.pub" 49 //nolint gosec 50 err = os.WriteFile(sshkeyfile, []byte(sshkey), 0644) 51 require.NoErrorf(t, err, "Create test id_rsa.pub failed") 52 //nolint gosec 53 err = os.WriteFile(sshkeyfile2, []byte(sshkey2), 0644) 54 require.NoErrorf(t, err, "Create test id_rsa2.pub failed") 55 56 // redirect Stdin for test 57 r, w, err := os.Pipe() 58 require.NoErrorf(t, err, "Pipe failed") 59 inputReader = r 60 61 // prepare or skip container based tests 62 if os.Getenv("SKIP_LDAP") != "" { 63 t.Skip("Skipping LDAP testing in CI environment") 64 } 65 ldapContainer, err = prepareLdapContainer() 66 require.NoErrorf(t, err, "Ldap Server not available") 67 require.NotNil(t, ldapContainer, "Prepare failed") 68 defer common.DestroyDockerContainer(ldapContainer) 69 server, sslport = common.GetContainerHostAndPort(ldapContainer, "1636/tcp") 70 71 base := LdapBaseDn 72 lc = ldaplib.NewConfig(server, sslport, true, true, base, ldapTimeout) 73 74 t.Run("Ldap Connect", func(t *testing.T) { 75 t.Logf("Connect '%s' using SSL on port %d", LdapTestUserDN, sslport) 76 err = lc.Connect(LdapTestUserDN, LdapTestUserPassword) 77 require.NoErrorf(t, err, "admin Connect returned error %v", err) 78 assert.NotNilf(t, lc.Conn, "Ldap Connect is nil") 79 assert.IsType(t, &ldap.Conn{}, lc.Conn, "returned object ist not ldap connection") 80 if lc.Conn == nil { 81 t.Fatalf("No valid Connection, terminate") 82 return 83 } 84 }) 85 t.Run("change NonAdmin ssh key", func(t *testing.T) { 86 args := []string{ 87 "ldap", 88 "change-sshpubkey", 89 "--ldap.host", server, 90 "--ldap.port", fmt.Sprintf("%d", sslport), 91 "--ldap.tls", "true", 92 "--ldap.insecure", "true", 93 "--ldap.base", LdapBaseDn, 94 "--ldap.binddn", LdapTestUserDN, 95 "--ldap.bindpassword", LdapTestUserPassword, 96 "--sshpubkeyfile", sshkeyfile, 97 "--info", 98 "--unit-test", 99 } 100 out, err = common.CmdRun(RootCmd, args) 101 require.NoErrorf(t, err, "Command returned error: %s", err) 102 t.Logf(out) 103 assert.Containsf(t, out, "SUCCESS: ", "Output not as expected") 104 _ = ldapPassCmd.Flags().Set("new_password", "") 105 }) 106 t.Run("set SSH Key by Admin", func(t *testing.T) { 107 args := []string{ 108 "ldap", 109 "change-sshpubkey", 110 "--ldap.host", server, 111 "--ldap.port", fmt.Sprintf("%d", sslport), 112 "--ldap.tls", "true", 113 "--ldap.insecure", "true", 114 "--ldap.base", LdapBaseDn, 115 "--ldap.binddn", LdapAdminUser, 116 "--ldap.bindpassword", LdapAdminPassword, 117 "--ldap.targetdn", LdapTestUserDN, 118 "--sshpubkeyfile", sshkeyfile, 119 "--info", 120 "--unit-test", 121 } 122 out, err = common.CmdRun(RootCmd, args) 123 require.NoErrorf(t, err, "Command returned error: %s", err) 124 t.Logf(out) 125 assert.Containsf(t, out, "SUCCESS: ", "Output not as expected") 126 _ = ldapSSHCmd.Flags().Set("ldap.targetdn", "") 127 }) 128 t.Run("set SSH Key without class", func(t *testing.T) { 129 args := []string{ 130 "ldap", 131 "change-sshpubkey", 132 "--ldap.host", server, 133 "--ldap.port", fmt.Sprintf("%d", sslport), 134 "--ldap.tls", "true", 135 "--ldap.insecure", "true", 136 "--ldap.base", LdapBaseDn, 137 "--ldap.binddn", LdapTestUser2DN, 138 "--ldap.bindpassword", LdapTestUser2Password, 139 "--sshpubkeyfile", sshkeyfile, 140 "--info", 141 "--unit-test", 142 } 143 out, err = common.CmdRun(RootCmd, args) 144 require.Errorf(t, err, "Command should return error") 145 t.Logf(out) 146 assert.Containsf(t, out, "objectclass ldapPublicKey not found", "Output not as expected") 147 _ = ldapPassCmd.Flags().Set("ldap.targetdn", "") 148 }) 149 t.Run("change NonAdmin Ldap password", func(t *testing.T) { 150 args := []string{ 151 "ldap", 152 "change-password", 153 "--ldap.host", server, 154 "--ldap.port", fmt.Sprintf("%d", sslport), 155 "--ldap.tls", "true", 156 "--ldap.insecure", "true", 157 "--ldap.base", LdapBaseDn, 158 "--ldap.binddn", LdapTestUserDN, 159 "--ldap.bindpassword", LdapTestUserPassword, 160 "--new-password", LdapNewPassword, 161 "--ldap.targetdn", "", 162 "--info", 163 "--unit-test", 164 } 165 out, err = common.CmdRun(RootCmd, args) 166 require.NoErrorf(t, err, "Command returned error: %s", err) 167 t.Logf(out) 168 assert.Containsf(t, out, "SUCCESS: ", "Output not as expected") 169 _ = ldapPassCmd.Flags().Set("new-password", "") 170 _ = ldapPassCmd.Flags().Set("ldap.targetdn", "") 171 }) 172 t.Run("change Ldap password by Admin", func(t *testing.T) { 173 args := []string{ 174 "ldap", 175 "change-password", 176 "--ldap.host", server, 177 "--ldap.port", fmt.Sprintf("%d", sslport), 178 "--ldap.tls", "true", 179 "--ldap.insecure", "true", 180 "--ldap.base", LdapBaseDn, 181 "--ldap.binddn", LdapAdminUser, 182 "--ldap.bindpassword", LdapAdminPassword, 183 "--ldap.targetdn", LdapTestUser2DN, 184 "--new-password", LdapNewPassword, 185 "--info", 186 "--unit-test", 187 } 188 out, err = common.CmdRun(RootCmd, args) 189 require.NoErrorf(t, err, "Command returned error: %s", err) 190 t.Logf(out) 191 assert.Containsf(t, out, "SUCCESS: ", "Output not as expected") 192 _ = ldapPassCmd.Flags().Set("new-password", "") 193 _ = ldapPassCmd.Flags().Set("ldap.targetdn", "") 194 }) 195 t.Run("change Ldap password by Admin with prompt", func(t *testing.T) { 196 args := []string{ 197 "ldap", 198 "change-password", 199 "--ldap.host", server, 200 "--ldap.port", fmt.Sprintf("%d", sslport), 201 "--ldap.tls", "true", 202 "--ldap.insecure", "true", 203 "--ldap.base", LdapBaseDn, 204 "--ldap.binddn", LdapAdminUser, 205 "--ldap.bindpassword", LdapAdminPassword, 206 "--ldap.targetdn", LdapTestUser2DN, 207 // "--new-password", LdapNewPassword, 208 "--info", 209 "--unit-test", 210 } 211 _, _ = w.WriteString(fmt.Sprintf("%s\n", LdapNewPassword+"1")) 212 time.Sleep(1 * time.Second) 213 _, _ = w.WriteString(fmt.Sprintf("%s\n", LdapNewPassword+"1")) 214 out, err = common.CmdRun(RootCmd, args) 215 require.NoErrorf(t, err, "Command returned error: %s", err) 216 t.Logf(out) 217 assert.Containsf(t, out, "SUCCESS: ", "Output not as expected") 218 _ = ldapPassCmd.Flags().Set("new-password", "") 219 _ = ldapPassCmd.Flags().Set("ldap.targetdn", "") 220 }) 221 t.Run("change and generate password", func(t *testing.T) { 222 np := ldapPassCmd.Flags().Lookup("new-password") 223 np.Changed = false 224 args := []string{ 225 "ldap", 226 "change-password", 227 "--ldap.host", server, 228 "--ldap.port", fmt.Sprintf("%d", sslport), 229 "--ldap.tls", "true", 230 "--ldap.insecure", "true", 231 "--ldap.base", LdapBaseDn, 232 "--ldap.binddn", LdapAdminUser, 233 "--ldap.bindpassword", LdapAdminPassword, 234 "--ldap.targetdn", LdapTestUser2DN, 235 "--generate", 236 "--profile", "6 1 1 1 0 0", 237 "--info", 238 "--unit-test", 239 } 240 out, err = common.CmdRun(RootCmd, args) 241 require.NoErrorf(t, err, "Command returned error: %s", err) 242 t.Logf(out) 243 assert.Containsf(t, out, "SUCCESS: ", "Output not as expected") 244 assert.Containsf(t, out, "generated Password: ", "Output not as expected") 245 _ = ldapPassCmd.Flags().Set("ldap.targetdn", "") 246 targetDN = "" 247 }) 248 t.Run("Show Attributes without basedn", func(t *testing.T) { 249 ldapBaseDN = "" 250 args := []string{ 251 "ldap", 252 "show", 253 "--ldap.host", server, 254 "--ldap.port", fmt.Sprintf("%d", sslport), 255 "--ldap.tls", "true", 256 "--ldap.insecure", "true", 257 "--ldap.binddn", LdapAdminUser, 258 "--ldap.bindpassword", LdapAdminPassword, 259 "--ldap.targetuser", "test2", 260 "--info", 261 "--unit-test", 262 } 263 out, err = common.CmdRun(RootCmd, args) 264 require.NoErrorf(t, err, "Command returned error: %s", err) 265 t.Logf(out) 266 assert.Containsf(t, out, "sn: test2", "Output not as expected") 267 }) 268 t.Run("Show groups without bind pass", func(t *testing.T) { 269 ldapBaseDN = "" 270 ldapBindPassword = "" 271 args := []string{ 272 "ldap", 273 "groups", 274 "--ldap.host", server, 275 "--ldap.port", fmt.Sprintf("%d", sslport), 276 "--ldap.tls", "true", 277 "--ldap.insecure", "true", 278 "--ldap.binddn", LdapAdminUser, 279 // "--ldap.bindpassword", LdapAdminPassword, 280 "--ldap.targetuser", "test2", 281 "--info", 282 "--unit-test", 283 } 284 285 // write to Stdin 286 _, _ = w.WriteString(fmt.Sprintf("%s\n", LdapAdminPassword)) 287 out, err = common.CmdRun(RootCmd, args) 288 require.NoErrorf(t, err, "Command returned error: %s", err) 289 t.Logf(out) 290 assert.Containsf(t, out, "Group: cn=ssh,ou=Groups,dc=example,dc=local", "Output not as expected") 291 }) 292 _ = w.Close() 293 } 294 295 func TestPromptPassword(t *testing.T) { 296 // redirect Stdin 297 oldStdin := os.Stdin 298 re, wr, _ := os.Pipe() 299 inputReader = re 300 // write to Stdin 301 _, _ = wr.WriteString("test\n") 302 // test promptPassword 303 password, err := promptPassword("TestPromptPassword:") 304 require.NoError(t, err, "PromptPassword should not return error") 305 assert.Equal(t, "test", password, "PromptPassword should return test") 306 // restore Stdin 307 inputReader = oldStdin 308 _ = wr.Close() 309 }