ldap_server: Log failures to find a valid user in the simple bind
authorGary Lockyer <gary@catalyst.net.nz>
Wed, 22 Mar 2017 23:39:25 +0000 (12:39 +1300)
committerAndrew Bartlett <abartlet@samba.org>
Wed, 29 Mar 2017 00:37:29 +0000 (02:37 +0200)
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
python/samba/tests/auth_log.py
source4/auth/ntlm/auth_simple.c

index abd2952fbb0c0f2388a7cfafacf35bb2f4a9e780..a2bddd488e8180d9e718565b328a50dceba333b4 100644 (file)
@@ -32,6 +32,7 @@ import samba.tests.auth_log_base
 from samba.credentials import Credentials, DONT_USE_KERBEROS, MUST_USE_KERBEROS
 from samba import NTSTATUSError
 from subprocess import call
+from ldb import LdbError
 
 class AuthLogTests(samba.tests.auth_log_base.AuthLogTestBase):
 
@@ -485,6 +486,85 @@ class AuthLogTests(samba.tests.auth_log_base.AuthLogTestBase):
         self.assertEquals("simple bind",
                            msg["Authentication"]["authDescription"])
 
+    def test_ldap_simple_bind_bad_password(self):
+        def isLastExpectedMessage( msg):
+            return (msg["type"] == "Authentication" and
+                    msg["Authentication"]["serviceDescription"]  == "LDAP" and
+                    msg["Authentication"]["status"]
+                        == "NT_STATUS_WRONG_PASSWORD" and
+                    msg["Authentication"]["authDescription"] == "simple bind")
+
+        creds = self.insta_creds(template=self.get_credentials())
+        creds.set_password( "badPassword")
+        creds.set_bind_dn("%s\\%s" % (creds.get_domain(),
+                                     creds.get_username()))
+
+        thrown = False
+        try:
+            self.samdb = SamDB(url="ldaps://%s" % os.environ["SERVER"],
+                               lp = self.get_loadparm(),
+                               credentials=creds)
+        except LdbError:
+            thrown = True
+        self.assertEquals( thrown, True)
+
+        messages = self.waitForMessages( isLastExpectedMessage)
+        self.assertEquals(1,
+                          len(messages),
+                          "Did not receive the expected number of messages")
+
+
+    def test_ldap_simple_bind_bad_user(self):
+        def isLastExpectedMessage( msg):
+            return (msg["type"] == "Authentication" and
+                    msg["Authentication"]["serviceDescription"]  == "LDAP" and
+                    msg["Authentication"]["status"]
+                        == "NT_STATUS_NO_SUCH_USER" and
+                    msg["Authentication"]["authDescription"] == "simple bind")
+
+        creds = self.insta_creds(template=self.get_credentials())
+        creds.set_bind_dn("%s\\%s" % (creds.get_domain(), "badUser"))
+
+        thrown = False
+        try:
+            self.samdb = SamDB(url="ldaps://%s" % os.environ["SERVER"],
+                               lp = self.get_loadparm(),
+                               credentials=creds)
+        except LdbError:
+            thrown = True
+        self.assertEquals( thrown, True)
+
+        messages = self.waitForMessages( isLastExpectedMessage)
+        self.assertEquals(1,
+                          len(messages),
+                          "Did not receive the expected number of messages")
+
+
+    def test_ldap_simple_bind_unparseable_user(self):
+        def isLastExpectedMessage( msg):
+            return (msg["type"] == "Authentication" and
+                    msg["Authentication"]["serviceDescription"]  == "LDAP" and
+                    msg["Authentication"]["status"]
+                        == "NT_STATUS_NO_SUCH_USER" and
+                    msg["Authentication"]["authDescription"] == "simple bind")
+
+        creds = self.insta_creds(template=self.get_credentials())
+        creds.set_bind_dn("%s\\%s" % (creds.get_domain(), "abdcef"))
+
+        thrown = False
+        try:
+            self.samdb = SamDB(url="ldaps://%s" % os.environ["SERVER"],
+                               lp = self.get_loadparm(),
+                               credentials=creds)
+        except LdbError:
+            thrown = True
+        self.assertEquals( thrown, True)
+
+        messages = self.waitForMessages( isLastExpectedMessage)
+        self.assertEquals(1,
+                          len(messages),
+                          "Did not receive the expected number of messages")
+
     def test_smb(self):
         def isLastExpectedMessage( msg):
             return (msg["type"] == "Authorization" and
index 7e434d7d3c21241ec8a039df349d74abcf5205ef..cd96113ca0396c5f3d56ac0dc3ba949f68606614 100644 (file)
@@ -42,8 +42,8 @@ _PUBLIC_ NTSTATUS authenticate_ldap_simple_bind(TALLOC_CTX *mem_ctx,
        NTSTATUS nt_status;
        uint8_t authoritative = 0;
        TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
-       const char *nt4_domain;
-       const char *nt4_username;
+       const char *nt4_domain = NULL;
+       const char *nt4_username = NULL;
        uint32_t flags = 0;
        const char *transport_protection = AUTHZ_TRANSPORT_PROTECTION_NONE;
        if (using_tls) {
@@ -54,15 +54,7 @@ _PUBLIC_ NTSTATUS authenticate_ldap_simple_bind(TALLOC_CTX *mem_ctx,
                return NT_STATUS_NO_MEMORY;
        }
 
-       nt_status = crack_auto_name_to_nt4_name(tmp_ctx, ev, lp_ctx, dn,
-                                               &nt4_domain, &nt4_username);
-
-       if (!NT_STATUS_IS_OK(nt_status)) {
-               talloc_free(tmp_ctx);
-               return nt_status;
-       }
-
-       nt_status = auth_context_create(tmp_ctx, 
+       nt_status = auth_context_create(tmp_ctx,
                                        ev, msg,
                                        lp_ctx,
                                        &auth_context);
@@ -71,13 +63,19 @@ _PUBLIC_ NTSTATUS authenticate_ldap_simple_bind(TALLOC_CTX *mem_ctx,
                return nt_status;
        }
 
+       /*
+        * We check the error after building the user_info so we can
+        * log a failure to find the user correctly
+        */
+       nt_status = crack_auto_name_to_nt4_name(tmp_ctx, ev, lp_ctx, dn,
+                                               &nt4_domain, &nt4_username);
+
        user_info = talloc_zero(tmp_ctx, struct auth_usersupplied_info);
        if (!user_info) {
                talloc_free(tmp_ctx);
                return NT_STATUS_NO_MEMORY;
        }
 
-       user_info->mapped_state = true;
        user_info->client.account_name = dn;
        /* No client.domain_name, use account_name instead */
        user_info->mapped.account_name = nt4_username;
@@ -108,6 +106,19 @@ _PUBLIC_ NTSTATUS authenticate_ldap_simple_bind(TALLOC_CTX *mem_ctx,
                MSV1_0_CLEARTEXT_PASSWORD_ALLOWED |
                MSV1_0_CLEARTEXT_PASSWORD_SUPPLIED;
 
+       /* This is a check for the crack names call above */
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               log_authentication_event(auth_context->msg_ctx,
+                                        auth_context->lp_ctx,
+                                        user_info, nt_status,
+                                        NULL, NULL, NULL, NULL);
+               talloc_free(tmp_ctx);
+               return nt_status;
+       }
+
+       /* Now that we have checked if the crack names worked, set mapped_state */
+       user_info->mapped_state = true;
+
        nt_status = auth_check_password(auth_context, tmp_ctx, user_info,
                                        &user_info_dc, &authoritative);
        if (!NT_STATUS_IS_OK(nt_status)) {