/php-uniauth

A PHP extension implementing universal user authentication session management

Primary LanguageC

php-uniauth - v1.1.1
--------------------------------------------------------------------------------
This PHP extension provides authentication session management via a uniauth
server. The extension implements an authentication flow designed to make user
authentication universal among applications talking to the same uniauth server.

The implementation consists of an extension that provides PHP userspace a
high-level interface for connecting with a uniauth server and manipulating
sessions.

Uniauth server implementations:

    *NOTE* The following implementation is used for this extension.

    Linux: https://git.rserver.us/network/uniauthd.git

Primary author:

    Roger Gee <rpg11a@acu.edu>

--------------------------------------------------------------------------------
The Uniauth Flow

Uniauth implements a user authentication flow for web applications. This flow
involves a persistent uniauth server and a stateless client. Whenever the client
needs to check user authentication, it connects to the server and queries a
session record by ID. Likewise, when the client needs to create and authenticate
a session, it uses the server to store and update the session information.

There are two roles in the flow taken by applications:

    1. applicant
    2. registrar

The applicant endpoint queries authentication status and, if none is found,
redirects to the registrar endpoint for registration, during which process
authentication occurs. The registrar then redirects the user-agent back to the
applicant, upon which event the applicant queries authentication status and
finds that it exists. This entire process happens transparently in the
applicant: the applicant does not have to handle both cases separately.

The registrar endpoint provides a means to collect user credentials and
authenticate users. Once the registrar has verified user credentials, it submits
the collected user ID and name (along with a display name) to the uniauth
server. The server assigns this information to an internal session, thus
registering the user as authenticated. Internally, this uniauth registration is
shared among all applications that use the registrar endpoint for the same user.

While the specifics of uniauth sessions may differ between server
implementations, the basic idea is that a single registration is maintained
among all applicants targeting the same registrar. The means that the server
internally connects the applicant and registrar sessions so that they point at
the same registration. This allows applicants from different domains
(i.e. having different session IDs) to utilize the same registration.

--------------------------------------------------------------------------------
Storage

A uniauth server maintains a database of authentication records that hold
information about the user session. Records are keyed by a session ID (sometimes
called a session key in this document). This ID may be provided by the userspace
script. If the userspace script does not provide a session ID, the PHP session
ID will be used as the uniauth session ID instead. (This means you must have
already called session_start() in your program).

    *NOTE* The extension does not actually manipulate the PHP session data
    itself if it uses the session ID. Instead it uses the configured session ID
    to key the uniauth records it creates with the server. This frees PHP
    userspace from having to track this information in its session. You can
    however still use the PHP session backend to store additional session
    values.

If a PHP session is not required, then a separate cookie can be used instead. To
avoid boilerplate associated with creating cookies and generating uniauth keys,
the uniauth_cookie() function is provided. This function generates a random
cookie session, overriding the default behavior of using the PHP session when
using the other extension functions. It also sets the cookie so it gets
transmitted to the user agent.

--------------------------------------------------------------------------------
PHP Userspace Functions Overview

Applicant Endpoint:

The core function used by applicants is uniauth(), which checks to see if a
registration exists for session (i.e. checks if the session is
authenticated). If not, it transparently redirects the user-agent to the
specified registrar endpoint. Otherwise, the function returns an associative
array containing the 'id', 'user' and 'display' records for the entry.

When an applicant redirects to a registrar, it passes the uniauth session ID via
a GET query parameter named 'uniauth'. This allows the registrar to identify the
target session that is to be associated with the registration should
authentication be successful.

Note: a uniauth session is considered authenticated by the standard when there
is a valid ID associated with the session (i.e. id >= 1).

A call to uniauth() is the minimum that is required for applicants. This call
will transparently begin the redirect flow.

Registrar Endpoint:

When calling a registrar endpoint, one of two things can happen.

1. There is no uniauth session for the registrar:

    In this case, a session must be created and authenticated. The registrar
    endpoint calls uniauth_apply() to begin this process. This function takes
    the query parameter passed from the applicant's call to uniauth() and stores
    it in a new uniauth session. It must set a cookie (possibly via
    uniauth_cookie()) or use the PHP session to track the new uniauth session.

    Now the registrar can present a login form or similar means to collect user
    credentials. When the credentials have been verified, the uniauth_register()
    function can be called with the correct information. This updates the
    registration associated with the registrar session. Once registration is
    complete, the registrar session is authenticated and ready to transfer.

    Finally, the uniauth_transfer() function is called to transfer the registrar
    session into the applicant session. Internally this updates the applicant
    session to point at the same registration as the registrar session. This
    function will automatically redirect the user-agent back to the original,
    applicant endpoint, thus "transferring" back to the original applicant
    endpoint.

2. There is already an authenticated uniauth session for the registrar:

    In this case the functionality should skip to calling uniauth_transfer().

    The uniauth_check() function is provided for the registrar endpoint so that
    it can check if an authenticated session exists. This should be done before
    calling uniauth_apply() in the former case. If 'true' is returned, then the
    registrar can skip to calling uniauth_transfer() (i.e. case #2 is true).

Logging Out:

To explictly invalidate a uniauth session, the uniauth_purge() API may be
employed. This function clears out the registration associated with the session
ID so the user login status is void. Note that this will log out all services
(i.e. applicants) that have sessions referencing the registration. The session
record is not technically freed until it expires naturally. This means the same
session IDs can be reused for future authentications until the user-agent drops
the cookie.

--------------------------------------------------------------------------------
PHP Userspace Functions Detail

    Generate notes:

        Unless a connection error occurs, all functions throw upon error. It is
        recommended that you wrap all uniauth calls in a try-catch block so as
        to report errors.

        Some functions have unusual side effects, such as setting superglobal
        values or cookies or aborting the script. Make sure you are aware of
        these.

    array uniauth([string $url, string $session_id])

        This function looks up an authenticated uniauth session.

        The function returns the session information as a login array if an
        authenticated session was found. If not, the function's behavior depends
        on whether an authentication endpoint url was specified:

            If an authentication endpoint url was specified, the function sends
            a redirect header pointing at the specified URL for the registrar
            endpoint. It then aborts the script.

            Otherwise (if url=null) the function just returns null, indicating
            that no authenticated session was available.

        The calling script has no awareness that a redirect occurred. Thus the
        redirect flow happens transparently.

        If the second parameter is specified, then the function uses the
        requested session ID. Otherwise, the current PHP session ID is used
        unless uniauth_cookie() was previously called.

            $url - The url of the registrar endpoint handling the
            authentication. This parameter may be null to avoid a redirect and
            just query the status of a uniauth session.

            $session_id - An override uniauth session ID to use in place of the
            default behavior.

        Return value: an array with the following keys pulled from the uniauth
        session:

            id - user tracking ID as determined by the registrar
            user - user handle as determined by the registrar
            display - user display name as determined by the registrar

        Returns mnull if no session was available and a redirect did not occur.

    bool uniauth_check([string $session_id])

        This function determines if an authenticated session exists. It does not
        update the session expiration.

            $session_id - Uniauth session ID to use (optional)

                The actual session ID used is determined in the same way as in
                the uniauth() function.

        Return value: true is returned if the specified session exists and is
        authenticated. False is returned if the specified session does not exist
        or exists but is not authenticated.

        NOTE: This function is largely obsolete in applicant implementations due
        to changes to the uniauth() function. Prefer calling uniauth(null) over
        using uniauth_check() when needing to conditionally obtain a session's
        login array.

            GOOD: $login = uniauth(null);

            BAD: if (uniauth_check()) $login = uniauth('http://auth.tld')
                 else $login = null;

    void uniauth_apply([string $session_id])

        This function creates a uniauth session for the registrar endpoint
        application (if it doesn't exist). The function annotates the new
        registrar session with the applicant session ID, which is passed in
        using a 'uniauth' query parameter in the request.

        This function should only be called in the initial GET request to the
        registrar endpoint. It must be called before any uniauth_transfer() call
        would succeed.

            $session_id - Uniauth session ID to use (optional)

                The actual session ID used is determined in the same way as in
                the uniauth() function.

        The session ID is determined in the same way as in the uniauth()
        function.

    void uniauth_register(int $id, string $name, string $display_name[, string $session_id, int $lifetime])

        This function is used to register (i.e. authenticate) a uniauth
        session. It assigns the specified user information into the
        current/specified uniauth session. After a successful call, the session
        is now authenticated.

            $id - Application-defined user ID for the session

            $name - Application-defined user name for the session

            $display_name - Application-defined user display name for the session

            $session_id - Uniauth session ID to use (optional)

                The actual session ID used is determined in the same way as in
                the uniauth() function.

            $lifetime - Defines the session lifetime starting from the current instant (optional)

                If this value is omitted or a non-positive number, then the
                uniauth session will have a lifetime equal to the value of the
                php.ini option "uniauth.lifetime" and the uniauth cookie (if
                any) is a persistent cookie. The default value for
                "uniauth.lifetime" is 86400, or 1 day; the value for this
                setting indicates the number of seconds for the lifetime.

                Otherwise the uniauth session has the specified lifetime and the
                uniauth cookie (if any) will be a session cookie.

    void uniauth_transfer([string $session_id])

        This function is used to transfer the information from one session
        (i.e. the source session) into another (i.e. the destination
        session). Internally this merely updates the destination session to
        point at the source session. Practically, the source session is the
        registrar session and the destination is the applicant session.

        The destination session ID is pulled from the source session. It was set
        previously in a call to uniauth_apply().

            $session_id - Uniauth session ID to use (optional)

                The actual session ID used is determined in the same way as in
                the uniauth() function.

        This function technically does not return and will bail out to perform the redirect. Otherwise it will throw an exception on failure.

    bool uniauth_purge([string $session_id])

        This functions ends the current uniauth session.

            $session_id - Uniauth session ID to use (optional)

                The actual session ID used is determined in the same way as in
                the uniauth() function.

        Note: this function merely invalidates the uniauth session. The session
        lifetime actually persists, which means the backend record can be reused
        in future authentication attempts within a certain amount of time. Any
        cookies used to track the session ID should also be preserved so as to
        avoid having to regenerate the session within a certain amount of time.

        Returns true if the session was valid and was invalidated, false
        otherwise.

    string uniauth_cookie()

        This is a convenience function used to eliminate boilerplate associated
        with when you want to use a simple cookie to track the session ID
        instead of the PHP session. This function will randomly generate a
        64-character ID and set it in a cookie with name="uniauth". If such a
        cookie already exists, it merely continues to use that session ID.

        Another vital behavior of this function is that it overrides the default
        behavior of most uniauth functions when determining the default session
        ID. Instead of using the PHP session by default, the functions' default
        behavior will be to use the uniauth cookie. For example:

            // This call will use the PHP session ID.
            session_start();
            uniauth("http://localhost/auth.php");

            // This call will use the generated uniauth cookie.
            uniauth_cookie();
            uniauth("http://localhost/auth.php");

        Return value: the function returns the session ID. Note that this value
        can also be grabbed from the $_COOKIE superglobal (without another
        request) since the function makes sure the cookie's value is set as part
        of its implementation.

        NOTE: using uniauth cookies will overwrite any existing cookies! You
        should always make uniauth calls before any other calls to set cookies!