Repository: privacyidea/privacyidea

Issue:
Migrate EMail, TAN and VASCO token to Python 3
This slightly changes behavior: The VASCO token initialization now throws a ``ParameterError`` if the secret couldn't be decoded.


Discussion:
# [Codecov](https://codecov.io/gh/privacyidea/privacyidea/pull/1417?src=pr&el=h1) Report
> Merging [#1417](https://codecov.io/gh/privacyidea/privacyidea/pull/1417?src=pr&el=desc) into [master](https://codecov.io/gh/privacyidea/privacyidea/commit/333d704397623ca20798f505b39f7278ba24416e?src=pr&el=desc) will **decrease** coverage by `<.01%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/privacyidea/privacyidea/pull/1417/graphs/tree.svg?width=650&token=7nHLZki60B&height=150&src=pr)](https://codecov.io/gh/privacyidea/privacyidea/pull/1417?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master    #1417      +/-   ##
==========================================
- Coverage   96.78%   96.78%   -0.01%     
==========================================
  Files         144      144              
  Lines       17180    17185       +5     
==========================================
+ Hits        16628    16632       +4     
- Misses        552      553       +1
```


| [Impacted Files](https://codecov.io/gh/privacyidea/privacyidea/pull/1417?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [privacyidea/lib/tokens/vascotoken.py](https://codecov.io/gh/privacyidea/privacyidea/pull/1417/diff?src=pr&el=tree#diff-cHJpdmFjeWlkZWEvbGliL3Rva2Vucy92YXNjb3Rva2VuLnB5) | `93.84% <100%> (+0.29%)` | :arrow_up: |
| [privacyidea/lib/tokens/emailtoken.py](https://codecov.io/gh/privacyidea/privacyidea/pull/1417/diff?src=pr&el=tree#diff-cHJpdmFjeWlkZWEvbGliL3Rva2Vucy9lbWFpbHRva2VuLnB5) | `100% <100%> (ø)` | :arrow_up: |
| [privacyidea/lib/tokens/tantoken.py](https://codecov.io/gh/privacyidea/privacyidea/pull/1417/diff?src=pr&el=tree#diff-cHJpdmFjeWlkZWEvbGliL3Rva2Vucy90YW50b2tlbi5weQ==) | `100% <100%> (ø)` | :arrow_up: |
| [privacyidea/lib/tokens/vasco.py](https://codecov.io/gh/privacyidea/privacyidea/pull/1417/diff?src=pr&el=tree#diff-cHJpdmFjeWlkZWEvbGliL3Rva2Vucy92YXNjby5weQ==) | `96.72% <100%> (-1.64%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/privacyidea/privacyidea/pull/1417?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/privacyidea/privacyidea/pull/1417?src=pr&el=footer). Last update [333d704...6ae65d0](https://codecov.io/gh/privacyidea/privacyidea/pull/1417?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Resolving patch:
diff --git a/privacyidea/lib/authcache.py b/privacyidea/lib/authcache.py
--- a/privacyidea/lib/authcache.py
+++ b/privacyidea/lib/authcache.py
@@ -62,6 +62,21 @@ def delete_from_cache(username, realm, resolver, password):
     return r
 
 
+def cleanup(minutes):
+    """
+    Will delete all authcache entries, where last_auth column is older than
+    the given minutes.
+
+    :param minutes: Age of the last_authentication in minutes
+    :type minutes: int
+    :return:
+    """
+    cleanuptime = datetime.datetime.utcnow() - datetime.timedelta(minutes=minutes)
+    r = db.session.query(AuthCache).filter(AuthCache.last_auth < cleanuptime).delete()
+    db.session.commit()
+    return r
+
+
 def verify_in_cache(username, realm, resolver, password,
                     first_auth = None,
                     last_auth = None):


Test patch:
diff --git a/tests/test_lib_authcache.py b/tests/test_lib_authcache.py
--- a/tests/test_lib_authcache.py
+++ b/tests/test_lib_authcache.py
@@ -7,7 +7,8 @@
 
 from privacyidea.lib.authcache import (add_to_cache, delete_from_cache,
                                        update_cache_last_auth, verify_in_cache,
-                                       _hash_password)
+                                       _hash_password,
+                                       cleanup)
 from privacyidea.models import AuthCache
 import datetime
 
@@ -92,7 +93,23 @@ def test_03_delete_old_entries(self):
         r = AuthCache.query.filter(AuthCache.username == "grandpa").first()
         self.assertEqual(r, None)
 
+    def test_04_cleanup_authcache(self):
+        # cleanup everything!
+        r = cleanup(100000000)
+        # Create some entries:
+        AuthCache("grandpa", self.realm, self.resolver, _hash_password(self.password),
+                  first_auth=datetime.datetime.utcnow() - datetime.timedelta(
+                      days=10),
+                  last_auth=datetime.datetime.utcnow() - datetime.timedelta(
+                      days=2)).save()
+        AuthCache("grandpa", self.realm, self.resolver, _hash_password(self.password),
+                  first_auth=datetime.datetime.utcnow() - datetime.timedelta(
+                      minutes=10),
+                  last_auth=datetime.datetime.utcnow() - datetime.timedelta(
+                      minutes=2)).save()
 
-
-
+        # Now we delete entries, that are older than 20 minutes. Only the 2 days old
+        # should be deleted. Not the 2 minutes old.
+        r = cleanup(10)
+        self.assertEqual(1, r)