Blog entries

  • Apache authentication

    2013/10/10 by Dimitri Papadopoulos

    An Apache front end might be useful, as Apache provides standard log files, monitoring or authentication. In our case, we have Apache authenticate users before they are cleared to access our CubicWeb application. Still, we would like user accounts to be managed within a CubicWeb instance, avoiding separate sets of identifiers, one for Apache and the other for CubicWeb.

    We have to address two issues:

    • have Apache authenticate users against accounts in the CubicWeb database,
    • have CubicWeb trust Apache authentication.

    Apache authentication against CubicWeb accounts

    A possible solution would be to access the identifiers associated to a CubicWeb account at the SQL level, directly from the SQL database underneath a CubicWeb instance. The login password can be found in the cw_login and cw_upassword columns of the cw_cwuser table. The benefit is that we can use existing Apache modules for authentication against SQL databases, typically mod_authn_dbd. On the other hand this is highly dependant on the underlying SQL database.

    Instead we have chosen an alternate solution, directly accessing the CubicWeb repository. Since we need Python to access the repository, our sysasdmins have deployed mod_python on our Apache server.

    We wrote a Python authentication module that accesses the repository using ZMQ. Thus ZMQ needs be enabled. To enable ZMQ uncomment and complete the following line in all-in-one.conf:

    zmq-repository-address=zmqpickle-tcp://localhost:8181
    

    The Python authentication module looks like:

    from mod_python import apache
    from cubicweb import dbapi
    from cubicweb import AuthenticationError
    
    def authenhandler(req):
        pw = req.get_basic_auth_pw()
        user = req.user
    
        database = 'zmqpickle-tcp://localhost:8181'
        try:
            cnx = dbapi.connect(database, login=user, password=pw)
        except AuthenticationError:
            return apache.HTTP_UNAUTHORIZED
        else:
            cnx.close()
            return apache.OK
    

    CubicWeb trusts Apache

    Our sysadmins set up Apache to add x-remote-user to the HTTP headers forwarded to CubicWeb - more on the relevant Apache configuration in the next paragraph.

    We then add the cubicweb-trustedauth cube to the dependencies of our CubicWeb application. We simply had to add to the __pkginfo__.py file of our CubicWeb application:

    __depends__ =  {
        'cubicweb': '>= 3.16.1',
        'cubicweb-trustedauth': None,
    }
    

    This cube gets CubicWeb to trust the x-remote-user header sent by the Apache front end. CubicWeb bypasses its own authentication mechanism. Users are directly logged into CubicWeb as the user with a login identical to the Apache login.

    Apache configuration and deployment

    Our Apache configuration looks like:

    <Location /apppath >
      AuthType Basic
      AuthName "Restricted Area"
      AuthBasicAuthoritative Off
      AuthUserFile /dev/null
      require valid-user
    
      PythonAuthenHandler cubicwebhandler
    
      RewriteEngine On
      RewriteCond %{REMOTE_USER} (.*)
      RewriteRule . - [E=RU:%1]
    <Location /apppath >
    
    RequestHeader set X-REMOTE-USER %{RU}e
    
    ProxyPass          /apppath  http://127.0.0.1:8080
    ProxyPassReverse   /apppath  http://127.0.0.1:8080
    

    The CubicWeb application is accessed as http://ourserver/apppath/.

    The Python authentication module is deployed as /usr/lib/python2.7/dist-packages/cubicwebhandler/handler.py where cubicwebhandler is the attribute associated to PythonAuthenHandler in the Apache configuration.


  • Using RQL's HAVING clause to by-pass limitation of the WHERE clause

    2010/06/09 by Sylvain Thenault

    The HAVING clause, as in SQL, has been originally introduced to restrict a query according to value returned by an aggregat function, e.g.:

    Any X GROUPBY X WHERE X relation Y HAVING COUNT(Y) > 10
    

    It may however be used for something else...

    For instance, let's say you want to get people whose uppercased first name equals to another person uppercased first name. Since in the WHERE clause, we are limited to 3-expression (<subject> <relation> <object>), such thing can't be expressed (believe me or try it out). But this can be expressed using HAVING comparison expression:

    Person X WHERE X firstname XFN, Y firstname YFN HAVING X > Y, UPPER(XFN) = UPPER(YFN)
    

    Nice, no? This open some new possibilities. Another example:

    Person X WHERE X birthday XB HAVING YEAR(XB) = 2000
    

    Get it? That lets you use transformation functions not only in selection but for restriction as well, which was the major flaw in the RQL language.

    Notice that while we would like this to work without the HAVING clause, this can't be currently be done because it introduces an ambiguity in RQL's grammar that can't be handled by yapps, the parser's generator we're using.


  • Deactivating the 'reledit' feature

    2010/06/09 by Sylvain Thenault

    The 'reledit' feature is the one that makes attributes/relations editable in entity's primary view for authorized users (you know, the pen that appears when your mouse is over a field's value, clicking on it making a form to edit this field appears).

    This is a nice feature, but you may not want it. It can be easily deactivated everywhere it's used automatically in the site by using the code snippet below:

    from cubicweb.web.views import editforms
    
    class DeactivatedAutoClickAndEditFormView(editforms.AutoClickAndEditFormView):
        def should_edit_attribute(self, entity, rschema, form):
            return False
    
        def should_edit_relation(self, entity, rschema, role, rvid):
            return False
    
    def registration_callback(vreg):
        vreg.register_and_replace(DeactivatedAutoClickAndEditFormView,
                                  editforms.AutoClickAndEditFormView)