Factory of decorators for limit the access to views.

        :tests: *function, optional
            One or more functions that takes the args and kwargs of the
            view and returns either `True` or `False`.
            All test must return True to show the view.

        Options:

        :role: str, optional
            Test for the user having a role with this name.

        :roles: list, optional
            Test for the user having **any** role in this list of names.

        :csrf: bool, None, optional
            If ``None`` (the default), the decorator will check the value
            of the CSFR token for POST, PUT or DELETE requests.
            If ``True`` it will do the same also for all requests.
            If ``False``, the value of the CSFR token will not be checked.

        :url_sign_in: str, function, optional
            If any required condition fail, redirect to this place.
            Override the default URL. This can also be a callable.

        :request: obj, optional
            Overwrite the request for testing.

        The rest of the ``key=value`` pairs in ``kwargs`` are interpreted as tests.
        The user must have a property `key` with a value equals to `value`.
        If the user has a method named `key`, that method is called with
        `value` as a single argument and must return True to show the view.

def protected(self, *tests, **kwargs):
        """Factory of decorators for limit the access to views.

        :tests: *function, optional
            One or more functions that takes the args and kwargs of the
            view and returns either `True` or `False`.
            All test must return True to show the view.

        Options:

        :role: str, optional
            Test for the user having a role with this name.

        :roles: list, optional
            Test for the user having **any** role in this list of names.

        :csrf: bool, None, optional
            If ``None`` (the default), the decorator will check the value
            of the CSFR token for POST, PUT or DELETE requests.
            If ``True`` it will do the same also for all requests.
            If ``False``, the value of the CSFR token will not be checked.

        :url_sign_in: str, function, optional
            If any required condition fail, redirect to this place.
            Override the default URL. This can also be a callable.

        :request: obj, optional
            Overwrite the request for testing.

        The rest of the ``key=value`` pairs in ``kwargs`` are interpreted as tests.
        The user must have a property `key` with a value equals to `value`.
        If the user has a method named `key`, that method is called with
        `value` as a single argument and must return True to show the view.

        """
        _role = kwargs.pop('role', None)
        _roles = kwargs.pop('roles', None) or []
        _csrf = kwargs.pop('csrf', None)
        _url_sign_in = kwargs.pop('url_sign_in', None)
        _request = kwargs.pop('request', None)

        if _role:
            _roles.append(_role)
        _roles = [to_unicode(r) for r in _roles]

        _tests = tests
        _user_tests = kwargs

        def decorator(f):
            @functools.wraps(f)
            def wrapper(*args, **kwargs):
                logger = logging.getLogger(__name__)
                request = _request or self.request or args and args[0]
                url_sign_in = self._get_url_sign_in(request, _url_sign_in)

                user = self.get_user()
                if not user:
                    return self._login_required(request, url_sign_in)

                if hasattr(user, 'has_role') and _roles:
                    if not user.has_role(*_roles):
                        logger.debug(u'User `{0}`: has_role fail'.format(user.login))
                        logger.debug(u'User roles: {0}'.format([r.name for r in user.roles]))
                        return self.wsgi.raise_forbidden()

                for test in _tests:
                    test_pass = test(user, *args, **kwargs)
                    if not test_pass:
                        logger.debug(u'User `{0}`: test fail'.format(user.login))
                        return self.wsgi.raise_forbidden()

                for name, value in _user_tests.items():
                    user_test = getattr(user, name)
                    test_pass = user_test(value, *args, **kwargs)
                    if not test_pass:
                        logger.debug(u'User `{0}`: test fail'.format(user.login))
                        return self.wsgi.raise_forbidden()

                disable_csrf = _csrf == False  # noqa
                if (not self.wsgi.is_idempotent(request) and not disable_csrf) or _csrf:
                    if not self.csrf_token_is_valid(request):
                        logger.debug(u'User `{0}`: invalid CSFR token'.format(user.login))
                        return self.wsgi.raise_forbidden("CSFR token isn't valid")

                return f(*args, **kwargs)
            return wrapper
        return decorator