make ldap_conn() be a context manager, so unbind_s can be run automatically
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index 80c0525..47defa5 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -25,6 +25,7 @@
 import string
 import crypt
 import random
+from contextlib import contextmanager
 from urllib.request import urlopen
 from urllib.parse import urlparse
 from io import BytesIO
@@ -628,17 +629,27 @@
             d = self.user_registration_date(user)
         return d
 
-
-def ldap_conn(who=None, cred=None):
+def ldap_conn_staysopen(who=None, cred=None):
     '''
-    Init & bind a connection with the given creds, or the admin creds if not
-    specified. Remember to unbind the connection when done.
+    You must call .unbind_s() when done with this
     '''
     con = ldap.initialize(config['auth.ldap.server'])
     con.simple_bind_s(who or config['auth.ldap.admin_dn'],
                       cred or config['auth.ldap.admin_password'])
     return con
 
+@contextmanager
+def ldap_conn(who=None, cred=None):
+    '''
+    Init & bind a connection with the given creds, or the admin creds if not
+    specified.
+    '''
+    con = ldap_conn_staysopen(who, cred)
+    try:
+        yield con
+    finally:
+        con.unbind_s()
+
 
 def ldap_user_dn(username):
     'return a Distinguished Name for a given username'
@@ -667,7 +678,6 @@
 
         # full registration into LDAP
         uid = str(M.AuthGlobals.get_next_uid()).encode('utf-8')
-        con = ldap_conn()
         uname = user_doc['username'].encode('utf-8')
         display_name = user_doc['display_name'].encode('utf-8')
         ldif_u = modlist.addModlist(dict(
@@ -681,12 +691,12 @@
             loginShell=b'/bin/bash',
             gecos=uname,
             description=b'SCM user account'))
-        try:
-            con.add_s(ldap_user_dn(user_doc['username']), ldif_u)
-        except ldap.ALREADY_EXISTS:
-            log.exception('Trying to create existing user %s', uname)
-            raise
-        con.unbind_s()
+        with ldap_conn() as con:
+            try:
+                con.add_s(ldap_user_dn(user_doc['username']), ldif_u)
+            except ldap.ALREADY_EXISTS:
+                log.exception('Trying to create existing user %s', uname)
+                raise
 
         if asbool(config.get('auth.ldap.use_schroot', True)):
             argv = ('schroot -d / -c {} -u root /ldap-userconfig.py init {}'.format(
@@ -742,11 +752,10 @@
         else:
             ldap_ident = ldap_pass = None
         try:
-            con = ldap_conn(ldap_ident, ldap_pass)
             new_password = self._encode_password(new_password)
-            con.modify_s(
-                dn, [(ldap.MOD_REPLACE, 'userPassword', new_password)])
-            con.unbind_s()
+            with ldap_conn(ldap_ident, ldap_pass) as con:
+                con.modify_s(
+                    dn, [(ldap.MOD_REPLACE, 'userPassword', new_password)])
             user.last_password_updated = datetime.utcnow()
             session(user).flush(user)
         except ldap.INVALID_CREDENTIALS:
@@ -792,8 +801,8 @@
         except ValueError:
             return False
         try:
-            con = ldap_conn(ldap_user, password)
-            con.unbind_s()
+            with ldap_conn(ldap_user, password):
+                pass
             return True
         except (ldap.INVALID_CREDENTIALS, ldap.UNWILLING_TO_PERFORM, ldap.NO_SUCH_OBJECT):
             log.debug(f'LdapAuth: could not authenticate {username}', exc_info=True)
@@ -1740,13 +1749,11 @@
             return LocalUserPreferencesProvider().get_pref(user, pref_name)
 
     def _get_pref(self, username, pref_name, multi=False):
-        con = ldap_conn()
-        try:
-            rs = con.search_s(ldap_user_dn(username), ldap.SCOPE_BASE)
-        except ldap.NO_SUCH_OBJECT:
-            rs = []
-        else:
-            con.unbind_s()
+        with ldap_conn() as con:
+            try:
+                rs = con.search_s(ldap_user_dn(username), ldap.SCOPE_BASE)
+            except ldap.NO_SUCH_OBJECT:
+                rs = []
         if not rs:
             log.warning(f'LdapUserPref: No user record found for: {username}')
             return ''
@@ -1767,10 +1774,9 @@
                 ldap_val = [v.encode('utf-8', errors='replace') for v in pref_value]
             else:
                 ldap_val = pref_value.encode('utf-8', errors='replace')
-            con = ldap_conn()
-            con.modify_s(ldap_user_dn(user.username),
-                         [(ldap.MOD_REPLACE, ldap_attr, ldap_val)])
-            con.unbind_s()
+            with ldap_conn() as con:
+                con.modify_s(ldap_user_dn(user.username),
+                             [(ldap.MOD_REPLACE, ldap_attr, ldap_val)])
         else:
             return LocalUserPreferencesProvider().set_pref(user, pref_name, pref_value)