Uploaded image for project: 'mod_python'
  1. mod_python
  2. MODPYTHON-124

Improvements associated with the req.ap_auth_type attribute.

    Details

    • Type: Improvement
    • Status: Closed
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: 3.3.x
    • Fix Version/s: 3.3.1
    • Component/s: core
    • Labels:
      None

      Description

      The "req.ap_auth_type" attribute is set to the authentication type corresponding to the type of authentication processing successfully carried out in respect of a request. For example, if one has Apache configuration:

      AuthType Basic
      AuthName "Restricted Files"
      AuthUserFile /usr/local/apache/passwd/passwords
      Require valid-user

      it is expected that the request uses basic authentication header as appropriate. These headers will be dealt with by inbuilt Apache core module. Upon successful authentication, the Apache core module will set "req.ap_auth_type" attribute to be "Basic" and set "req.user" to the user ID of the logged in user.

      If instead Apache support for digest authentication was used, eg:

      AuthType Digest
      ...

      then "req.ap_auth_type" attribute will be set to "Digest".

      If authentication was not requested, ie., no AuthType directive, the "req.ap_auth_type" is set to Python None.

      The intent is that you should be able to implement authentication handlers in mod_python using PythonAuthenHandler, but you can't actually do this correctly at the moment as there are a few things missing.

      Firstly, in order to trigger the PythonAuthenHandler, you must still define the AuthType/AuthName/Require directives. In order to ensure that our authentication handler is triggered and not the builtin ones or some other one, the AuthType directive should specify a string other than "Basic" or "Digest". This would be a name we choose and can basically be anything. For example, you might choose a descriptive name like "Python-Basic-DBM" to denote basic authentication is used against a DBM database but using the Python authentication handler.

      AuthType Python-Basic-DBM
      AuthName "Web Application"
      Require valid-user

      PythonAuthenHandler basicdbmauth
      PythonOption basicdbmauth.UserDatabase /.../users.dbm

      When the authentication handler in "basicdbmauth" is called, the "req.ap_auth_type" field is still None. This is because authentication hasn't succeed yet.

      In terms of being able to implement the authentication handler correctly, the first problem is that there is no way to access the actual value associated with the AuthType directive. This needs to be consulted to determine if the authentication handler should actually do anything. Second is that the value associated with the AuthName directive can't be determined either, something which may influence against which database authentication should be done.

      Thus first lot of changes that need to be made are that "req" object needs to have two new methods called "get_auth_type()" and "get_auth_name()". These will map to the Apache API functions called "ap_auth_type()" and "ap_auth_name()". Note that "ap_auth_type()" is returning a different value to "req.ap_auth_type".

      With those two functions, authentication handler can then be written as:

      def authenhandler(req):
      if req.get_auth_type() != "Python-Basic-DBM":
      return apache.DECLINED

      realm = req.get_auth_name()

      1. Do all the processing of Authorization header and
      2. validate user etc. If not okay, return appropriate error
      3. status. If okay, keep going.

      req.user = ... from header
      req.ap_auth_type = "Python-Basic-DBM"

      return apache.OK

      As well as returning apache.OK, convention is to set "req.user" and "req.ap_auth_type".

      This is where the final problem occurs. That is that "req.ap_auth_type" is read only and cannot actually be set as necessary.

      Thus in addition to "req.get_auth_type()", "req.get_auth_name()", need to make "req.ap_auth_type" writable.

      Having made these changes it would then actually be possible to write authentication handlers correctly, ie., whereby they correctly look at AuthType etc to see whether they should be applied.

        Activity

        Hide
        grahamd Graham Dumpleton added a comment -

        FWIW, where example gave:

        1. Do all the processing of Authorization header and
        2. validate user etc. If not okay, return appropriate error
        3. status. If okay, keep going.

        req.user = ... from header
        req.ap_auth_type = "Python-Basic-DBM"

        If "req.get_basic_auth_pw()" were used to do the decoding of the "Authorization" header, the "req.user" and "req.ap_auth_type" fields would have been automatically populated with the user ID and auth type of "Basic" respectively.

        The "req.ap_auth_type" attribute still needs to be writable though if it was desired that totally new or unsupported authorisation schemes needed to be implemented.

        Show
        grahamd Graham Dumpleton added a comment - FWIW, where example gave: Do all the processing of Authorization header and validate user etc. If not okay, return appropriate error status. If okay, keep going. req.user = ... from header req.ap_auth_type = "Python-Basic-DBM" If "req.get_basic_auth_pw()" were used to do the decoding of the "Authorization" header, the "req.user" and "req.ap_auth_type" fields would have been automatically populated with the user ID and auth type of "Basic" respectively. The "req.ap_auth_type" attribute still needs to be writable though if it was desired that totally new or unsupported authorisation schemes needed to be implemented.
        Hide
        grahamd Graham Dumpleton added a comment -

        Whoops, stuffed up what the names should be. They should be:

        req.auth_name()
        req.auth_type()

        If "get_" prefix is used, breaks with existing convention as to how names in request object map to Apache API functions. Thus:

        def authenhandler(req):
        if req.auth_type() != "Python-Basic-DBM":
        return apache.DECLINED

        realm = req.auth_name()

        1. Do all the processing of Authorization header and
        2. validate user etc. If not okay, return appropriate error
        3. status. If okay, keep going.

        req.user = ... from header
        req.ap_auth_type = "Python-Basic-DBM"

        return apache.OK

        Show
        grahamd Graham Dumpleton added a comment - Whoops, stuffed up what the names should be. They should be: req.auth_name() req.auth_type() If "get_" prefix is used, breaks with existing convention as to how names in request object map to Apache API functions. Thus: def authenhandler(req): if req.auth_type() != "Python-Basic-DBM": return apache.DECLINED realm = req.auth_name() Do all the processing of Authorization header and validate user etc. If not okay, return appropriate error status. If okay, keep going. req.user = ... from header req.ap_auth_type = "Python-Basic-DBM" return apache.OK
        Hide
        grahamd Graham Dumpleton added a comment -

        Changes to add req.auth_name(), req.auth_type() and make req.ap_auth_type writable commited into mod_python SVN trunk in revsion 378864.

        Show
        grahamd Graham Dumpleton added a comment - Changes to add req.auth_name(), req.auth_type() and make req.ap_auth_type writable commited into mod_python SVN trunk in revsion 378864.
        Hide
        jgallacher Jim Gallacher added a comment -

        I've been playing around with the changes implemented here and I like it.

        However I wonder why auth_name and auth_type are methods of request instead of members?

        Also, auth_type() and ap_auth_type both give access to AuthType, which I think is confusing. Why do we need both?

        I'm not in favour of the ap_auth_type name as I think this may be one of the few places where we prepend ap_ to a method or attribute. This exposes an underlying implementation detail which is not of interest to the user and makes it more difficult to find in the documentation index.

        I'll upload a patch of an alternative implemenation.

        Show
        jgallacher Jim Gallacher added a comment - I've been playing around with the changes implemented here and I like it. However I wonder why auth_name and auth_type are methods of request instead of members? Also, auth_type() and ap_auth_type both give access to AuthType, which I think is confusing. Why do we need both? I'm not in favour of the ap_auth_type name as I think this may be one of the few places where we prepend ap_ to a method or attribute. This exposes an underlying implementation detail which is not of interest to the user and makes it more difficult to find in the documentation index. I'll upload a patch of an alternative implemenation.
        Hide
        grahamd Graham Dumpleton added a comment -

        req.ap_auth_type is called what it is and is a member as that is what it is called in the request_rec struture. I didn't prepend it with "ap_". See:

        http://docx.webperf.org/structrequest__rec.html

        I agree that it looks strange, but I kept the convention of preserving the names as they appear in the request_rec structure. It is the only member in request_rec that has such a prefix.

        req.auth_type() and req.auth_name() are functions as that reflects the fact that they are actually functions in the Apache API. See:

        http://httpd.apache.org/dev/apidoc/apidoc_ap_auth_type.html
        http://httpd.apache.org/dev/apidoc/apidoc_ap_auth_name.html

        Again, thus followed convention as I saw it reflected in implementation of requestobject. Ie., for a function drop the 'ap_' prefix.

        Note that req.ap_auth_type and req.auth_type() are not the same thing.

        The req.auth_type() function returns the value associated with the AuthType directive.

        The req.ap_auth_type member of the request_rec initially starts out as None. One of the things that an authentication handler will do if it handles the authentication type returned by req.auth_type() is to set req.ap_auth_type to be not None. Presumably it would be set to same value as returned by req.auth_type() at that point. It would also set req.user.

        Thus, the req.ap_auth_type being non None is an indicator that an authentication module has processed the authentication for the request and also indicates who it was.

        That the req.ap_auth_type member kept the 'ap_' prefix by convention was a blessing, else there would have been a clash on the use of the "auth_type" name and one would have had to break the convention that seems to exist for this one case.

        Show
        grahamd Graham Dumpleton added a comment - req.ap_auth_type is called what it is and is a member as that is what it is called in the request_rec struture. I didn't prepend it with "ap_". See: http://docx.webperf.org/structrequest__rec.html I agree that it looks strange, but I kept the convention of preserving the names as they appear in the request_rec structure. It is the only member in request_rec that has such a prefix. req.auth_type() and req.auth_name() are functions as that reflects the fact that they are actually functions in the Apache API. See: http://httpd.apache.org/dev/apidoc/apidoc_ap_auth_type.html http://httpd.apache.org/dev/apidoc/apidoc_ap_auth_name.html Again, thus followed convention as I saw it reflected in implementation of requestobject. Ie., for a function drop the 'ap_' prefix. Note that req.ap_auth_type and req.auth_type() are not the same thing. The req.auth_type() function returns the value associated with the AuthType directive. The req.ap_auth_type member of the request_rec initially starts out as None. One of the things that an authentication handler will do if it handles the authentication type returned by req.auth_type() is to set req.ap_auth_type to be not None. Presumably it would be set to same value as returned by req.auth_type() at that point. It would also set req.user. Thus, the req.ap_auth_type being non None is an indicator that an authentication module has processed the authentication for the request and also indicates who it was. That the req.ap_auth_type member kept the 'ap_' prefix by convention was a blessing, else there would have been a clash on the use of the "auth_type" name and one would have had to break the convention that seems to exist for this one case.

          People

          • Assignee:
            grahamd Graham Dumpleton
            Reporter:
            grahamd Graham Dumpleton
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development