Repository: privacyidea/privacyidea

Issue:
Authentication attempt of user without tokens is missing in audit log if SQL Truncate is enabled
Steps to reproduce:
* privacyIDEA 2.22.1
* Set ``PI_AUDIT_SQL_TRUNCATE = True`` in the config
* Have a user in the default realm which has no tokens assigned, e.g. ``fred``.
* Then, authentication via ``/validate/check`` fails as expected:
```

$ http --verify no POST https://privacyidea.workshop.local/validate/check user=fred pass=asdf  
HTTP/1.1 200 OK
Cache-Control: no-cache
Connection: Keep-Alive
Content-Length: 879
Content-Type: application/json
Date: Mon, 23 Apr 2018 17:22:48 GMT
Keep-Alive: timeout=5, max=100
Server: Apache/2.4.18 (Ubuntu)

{
    "detail": {
        "message": "The user has no tokens assigned",
        "threadid": 140576166987520
    },
    "id": 1,
    "jsonrpc": "2.0",
    "result": {
        "status": true,
        "value": false
    },
    "signature": "...",
    "time": 1524504168.966818,
    "version": "privacyIDEA 2.22.1",
    "versionnumber": "2.22.1"
}
```

However, the audit log shows nothing. privacyidea.log says:
```
[2018-04-23 19:23:00,089][1786][140576083060480][ERROR][privacyidea.lib.auditmodules.sqlaudit:240] exception TypeError("'NoneType' object has no attribute '__getitem__'",)
[2018-04-23 19:23:00,089][1786][140576083060480][ERROR][privacyidea.lib.auditmodules.sqlaudit:241] DATA: {'info': '', 'administrator': u'super', 'realm': u'**', 'success': True, 'privacyidea_server': 'privacyidea.workshop.local', 'client_user_agent': 'firefox', 'token_type': None, 'client': '192.168.33.1', 'user': '', 'resolver': '', 'action_detail': '', 'action': 'GET /audit/', 'serial': u'**'}
```
I believe this is because ``token_type`` is ``None``, which causes
https://github.com/privacyidea/privacyidea/blob/834ff2f77c37863244a94a58ae7b159d70bbc809/privacyidea/lib/auditmodules/sqlaudit.py#L119
to fail.


Discussion:
just for the record, this also fails if the user *has* a token assigned, but supplies the wrong OTP PIN:
```
[2018-04-23 19:33:17,985][2162][140340636894976][ERROR][privacyidea.lib.auditmodules.sqlaudit:241] DATA: {'info': 'wrong otp pin', 'realm': u'ucsrealm', 'tokentype': None, 'success': False, 'privacyidea_server': '192.168.33.191', 'client_user_agent': None, 'client': '192.168.33.192', 'user': u'fred', 'resolver': u'ucsres', 'action_detail': '', 'action': 'POST /validate/check', 'serial': None}
```

Resolving patch:
diff --git a/privacyidea/lib/auditmodules/sqlaudit.py b/privacyidea/lib/auditmodules/sqlaudit.py
--- a/privacyidea/lib/auditmodules/sqlaudit.py
+++ b/privacyidea/lib/auditmodules/sqlaudit.py
@@ -116,7 +116,10 @@ def _truncate_data(self):
         """
         for column, l in column_length.iteritems():
             if column in self.audit_data:
-                self.audit_data[column] = self.audit_data[column][:l]
+                data = self.audit_data[column]
+                if isinstance(data, basestring):
+                    data = data[:l]
+                self.audit_data[column] = data
 
     @staticmethod
     def _create_filter(param, timelimit=None):


Test patch:
diff --git a/tests/test_lib_audit.py b/tests/test_lib_audit.py
--- a/tests/test_lib_audit.py
+++ b/tests/test_lib_audit.py
@@ -201,6 +201,12 @@ def test_06_truncate_data(self):
         self.assertEqual(len(self.Audit.audit_data.get("token_type")),
                          column_length.get("token_type"))
 
+        # check treatment of None and boolean values
+        self.Audit.log({"token_type": None, "info": True})
+        self.Audit._truncate_data()
+        self.assertEqual(self.Audit.audit_data.get("token_type"), None)
+        self.assertEqual(self.Audit.audit_data.get("info"), True)
+
     def test_07_sign_non_ascii_entry(self):
         # Log a username as unicode with a non-ascii character
         self.Audit.log({"serial": "1234",