Gallery2:Modules:httpauth - Gallery Codex
Personal tools

Gallery2:Modules:httpauth

From Gallery Codex

Description

Login using HTTP authentication.

Features

  • Supports HTTP Basic authentication directly, using the Authorization request header and WWW-Authenticate response header.
  • Supports web server authentication, using the REMOTE_USER environment variable.

Server Authentication

To use Kerberos as a server-authentication mechanism, please add this to your .htaccess file:

<Location /gallery2>
    AuthType Kerberos
    Require valid-user
</Location>

And configure your HTTP Auth module to use server-auth in site admin -> HTTP Auth.

Logout

Because most web browsers cache HTTP auth credentials, the Gallery logout link didn't work as expected after logging in with HTTP auth. Gallery correctly logged out the active user but the web browser simply logged in again with the next request.

To work around this, the HTTP auth module listens for the Gallery::Logout event and delegates to the httpauth.TryLogout page if necessary: http://gallery.svn.sourceforge.net/viewvc/gallery/trunk/gallery2/modules/httpauth/TryLogout.inc?view=markup

The TryLogout page tries clearing the browser's authentication cache by as many tricks possible:

  • Ask browser to authenticate with bogus authtype:
GalleryUtilities::setResponseHeader('HTTP/1.0 401 Unauthorized', false);
GalleryUtilities::setResponseHeader('WWW-Authenticate: Bogus', false);
  • Redirect with random username and password. This won't actually clear the browser's authentication cache but will replace it with an invalid username and password. Since Gallery ignores invalid HTTP auth credentials, this effectively logs the user out.
  • Clear Internet Explorer's authentication cache with JavaScript:
 try {ldelim}
   {* http://msdn.microsoft.com/workshop/author/dhtml/reference/constants/clearauthenticationcache.asp *}
   document.execCommand("ClearAuthenticationCache");
 {rdelim} catch (exception) {ldelim}
 {rdelim}

The TryLogout page redirects to the FinishLogout page for two resons:

  1. To replace the browser's authentication cache with an invalid username and password
  2. To check that the user was indeed logged out. If the user was logged out, the FinishLogout page redirects back to the Gallery application. Otherwise it displays a warning advising the user to manually clear their authentication cache (Clear Private Data in Firefox).

The TryLogout page redirects to the FinishLogout page using JavaScript and falls back on a manual link. It can't use a 302 Found status because the page needs to load for the Internet Explorer JavaScript to execute and because we can't put an invalid username and password in a Location: header.

Authorization Header

For security, Apache doesn't pass the Authorization: HTTP header to CGI scripts unless built with SECURITY_HOLE_PASS_AUTHORIZATION

server/util_script.c:

#ifndef SECURITY_HOLE_PASS_AUTHORIZATION
        else if (!strcasecmp(hdrs[i].key, "Authorization")
                 || !strcasecmp(hdrs[i].key, "Proxy-Authorization")) {
            continue;
        }
#endif

Consequently the HTTP auth module works with mod_php but not PHP CGI. To work around this, the HTTP auth module defines a URL rewrite rule to put the contents of the Authorization: HTTP header in a request variable:

    /**
     * @see GalleryModule::getRewriteRules
     */
    function getRewriteRules() {
        $rules = array();

        /*
         * Only define the rule to pass the Authorization header to Gallery in a request variable if
         * it is already active, or if Gallery can't access HTTP usernames and passwords
         */
        list ($ret, $rewriteApi) = GalleryCoreApi::newFactoryInstance('RewriteApi');
        if ($ret) {
            $gallery->debug('Error in HttpAuthModule::getRewriteRules: ' . $ret->getAsText());
            return $rules;
        }
        if (!isset($rewriteApi)) {
            return $rules;
        }

        list ($ret, $isCompatible) = $rewriteApi->isCompatibleWithApi(array(1, 1));
        if ($ret) {
            $gallery->debug('Error in HttpAuthModule::getRewriteRules: ' . $ret->getAsText());
            return $rules;
        }
        if (!$isCompatible) {
            return $rules;
        }

        list ($ret, $activeRules) = $rewriteApi->fetchActiveRulesForModule($this->getId());
        if ($ret) {
            $gallery->debug('Error in HttpAuthModule::getRewriteRules: ' . $ret->getAsText());
            return $rules;
        }
        if (!in_array('authorization', $activeRules)) {
            /* Check that Gallery can access HTTP usernames and passwords */
            GalleryCoreApi::requireOnce('modules/httpauth/classes/HttpAuthHelper.class');
            list ($ret, $success) = HttpAuthHelper::checkHttpAuth();
            if ($ret) {
                $gallery->debug('Error in HttpAuthModule::getRewriteRules: ' . $ret->getAsText());
                return $rules;
            }
            if ($success) {
                return $rules;
            }
        }

        /* Pass the Authorization header to Gallery in a request variable */
        $rules['authorization'] = array(
            'comment' => $this->translate('Authorization Header'),
            'help' => $this->translate(
                'Pass the Authorization header to Gallery in a request variable.'),
            'keywords' => array(
                'authorization' => array(
                    'pattern' => '(.+)',
                    'help' => $this->translate('Authorization header.'))),
            'conditions' => array(
                array('test' => 'HTTP:Authorization',
                      'pattern' => '%authorization%'),
                array('test' => 'QUERY_STRING',
                      'pattern' => '!' . GalleryUtilities::prefixFormVariable('authorization')
                          . '=')),
            'options' => array('baseUrl' => '%{REQUEST_URI}'),
            'flags' => array('QSA'));

        return $rules;
    }

If the Authorization: HTTP header is not defined, the HTTP auth module tries to get the username and password from the request variable:

    /**
     * Get the HTTP authtype, username, and password using either the PHP server variables or the
     * authorization request variable.
     * @return array string HTTP authtype
     *               string HTTP username
     *               string HTTP password
     */
    function getHttpAuth() {
        $authtype = GalleryUtilities::getServerVar('AUTH_TYPE');
        $username = GalleryUtilities::getServerVar('PHP_AUTH_USER');
        $password = GalleryUtilities::getServerVar('PHP_AUTH_PW');

        if (empty($username)) {
            $authorization = GalleryUtilities::getServerVar('HTTP_AUTHORIZATION');
            if (empty($authorization)) {
                $authorization = GalleryUtilities::getRequestVariables('authorization');
                if (empty($authorization)) {
                    return array($authtype, $username, $password);
                }
            }

            list ($authtype, $authdata) = explode(' ', $authorization);
            list ($username, $password) = explode(':', base64_decode($authdata));
            if (empty($username)) {
                return array($authtype, $username, $password);
            }
        }

        /* AUTH_TYPE is often not defined, assume a default */
        if (empty($authtype)) {
            $authtype = 'Basic';
        }

        return array($authtype, $username, $password);
    }

Troubleshooting

Missing HTTP Authorization

HTTP usernames and passwords are sent in the Authorization request header, but some server configurations don't pass the Authorization header to scripts, e.g. Apache doesn't pass the Authorization header to CGI scripts unless it's built with '-D SECURITY_HOLE_PASS_AUTHORIZATION'.

Alternatively, we can pass the Authorization header to Gallery in a request variable using Apache mod_rewrite. http://httpd.apache.org/docs/2.2/rewrite/

URL rewrite module disabled

The URL rewrite module is needed to automatically pass the Authorization header to Gallery in a request variable.

Bad URL rewrite configuration

A preGallery URL rewrite parser is needed to automatically pass the Authorization header to Gallery in a request variable.

'Authorization Header' rule disabled

The URL rewrite rule which automatically passes the Authorization header to Gallery in a request variable is disabled.

Alternatively, if you use Apache mod_rewrite, you can manually add to your Gallery .htaccess file:

RewriteCond %{HTTP:Authorization} (.+)
RewriteCond %{QUERY_STRING} !g2_authorization=
RewriteRule .   %{REQUEST_URI}?g2_authorization=%1   [QSA]

TODO

  • Add a request variable or short URL so sites can define authentication for some requests but not others
  • Add self registration for server auth plugin which ignores username and password
  • Add HTTP auth login page
  • Support digest authentication (feature of PHP 5.1 which Gallery will require after the goPHP5 deadline)