diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index a7e92962a2f155faffc800405802dd0cfc7d7038..d1c52cbaddd85900968e47b943dae207fa85d892 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -86,12 +86,14 @@ test:pycaosdb:py34:
     tags: [ py34 ]
     stage: test
     script:
+        - touch ~/.pycaosdb.ini
         - tox -r -e py34
 
 test:pycaosdb:py27:
     tags: [ py27 ]
     stage: test
     script:
+        - touch ~/.pycaosdb.ini
         - tox -r -e py27
 
 # pylint tests for pycaosdb (python 3.4)
diff --git a/examples/server_side_script.py b/examples/server_side_script.py
new file mode 100755
index 0000000000000000000000000000000000000000..71bd9c05b4e86133cc356e1c15359701642a9486
--- /dev/null
+++ b/examples/server_side_script.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# ** header v3.0
+# This file is a part of the CaosDB Project.
+#
+# Copyright (C) 2018 Research Group Biomedical Physics,
+# Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+# ** end header
+#
+"""server_side_script.py.
+
+An example which implements a minimal server-side script.
+
+1) This script expects to find a *.txt file in the .upload_files dir which is
+printed to stdout.
+
+2) It executes a "Count stars" query and prints the result to stdout.
+
+3) It will return with code 0 if everything is ok, or with any code that is
+specified with the commandline option --exit
+"""
+
+import sys
+from os import listdir
+from caosdb import configure_connection, execute_query
+
+
+# parse --auth-token option and configure connection
+CODE = 0
+QUERY = "COUNT stars"
+for arg in sys.argv:
+    if arg.startswith("--auth-token="):
+        auth_token = arg[13:]
+        configure_connection(auth_token=auth_token)
+    if arg.startswith("--exit="):
+        CODE = int(arg[7:])
+    if arg.startswith("--query="):
+        QUERY = arg[8:]
+
+
+############################################################
+# 1 # find and print *.txt file ############################
+############################################################
+
+try:
+    for fname in listdir(".upload_files"):
+        if fname.endswith(".txt"):
+            with open(".upload_files/{}".format(fname)) as f:
+                print(f.read())
+except FileNotFoundError:
+    pass
+
+
+############################################################
+# 2 # query "COUNT stars" ##################################
+############################################################
+
+RESULT = execute_query(QUERY)
+print(RESULT)
+
+############################################################
+# 3 ########################################################
+############################################################
+
+sys.exit(CODE)
diff --git a/pytest.ini b/pytest.ini
index abdd410e5f9e9835a3233b22687ad49cc1109235..ca6aad829a3e0607292cf69b8b1d4b7f7758993e 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -1,3 +1,3 @@
 [pytest]
-testpaths = unittests
-addopts = -vv --cov=caosdb
+testpaths=unittests
+addopts=-x -vv --cov=caosdb
diff --git a/setup.cfg b/setup.cfg
index 74c5620b86c6fd5ee96abea95dab4010c9fb87a3..c46089e4d24843d7d4cc4f83dad6ec1351e4cc3f 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,2 +1,4 @@
+[aliases]
+test=pytest
 [pycodestyle]
 ignore=E501,E121,E123,E126,E226,E24,E704,W503,W504
diff --git a/setup.py b/setup.py
index f80c619591a55190d70ee105b0cff2e3d79894c1..146b93ba6a4590c7c54a4367c02e38e952c7a685 100755
--- a/setup.py
+++ b/setup.py
@@ -32,8 +32,9 @@ setup(name='PyCaosDB',
       author_email='timm.fitschen@ds.mpg.de',
       packages=find_packages('src'),
       package_dir={'': 'src'},
-      install_requires=['lxml>=3.6.4', 'coverage>=4.4.2',
-                        'PyYaml>=3.12', 'future'],
+      install_requires=['lxml>=3.6.4',
+                        'PyYaml>=3.12', 'future', 'PySocks>=1.6.7'],
       extras_require={'keyring': ['keyring>=13.0.0']},
-      tests_require=["pytest"],
+      setup_requires=["pytest-runner>=2.0,<3dev"],
+      tests_require=["pytest", "pytest-cov", "coverage>=4.4.2"],
       )
diff --git a/src/caosdb/__init__.py b/src/caosdb/__init__.py
index 91b429e602245a8cea6b5c939260e754a6de5f53..69f8f24e8eab9f3528eb2133cf8a49cd0d19acdf 100644
--- a/src/caosdb/__init__.py
+++ b/src/caosdb/__init__.py
@@ -24,7 +24,7 @@
 
 # Import of the connection function (which is used to connect to the DB):
 from os.path import expanduser, join
-from os import getcwd
+from os import getcwd, environ
 from caosdb.configuration import configure, get_config
 
 from caosdb.common import administration
@@ -42,5 +42,10 @@ from caosdb.common.models import (delete, execute_query, raise_errors,
                                   get_global_acl, get_known_permissions)
 # Import of convenience methods:
 import caosdb.apiutils
-configure(expanduser('~/.pycaosdb.ini'))
+
+# read configuration these files
+if "PYCAOSDBINI" in environ:
+    configure(expanduser(environ["PYCAOSDBINI"]))
+else:
+    configure(expanduser('~/.pycaosdb.ini'))
 configure(join(getcwd(), "pycaosdb.ini"))
diff --git a/src/caosdb/common/administration.py b/src/caosdb/common/administration.py
index ee57a370db58c3f1b604014a08b8de457724005f..98687e3c25286121decb499e233aa0743eff47a8 100644
--- a/src/caosdb/common/administration.py
+++ b/src/caosdb/common/administration.py
@@ -31,6 +31,71 @@ from caosdb.connection.connection import get_connection
 from caosdb.common.utils import xml2str
 
 
+def set_server_property(key, value):
+    """set_server_property.
+
+    Set a server property.
+
+    Parameters
+    ----------
+    key : str
+        The name of the server property.
+    value : str
+        The value of the server property.
+
+
+    Returns
+    -------
+    None
+    """
+    con = get_connection()
+
+    con._form_data_request(method="POST", path="_server_properties",
+                           params={key: value}).read()
+
+
+def get_server_properties():
+    """get_server_properties.
+
+    Get all server properties as a dict.
+
+    Returns
+    -------
+    dict
+        The server properties.
+    """
+    con = get_connection()
+    body = con._http_request(method="GET", path="_server_properties").response
+    xml = etree.parse(body)
+    props = dict()
+    for elem in xml.getroot():
+        props[elem.tag] = elem.text
+    return props
+
+
+def get_server_property(key):
+    """get_server_property.
+
+    Get a server property.
+
+    Parameters
+    ----------
+    key : str
+        The name of the server property
+
+    Returns
+    -------
+    value : str
+        The string value of the server property.
+
+    Raises
+    ------
+    KeyError
+        If the server property is no defined.
+    """
+    return get_server_properties()[key]
+
+
 def _retrieve_user(name, realm=None, **kwargs):
     con = get_connection()
     try:
@@ -154,6 +219,7 @@ def _delete_role(name, **kwargs):
 
 def _set_roles(username, roles, realm=None, **kwargs):
     xml = etree.Element("Roles")
+    print(roles)
     for r in roles:
         xml.append(etree.Element("Role", name=r))
 
@@ -189,8 +255,9 @@ def _get_roles(username, realm=None, **kwargs):
         e.msg = "User does not exist."
         raise
     ret = set()
-    for r in etree.fromstring(body)[0]:
-        ret.add(r.get("name"))
+    for r in etree.fromstring(body).xpath('/Response/Roles')[0]:
+        if r.tag == "Role":
+            ret.add(r.get("name"))
     return ret
 
 
@@ -251,11 +318,12 @@ class PermissionRule():
         xml = etree.fromstring(body)
         ret = set()
         for c in xml:
-            ret.add(PermissionRule._parse_element(c))
+            if c.tag in ["Grant", "Deny"]:
+                ret.add(PermissionRule._parse_element(c))
         return ret
 
     def __str__(self):
-        return self._action + "(" + self._permission + ")" + \
+        return str(self._action) + "(" + str(self._permission) + ")" + \
             ("P" if self._priority is True else "")
 
     def __repr__(self):
diff --git a/src/caosdb/common/models.py b/src/caosdb/common/models.py
index e07f97134035b79b66f1bfb9c33ee3b6d33ac97d..15d460b2c2a128e9dd878f5c88bccb6220591815 100644
--- a/src/caosdb/common/models.py
+++ b/src/caosdb/common/models.py
@@ -777,6 +777,7 @@ class Entity(object):
             e = Container().retrieve(query=self.id, sync=False)[0]
         e.acl = ACL(self.acl.to_xml())
         e.update()
+        return e
 
     def delete(self, raise_exception_on_error=True):
         return Container().append(self).delete(
@@ -1822,11 +1823,13 @@ class Container(list):
     insertion, update, and deletion which are a applied to all entities
     in the container or the whole container respectively.
     """
+
     _debug = staticmethod(
         lambda: (
             get_config().getint(
                 "Container",
-                "debug") if get_config().get(
+                "debug") if get_config().has_section("Container") and
+            get_config().get(
                 "Container",
                 "debug") is not None else 0))
 
diff --git a/src/caosdb/configuration.py b/src/caosdb/configuration.py
index 9f6b558abd7bd5e291eaa8bd89ca41ebe0c73bf8..4d0797844182b8465ef5f97a869e31ee4fcaf47d 100644
--- a/src/caosdb/configuration.py
+++ b/src/caosdb/configuration.py
@@ -21,9 +21,6 @@
 #
 # ** end header
 #
-
-"""Created on 20.09.2016."""
-
 try:
     # python2
     from ConfigParser import ConfigParser
@@ -31,38 +28,23 @@ except ImportError:
     # python3
     from configparser import ConfigParser
 
-_DEFAULTS = {"Connection":
-             {"url": None,
-              "timeout": "200",
-              "username": None,
-              "password_method": "plain",
-              "debug": "0",
-              "cacert": None},
-             "Container":
-             {"debug": "0"}}
-
 
 def _reset_config():
     global _pycaosdbconf
-    pycaosdbconf = None
-    _pycaosdbconf = ConfigParser(allow_no_value=True)
-    _init_defaults(_pycaosdbconf)
-
-
-def _init_defaults(confpar):
-    for sec in _DEFAULTS.keys():
-        confpar.add_section(sec)
-        for opt in _DEFAULTS[sec].keys():
-            confpar.set(sec, opt, _DEFAULTS[sec][opt])
+    _pycaosdbconf = ConfigParser(allow_no_value=False)
 
 
 def configure(inifile):
+    """read config from file.
+
+    Return a list of files which have successfully been parsed.
+    """
     global _pycaosdbconf
     if "_pycaosdbconf" not in globals():
         _pycaosdbconf = None
     if _pycaosdbconf is None:
         _reset_config()
-    _pycaosdbconf.read(inifile)
+    return _pycaosdbconf.read(inifile)
 
 
 def get_config():
diff --git a/src/caosdb/connection/SocksiPy.zip b/src/caosdb/connection/SocksiPy.zip
new file mode 100644
index 0000000000000000000000000000000000000000..e81f1f9393c766a3acd41b44245f9e17f090cbe5
Binary files /dev/null and b/src/caosdb/connection/SocksiPy.zip differ
diff --git a/src/caosdb/connection/connection.py b/src/caosdb/connection/connection.py
index 2c6a884cf85843c50fcc3920b9f387fe334be0d3..e6638d2fd8d55874c557f2cae7c0c58c1995f620 100644
--- a/src/caosdb/connection/connection.py
+++ b/src/caosdb/connection/connection.py
@@ -31,7 +31,7 @@ try:
 except ImportError:
     from urllib import quote
     from urlparse import urlparse
-
+from errno import EPIPE as BrokenPipe
 from socket import error as SocketError
 import ssl
 import logging
@@ -73,6 +73,14 @@ class _WrappedHTTPResponse(CaosDBHTTPResponse):
 
 
 class _DefaultCaosDBServerConnection(CaosDBServerConnection):
+    """_DefaultCaosDBServerConnection.
+
+    Methods
+    -------
+    configure
+    request
+    """
+
     def __init__(self):
         self._useragent = ("PyCaosDB - "
                            "DefaultCaosDBServerConnection")
@@ -80,6 +88,28 @@ class _DefaultCaosDBServerConnection(CaosDBServerConnection):
         self._base_path = None
 
     def request(self, method, path, headers=None, body=None, **kwargs):
+        """request.
+
+        Send a HTTP request to the server.
+
+        Parameters
+        ----------
+        method : str
+            The HTTP request method.
+        path : str
+            An URI path segment (without the 'scheme://host:port/' parts),
+            including query and frament segments.
+        headers : dict of str -> str, optional
+            HTTP request headers. (Defautl: None)
+        body : str or bytes or readable, opional
+            The body of the HTTP request. Bytes should be a utf-8 encoded
+            string.
+        **kwargs :
+            Any keyword arguments will be ignored.
+
+        Returns
+        -------
+        """
         if headers is None:
             headers = {}
         try:
@@ -87,7 +117,7 @@ class _DefaultCaosDBServerConnection(CaosDBServerConnection):
                 host=self.setup_fields["host"],
                 timeout=self.setup_fields["timeout"],
                 context=self.setup_fields["context"],
-            )
+                socket_proxy=self.setup_fields["socket_proxy"])
             self._http_con.request(method=method, url=self._base_path + path,
                                    headers=headers, body=body)
         except SocketError as socket_err:
@@ -97,7 +127,32 @@ class _DefaultCaosDBServerConnection(CaosDBServerConnection):
         return _WrappedHTTPResponse(self._http_con.getresponse())
 
     def configure(self, **config):
-        context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
+        """configure.
+
+        Configure the http connection.
+
+        Parameters
+        ----------
+        cacert : str
+            Path to the CA certificate which will be used to identify the
+            server.
+        url : str
+            The url of the CaosDB Server, e.g.
+            `https://example.com:443/rootpath`, including a possible root path.
+        **config :
+            Any further keyword arguments are being ignored.
+
+        Raises
+        ------
+        ConnectionException
+            If no url has been specified, or if the CA certificate cannot be
+            loaded.
+        """
+        if "ssl_version" in config and config["cacert"] is not None:
+            ssl_version = getattr(ssl, config["ssl_version"])
+        else:
+            ssl_version = ssl.PROTOCOL_TLSv1
+        context = ssl.SSLContext(ssl_version)
         context.verify_mode = ssl.CERT_REQUIRED
         if config.get("ssl_insecure"):
             print("Relaxed SSL mode.")
@@ -157,12 +212,39 @@ def _make_conf(*conf):
 
 
 _DEFAULT_CONF = {
-    "password_method": "plain",
-    "implementation": _DefaultCaosDBServerConnection,
+    "password_method": "plain", 
+    "implementation": _DefaultCaosDBServerConnection, 
+    "timeout": 210
 }
 
 
 def _get_authenticator(**config):
+    """_get_authenticator.
+
+    Import and configure the password_method.
+
+    Parameters
+    ----------
+    password_method : str
+        The simple name of a submodule of caosdb.connection.authentication.
+        Currently, there are three valid values for this parameter: 'plain',
+        'pass', and 'keyring'.
+    **config :
+        Any other keyword arguments are passed the configre method of the
+        password_method.
+
+    Returns
+    -------
+    AbstractAuthenticator
+        An object which implements the password_method and which already
+        configured.
+
+    Raises
+    ------
+    ConnectionException
+        If the password_method string cannot be resolved to a CaosAuthenticator
+        class.
+    """
     auth_module = ("caosdb.connection.authentication." +
                    config["password_method"])
     _LOGGER.debug("import auth_module %s", auth_module)
@@ -174,37 +256,37 @@ def _get_authenticator(**config):
         return auth_provider
 
     except ImportError:
-        raise RuntimeError("Password method \"{}\" not implemented. "
-                           "Valid methods: plain, pass, or keyring."
-                           .format(config["password_method"]))
+        raise ConfigurationException("Password method \"{}\" not implemented. "
+                                     "Valid methods: plain, pass, or keyring."
+                                     .format(config["password_method"]))
 
 
 def configure_connection(**kwargs):
-    """Configures the caosdb connection.
-
-    All paramters are optional. The default configuration is taken from the
-    `Connection` section of the configuration which can be retrieved by
-    `get_config`
-
-    Returns the Connection object.
-
-    Typical arguments are:
-    url             The URL of the CaosDB server. E.g. https://caosdb.org:433/playground
-    username        The username
-    password        Two options:
-                        1) The plain text password
-                        2) A function which returns the password.
-    timeout         A connection timeout in seconds.
-    password_method The method to use for obtaining the password.  Can be for
-        example:
-        - "plain"    Need username and password arguments.
-        - "pass"     Uses the `pass` password manager.
-        - "keyring"  Uses the `keyring` library.
-        - "input"    Asks for the password.
-    implementation  A class which implements CaosDBServerConnection. (Default:
+    """Configures the caosdb connection and return the Connection object.
+
+    The effective configuration is governed by the default values (see
+    'Parameters'), the global configuration (see `caosdb.get_config()`) and the
+    parameters which are passed to this function, with ascending priority.
+
+    The parameters which are listed here, are possibly not sufficient for a
+    working configuration of the connection. Check the `configure` method of
+    the implementation class and the password_method for more details.
+
+    Parameters
+    ----------
+    implementation : CaosDBServerConnection
+        The class which implements the connection. (Default:
         _DefaultCaosDBServerConnection)
-    ssl_insecure    Whether SSL certificate warnings should be ignored. Only use
-        this fordevelopment purposes! (Default: False)
+    password_method : str
+        The name of a submodule of caosdb.connection.authentication which
+        implements the AbstractAuthenticator interface. (Default: 'plain')
+    timeout : int
+        A connection timeout in seconds. (Default: 210)
+
+    Returns
+    -------
+    _Connection
+        The singleton instance of the _Connection class.
     """
     global_conf = (dict(get_config().items("Connection")) if
                    get_config().has_section("Connection") else dict())
@@ -263,7 +345,8 @@ def _handle_response_status(http_response):
 
 class _Connection(object):  # pylint: disable=useless-object-inheritance
     """This connection class provides the interface to the database connection
-    allowing for retrieval, insertion, update, etc. of entries.
+    allowing for retrieval, insertion, update, etc. of entities, files, users,
+    roles and much more.
 
     It wrapps an instance of CaosDBServerConnection which actually does the
     work (how, depends on the instance).
@@ -393,9 +476,13 @@ class _Connection(object):  # pylint: disable=useless-object-inheritance
             return self._retry_http_request(method=method, path=path,
                                             headers=headers, body=body,
                                             **kwargs)
-        except ConnectionException as conex:
-            print(conex)
-            return None
+        except SocketError as e:
+            if e.errno != BrokenPipe:
+                raise
+            return self._retry_http_request(method=method, path=path,
+                                            headers=headers, body=body,
+                                            reconnect=False,
+                                            **kwargs)
         except LoginFailedException:
             if kwargs.get("reconnect", True) is True:
                 self._login()
diff --git a/src/caosdb/connection/mockup.py b/src/caosdb/connection/mockup.py
index abde5d03da4d553b523c3ecc63ff7552696cc865..6d1bb1f389823c2824bbaa3f3b1b41462e284692 100644
--- a/src/caosdb/connection/mockup.py
+++ b/src/caosdb/connection/mockup.py
@@ -47,7 +47,7 @@ class MockUpResponse(CaosDBHTTPResponse):
     def __init__(self, status, headers, body):
         self._status = status
         self.headers = headers
-        self.body = StringIO(body)
+        self.response = StringIO(body)
 
     @property
     def status(self):
@@ -56,7 +56,7 @@ class MockUpResponse(CaosDBHTTPResponse):
 
     def read(self, size=-1):
         """Return the body of the response."""
-        return self.body.read(size)
+        return self.response.read(size)
 
     def getheader(self, name, default=None):
         """Get the contents of the header `name`, or `default` if there is no
diff --git a/src/caosdb/connection/streaminghttp.py b/src/caosdb/connection/streaminghttp.py
index fa97a964149ff1630bb3bbb3fd1cccf8029f8d6b..01774301b9bdb55bdbf6b56695042aaf354dba97 100644
--- a/src/caosdb/connection/streaminghttp.py
+++ b/src/caosdb/connection/streaminghttp.py
@@ -51,7 +51,8 @@ since there is no way to determine in advance the total size that will be
 yielded, and there is no way to reset an interator.
 """
 
-from __future__ import unicode_literals, print_function
+from __future__ import unicode_literals, print_function, absolute_import
+import socks
 import socket
 try:
     # python3
@@ -69,6 +70,14 @@ class StreamingHTTPSConnection(client.HTTPSConnection, object):
     that overrides the `send()` method to support iterable body objects."""
     # pylint: disable=unused-argument, arguments-differ
 
+    def __init__(self, socket_proxy=None, **kwargs):
+        if socket_proxy is not None:
+            host, port = socket_proxy.split(":")
+            socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, host,
+                                  int(port))
+            socket.socket = socks.socksocket
+        super(StreamingHTTPSConnection, self).__init__(**kwargs)
+
     def _send_output(self, body, **kwargs):
         """Send the currently buffered request and clear the buffer.
 
@@ -87,7 +96,7 @@ class StreamingHTTPSConnection(client.HTTPSConnection, object):
         if body is not None:
             self.send(body)
 
-    # pylint: disable=too-complex, too-many-branches
+    # pylint: disable=too-many-branches
 
     def send(self, value):
         """Send ``value`` to the server.
diff --git a/src/caosdb/exceptions.py b/src/caosdb/exceptions.py
index a5d6e99662c38e6f74e2e974a68ce8152997e271..45c4570b4227031a35a486b86ea65535ff105852 100644
--- a/src/caosdb/exceptions.py
+++ b/src/caosdb/exceptions.py
@@ -70,9 +70,10 @@ class ClientErrorException(CaosDBException):
 class ServerErrorException(CaosDBException):
     def __init__(self, body):
         xml = etree.fromstring(body)
-        msg = xml[0].get("description")
-        if xml[0].text is not None:
-            msg = msg + "\n\n" + xml[0].text
+        error = xml.xpath('/Response/Error')[0]
+        msg = error.get("description")
+        if error.text is not None:
+            msg = msg + "\n\n" + error.text
         CaosDBException.__init__(self, msg)
 
 
diff --git a/src/caosdb/utils/caosdb_admin.py b/src/caosdb/utils/caosdb_admin.py
index f1b41f60371608b3f19e6dcda85475d7df0361d5..b3145390fc9de36da57fe3dd88996199f50a3ce7 100755
--- a/src/caosdb/utils/caosdb_admin.py
+++ b/src/caosdb/utils/caosdb_admin.py
@@ -35,9 +35,9 @@ from argparse import ArgumentParser
 from argparse import RawDescriptionHelpFormatter
 
 __all__ = []
-__version__ = 0.2
+__version__ = 0.3
 __date__ = '2016-09-19'
-__updated__ = '2017-08-30'
+__updated__ = '2018-12-11'
 
 
 def do_update_role(args):
@@ -98,7 +98,7 @@ def do_insert(args):
         reconnect=True,
         query_dict=fdict,
         body=xml)
-    db.Container._response_to_entities(ret)
+    print(db.Container._response_to_entities(ret))
 
 
 def _promt_for_pw():
@@ -217,6 +217,25 @@ def do_deny_role_permissions(args):
     admin._set_permissions(role=args.role_name, permission_rules=perms)
 
 
+def do_retrieve_entity_acl(args):
+    entities = db.execute_query(q=args.query, flags={"ACL": None})
+    for entity in entities:
+        print(entity.id)
+        print(entity.acl)
+
+
+def do_action_entity_permissions(args):
+    entities = db.execute_query(q=args.query, flags={"ACL": None})
+    for entity in entities:
+        for p in args.permissions:
+            getattr(entity, args.action)(role=args.role, priority=args.priority,
+                                         permission=p)
+    entities.update(flags={"ACL": None})
+    for entity in entities:
+        print(entity.id)
+        print(entity.acl)
+
+
 def main(argv=None):
     """Command line options."""
 
@@ -230,46 +249,17 @@ def main(argv=None):
     program_build_date = str(__updated__)
     program_version_message = '%%(prog)s %s (%s)' % (
         program_version, program_build_date)
-    program_shortdesc = __import__('__main__').__doc__.split("\n")[1]
+    program_shortdesc = __import__('__main__').__doc__
     program_license = '''%s
 
-  Created by timm fitschen on %s.
-  Copyright 2016 BMPG. All rights reserved.
-
-  Distributed on an "AS IS" basis without warranties
-  or conditions of any kind, either express or implied.
-
 USAGE
-''' % (program_shortdesc, str(__date__))
+''' % (program_shortdesc)
 
     # Setup argument parser
     parser = ArgumentParser(description=program_license,
                             formatter_class=RawDescriptionHelpFormatter)
-    parser.add_argument(
-        "-v",
-        "--verbose",
-        dest="verbose",
-        action="count",
-        help="Set verbosity level [default: %(default)s]",
-        default=0)
     parser.add_argument('-V', '--version', action='version',
                         version=program_version_message)
-    parser.add_argument(
-        '-t',
-        '--timeout',
-        dest="con_timeout",
-        help="Timeout in seconds for the database requests. [default: %(default)s]",
-        metavar="TIMEOUT",
-        default=200)
-    parser.add_argument(
-        '-u',
-        '--user',
-        dest="con_user",
-        help="The user name you want to login with and do the administration stuff with. It will be prompted for a password.",
-        metavar="USER")
-    parser.add_argument('-c', '--connection_uri', dest="con_uri",
-                        help="The URI of the caosdb server.", metavar="URI")
-
     subparsers = parser.add_subparsers(
         title="commands",
         metavar="COMMAND",
@@ -555,20 +545,39 @@ USAGE
         metavar="ROLENAME",
         help="The name of the existing role.")
 
+    # entity acl
+    retrieve_entity_acl_parser = subparsers.add_parser(
+        "retrieve_entity_acl", help="Retrieve an entity ACL.")
+    retrieve_entity_acl_parser.set_defaults(call=do_retrieve_entity_acl)
+    retrieve_entity_acl_parser.add_argument(dest="query", metavar="QUERY",
+                                            help="A FIND query.")
+
+    for action in ["grant", "deny", "revoke_denial", "revoke_grant"]:
+        action_entity_permissions_parser = subparsers.add_parser(
+            "{}_entity_permissions".format(action),
+            help="{} entity permissions to a role.".format(action))
+        action_entity_permissions_parser.set_defaults(
+            call=do_action_entity_permissions, action=action)
+        action_entity_permissions_parser.add_argument(dest="query", metavar="QUERY",
+                                                      help="A FIND query.")
+        action_entity_permissions_parser.add_argument(dest="role", metavar="ROLE",
+                                                      help="The name of an exising role.")
+        action_entity_permissions_parser.add_argument(
+            dest="permissions",
+            metavar="PERMISSION",
+            help="A list of permissions",
+            nargs='+')
+        action_entity_permissions_parser.add_argument(
+            '--priority',
+            dest="priority",
+            action="store_true",
+            default=False,
+            help="This flag enables priority permission rules.")
+
     # Process arguments
     args = parser.parse_args()
 
-    VERBOSITY = args.verbose
-    timeout = int(args.con_timeout)
-
-    password = None
-    if args.con_user is not None:
-        password = getpass.getpass(prompt="login password: ")
-
-    db.configure_connection(url=args.con_uri, username=args.con_user,
-                            password=password, timeout=timeout)
-    db.get_connection()._debug = lambda: VERBOSITY
-    db.Container._debug = staticmethod(lambda: VERBOSITY)
+    db.configure_connection()._login()
 
     return args.call(args)
 
diff --git a/unittests/test_add_property.py b/unittests/test_add_property.py
index 267e7f00011d55dba4ca5876df383f26dbed1e4a..bd68f31b89c439c2bd333586b65d9f012b09d7e3 100644
--- a/unittests/test_add_property.py
+++ b/unittests/test_add_property.py
@@ -21,12 +21,7 @@
 #
 # ** end header
 #
-"""Created on 19.06.2017.
-
-@author: tf
-"""
 import caosdb as db
-# @UnresolvedImport
 from nose.tools import assert_is, assert_is_none, assert_equals, assert_is_not_none, assert_raises
 
 
diff --git a/unittests/test_administraction.py b/unittests/test_administraction.py
new file mode 100644
index 0000000000000000000000000000000000000000..dc05be2ac7c19ae066b9c8829677626796cea5fa
--- /dev/null
+++ b/unittests/test_administraction.py
@@ -0,0 +1,69 @@
+# -*- encoding: utf-8 -*-
+#
+# ** header v3.0
+# This file is a part of the CaosDB Project.
+#
+# Copyright (C) 2018 Research Group Biomedical Physics,
+# Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+# ** end header
+#
+"""Tests for the administration class."""
+# pylint: disable=missing-docstring
+from __future__ import unicode_literals
+from pytest import raises
+from caosdb import administration, configure_connection, get_connection
+from caosdb.connection.mockup import MockUpServerConnection, MockUpResponse
+
+
+def setup():
+    configure_connection(url="unittests", username="testuser",
+                         password="testpassword", timeout=200,
+                         implementation=MockUpServerConnection)
+
+
+def test_get_server_properties_success():
+    properties = "<Properties><TEST_PROP>TEST_VAL</TEST_PROP></Properties>"
+    get_connection()._delegate_connection.resources.append(
+        lambda **kwargs: MockUpResponse(200, {}, properties))
+    props = administration.get_server_properties()
+    assert isinstance(props, dict)
+
+
+def test_get_server_property_success():
+    properties = "<Properties><TEST_PROP>TEST_VAL</TEST_PROP></Properties>"
+    get_connection()._delegate_connection.resources.append(
+        lambda **kwargs: MockUpResponse(200, {}, properties))
+    assert "TEST_VAL" == administration.get_server_property("TEST_PROP")
+
+
+def test_get_server_property_key_error():
+    properties = "<Properties><TEST_PROP>TEST_VAL</TEST_PROP></Properties>"
+    get_connection()._delegate_connection.resources.append(
+        lambda **kwargs: MockUpResponse(200, {}, properties))
+    with raises(KeyError) as e:
+        assert administration.get_server_property("BLA")
+
+
+def test_set_server_property():
+    def check_form(**kwargs):
+        assert kwargs["path"] == "_server_properties"
+        assert kwargs["method"] == "POST"
+        assert kwargs["body"] == "TEST_PROP=TEST_VAL".encode()
+        assert kwargs["headers"]["Content-Type"] == "application/x-www-form-urlencoded"
+        return MockUpResponse(200, {}, "<Properties><TEST_PROP>TEST_VAL</TEST_PROP></Properties>")
+    get_connection()._delegate_connection.resources.append(check_form)
+    administration.set_server_property("TEST_PROP", "TEST_VAL")
diff --git a/unittests/test_configuration.py b/unittests/test_configuration.py
new file mode 100644
index 0000000000000000000000000000000000000000..76445b6f262120d6a29c73527a9bf042f85f8a05
--- /dev/null
+++ b/unittests/test_configuration.py
@@ -0,0 +1,40 @@
+# -*- encoding: utf-8 -*-
+#
+# ** header v3.0
+# This file is a part of the CaosDB Project.
+#
+# Copyright (C) 2018 Research Group Biomedical Physics,
+# Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+# ** end header
+#
+
+import caosdb as db
+from pytest import raises
+
+
+def test_config_ini_via_envvar():
+    from os import environ
+    from os.path import expanduser
+
+    with raises(KeyError):
+        environ["PYCAOSDBINI"]
+
+    environ["PYCAOSDBINI"] = "bla bla"
+    assert environ["PYCAOSDBINI"] == "bla bla"
+    assert db.configuration.configure(environ["PYCAOSDBINI"]) == []
+    environ["PYCAOSDBINI"] = "~/.pycaosdb.ini"
+    assert db.configuration.configure(expanduser(environ["PYCAOSDBINI"])) == [expanduser("~/.pycaosdb.ini")]
diff --git a/unittests/test_connection.py b/unittests/test_connection.py
index 06838d1c15b70787be159b4ad2d7f1bb70abe6c8..26e3388dfa4dd7d360b8a373d631f5a362990f66 100644
--- a/unittests/test_connection.py
+++ b/unittests/test_connection.py
@@ -92,6 +92,8 @@ def test_make_uri_path():
 
 
 def test_configure_connection():
+    if not get_config().has_section("Connection"):
+        get_config().add_section("Connection")
     get_config().set("Connection", "url", "https://host.de")
     get_config().set("Connection", "username", "test_username")
     get_config().set("Connection", "password", "test_password")