TigerZF
🌐Español

53.3. Zend_OpenId_Provider

Zend_OpenId_Provider puede usarse para implementar servidores OpenID. Este capítulo ofrece ejemplos que muestran cómo construir un servidor muy básico. Sin embargo, para la implementación de un servidor OpenID de producción (como www.myopenid.com) puede que tenga que lidiar con problemas más complejos.

53.3.1. Inicio rápido

El siguiente ejemplo incluye código para crear una cuenta de usuario usando Zend_OpenId_Provider::register. El elemento link con rel="openid.server" apunta a nuestro propio script de servidor. Si envía esta identidad a un sitio habilitado para OpenID, se realizará la autenticación en este servidor.

El código antes de la etiqueta <html> es solo un truco que crea automáticamente una cuenta de usuario. No necesitará ese código cuando use identidades reales.

Ejemplo 53.11. La identidad

<?php
// Set up test identity
define("TEST_SERVER", Zend_OpenId::absoluteURL("example-8.php"));
define("TEST_ID", Zend_OpenId::selfURL());
define("TEST_PASSWORD", "123");
$server = new Zend_OpenId_Provider();
if (!$server->hasUser(TEST_ID)) {
    $server->register(TEST_ID, TEST_PASSWORD);
}
?>
<html><head>
<link rel="openid.server" href="<?php echo TEST_SERVER;?>" />
</head><body>
<?php echo TEST_ID;?>
</body></html>

El siguiente script de servidor de identidad maneja dos tipos de solicitudes de sitios habilitados para OpenID (para asociación y autenticación). Ambos son gestionados por el mismo método: Zend_OpenId_Provider::handle. Los dos argumentos del constructor de Zend_OpenId_Provider son URLs de las páginas de inicio de sesión y confianza, que solicitan entrada del usuario final.

En caso de éxito, el método Zend_OpenId_Provider::handle devuelve una cadena que debe pasarse de vuelta al sitio habilitado para OpenID. En caso de fallo, devuelve FALSE. Este ejemplo devolverá una respuesta HTTP 403 si Zend_OpenId_Provider::handle falla. Obtendrá esta respuesta si abre este script con un navegador web, porque envía una solicitud que no cumple con OpenID.

Ejemplo 53.12. Proveedor de identidad simple

$server = new Zend_OpenId_Provider("example-8-login.php",
                                   "example-8-trust.php");
$ret = $server->handle();
if (is_string($ret)) {
    echo $ret;
} else if ($ret !== true) {
    header('HTTP/1.0 403 Forbidden');
    echo 'Forbidden';
}

[Note] Nota

Es una buena idea usar una conexión segura (HTTPS) para estos scripts, especialmente para los siguientes scripts interactivos, para evitar la divulgación de contraseñas.

El siguiente script implementa una pantalla de inicio de sesión para un servidor de identidad usando Zend_OpenId_Provider y redirige a esta página cuando un usuario requerido aún no ha iniciado sesión. En esta página, un usuario introducirá su contraseña para iniciar sesión.

Debe usar la contraseña "123" que se usó en el script de identidad anterior.

Al enviar, el script llama a Zend_OpenId_Provider::login con la identidad y contraseña del usuario aceptado, y luego redirige de vuelta al script principal del proveedor de identidad. En caso de éxito, el método Zend_OpenId_Provider::login establece una sesión entre el usuario y el proveedor de identidad y almacena la información sobre el usuario, que ahora ha iniciado sesión. Todas las solicitudes siguientes del mismo usuario no requerirán un procedimiento de inicio de sesión, incluso si provienen de otro sitio web habilitado para OpenID.

[Note] Nota

Tenga en cuenta que esta sesión es solo entre el usuario final y el proveedor de identidad. Los sitios habilitados para OpenID no saben nada de ella.

Ejemplo 53.13. Pantalla de inicio de sesión simple

<?php
$server = new Zend_OpenId_Provider();

if ($_SERVER['REQUEST_METHOD'] == 'POST' &&
    isset($_POST['openid_action']) &&
    $_POST['openid_action'] === 'login' &&
    isset($_POST['openid_identifier']) &&
    isset($_POST['openid_password'])) {
    $server->login($_POST['openid_identifier'],
                   $_POST['openid_password']);
    Zend_OpenId::redirect("example-8.php", $_GET);
}
?>
<html>
<body>
<form method="post">
<fieldset>
<legend>OpenID Login</legend>
<table border=0>
<tr>
<td>Name:</td>
<td>
<input type="text"
       name="openid_identifier"
       value="<?php echo htmlspecialchars($_GET['openid_identity']);?>">
</td>
</tr>
<tr>
<td>Password:</td>
<td>
<input type="text"
       name="openid_password"
       value="">
</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>
<input type="submit"
       name="openid_action"
       value="login">
</td>
</tr>
</table>
</fieldset>
</form>
</body>
</html>

El hecho de que el usuario ya haya iniciado sesión no significa que la autenticación deba tener éxito necesariamente. El usuario puede decidir no confiar en sitios habilitados para OpenID particulares. La siguiente pantalla de confianza permite al usuario final tomar esa decisión. Esta elección puede hacerse únicamente para las solicitudes actuales o para siempre. En el segundo caso, la información sobre sitios de confianza/no confianza se almacena en una base de datos interna, y todas las siguientes solicitudes de autenticación de este sitio se manejarán automáticamente sin interacción del usuario.

Ejemplo 53.14. Pantalla de confianza simple

<?php
$server = new Zend_OpenId_Provider();

if ($_SERVER['REQUEST_METHOD'] == 'POST' &&
    isset($_POST['openid_action']) &&
    $_POST['openid_action'] === 'trust') {

    if (isset($_POST['allow'])) {
        if (isset($_POST['forever'])) {
            $server->allowSite($server->getSiteRoot($_GET));
        }
        $server->respondToConsumer($_GET);
    } else if (isset($_POST['deny'])) {
        if (isset($_POST['forever'])) {
            $server->denySite($server->getSiteRoot($_GET));
        }
        Zend_OpenId::redirect($_GET['openid_return_to'],
                              array('openid.mode'=>'cancel'));
    }
}
?>
<html>
<body>
<p>A site identifying as
<a href="<?php echo htmlspecialchars($server->getSiteRoot($_GET));?>">
<?php echo htmlspecialchars($server->getSiteRoot($_GET));?>
</a>
has asked us for confirmation that
<a href="<?php echo htmlspecialchars($server->getLoggedInUser());?>">
<?php echo htmlspecialchars($server->getLoggedInUser());?>
</a>
is your identity URL.
</p>
<form method="post">
<input type="checkbox" name="forever">
<label for="forever">forever</label><br>
<input type="hidden" name="openid_action" value="trust">
<input type="submit" name="allow" value="Allow">
<input type="submit" name="deny" value="Deny">
</form>
</body>
</html>

Los servidores OpenID de producción normalmente admiten la Simple Registration Extension, que permite a los consumidores solicitar cierta información sobre el usuario al proveedor. En este caso, la página de confianza puede extenderse para permitir la introducción de los campos solicitados o la selección de un perfil de usuario específico.

53.3.2. Scripts de proveedor combinados

Es posible combinar toda la funcionalidad del proveedor en un solo script. En este caso, las URLs de inicio de sesión y confianza se omiten, y Zend_OpenId_Provider asume que apuntan a la misma página con el argumento GET adicional "openid.action".

[Note] Nota

El siguiente ejemplo no está completo. No proporciona código de interfaz gráfica para el usuario; en su lugar, realiza un inicio de sesión automático y una relación de confianza automática. Esto se hace solo para simplificar el ejemplo; un servidor de producción debería incluir algo de código de los ejemplos anteriores.

Ejemplo 53.15. Todo junto

$server = new Zend_OpenId_Provider();

define("TEST_ID", Zend_OpenId::absoluteURL("example-9-id.php"));
define("TEST_PASSWORD", "123");

if ($_SERVER['REQUEST_METHOD'] == 'GET' &&
    isset($_GET['openid_action']) &&
    $_GET['openid_action'] === 'login') {
    $server->login(TEST_ID, TEST_PASSWORD);
    unset($_GET['openid_action']);
    Zend_OpenId::redirect(Zend_OpenId::selfUrl(), $_GET);
} else if ($_SERVER['REQUEST_METHOD'] == 'GET' &&
    isset($_GET['openid_action']) &&
    $_GET['openid_action'] === 'trust') {
    unset($_GET['openid_action']);
    $server->respondToConsumer($_GET);
} else {
    $ret = $server->handle();
    if (is_string($ret)) {
        echo $ret;
    } else if ($ret !== true) {
        header('HTTP/1.0 403 Forbidden');
        echo 'Forbidden';
    }
}

Si compara este ejemplo con los ejemplos anteriores divididos en páginas separadas, verá solo una diferencia además del código de despacho: unset($_GET['openid_action']). Esta llamada a unset() es necesaria para enrutar la siguiente solicitud al manejador principal.

53.3.3. Simple Registration Extension

De nuevo, el código antes de la etiqueta <html> es solo un truco para demostrar la funcionalidad. Crea una nueva cuenta de usuario y la asocia con un perfil (apodo y contraseña). Estos trucos no son necesarios en proveedores desplegados donde los usuarios finales se registran en servidores OpenID y completan sus perfiles. Implementar esta interfaz gráfica queda fuera del alcance de este manual.

Ejemplo 53.16. Identidad con perfil

<?php
define("TEST_SERVER", Zend_OpenId::absoluteURL("example-10.php"));
define("TEST_ID", Zend_OpenId::selfURL());
define("TEST_PASSWORD", "123");
$server = new Zend_OpenId_Provider();
if (!$server->hasUser(TEST_ID)) {
    $server->register(TEST_ID, TEST_PASSWORD);
    $server->login(TEST_ID, TEST_PASSWORD);
    $sreg = new Zend_OpenId_Extension_Sreg(array(
        'nickname' =>'test',
        'email' => 'test@test.com'
    ));
    $root = Zend_OpenId::absoluteURL(".");
    Zend_OpenId::normalizeUrl($root);
    $server->allowSite($root, $sreg);
    $server->logout();
}
?>
<html>
<head>
<link rel="openid.server" href="<?php echo TEST_SERVER;?>" />
</head>
<body>
<?php echo TEST_ID;?>
</body>
</html>

Ahora debería pasar esta identidad al sitio web habilitado para OpenID (use el ejemplo de la Simple Registration Extension de la sección anterior), y este debería usar el siguiente script de servidor OpenID.

Este script es una variación del script del ejemplo "Todo junto". Usa el mismo mecanismo de inicio de sesión automático, pero no contiene ningún código para una página de confianza. El usuario ya confía para siempre en los scripts de ejemplo. Esta confianza fue establecida llamando al método Zend_OpenId_Provider::allowSite() en el script de identidad. El mismo método asocia el perfil con la URL de confianza. Este perfil se devolverá automáticamente ante una solicitud de la URL de confianza.

Para hacer que la Simple Registration Extension funcione, simplemente debe pasar una instancia de Zend_OpenId_Extension_Sreg como segundo argumento del método Zend_OpenId_Provider::handle().

Ejemplo 53.17. Proveedor con SREG

$server = new Zend_OpenId_Provider();
$sreg = new Zend_OpenId_Extension_Sreg();

define("TEST_ID", Zend_OpenId::absoluteURL("example-10-id.php"));
define("TEST_PASSWORD", "123");

if ($_SERVER['REQUEST_METHOD'] == 'GET' &&
    isset($_GET['openid_action']) &&
    $_GET['openid_action'] === 'login') {
    $server->login(TEST_ID, TEST_PASSWORD);
    unset($_GET['openid_action']);
    Zend_OpenId::redirect(Zend_OpenId::selfUrl(), $_GET);
} else if ($_SERVER['REQUEST_METHOD'] == 'GET' &&
    isset($_GET['openid_action']) &&
    $_GET['openid_action'] === 'trust') {
   echo "UNTRUSTED DATA" ;
} else {
    $ret = $server->handle(null, $sreg);
    if (is_string($ret)) {
        echo $ret;
    } else if ($ret !== true) {
        header('HTTP/1.0 403 Forbidden');
        echo 'Forbidden';
    }
}

53.3.4. ¿Algo más?

Construir proveedores OpenID es mucho menos común que construir sitios habilitados para OpenID, por lo que este manual no cubre todas las características de Zend_OpenId_Provider de forma exhaustiva, como se hizo con Zend_OpenId_Consumer.

En resumen, Zend_OpenId_Provider contiene:

  • Un conjunto de métodos para construir una interfaz gráfica de usuario final que permite a los usuarios registrar y gestionar sus sitios de confianza y perfiles

  • Una capa de almacenamiento abstracta para almacenar información sobre usuarios, sus sitios y sus perfiles. También almacena asociaciones entre el proveedor y los sitios habilitados para OpenID. Esta capa es muy similar a la de la clase Zend_OpenId_Consumer. También usa almacenamiento en archivos de forma predeterminada, pero puede usarse con otro backend.

  • Una capa abstracta de asociación de usuarios que puede asociar el navegador web de un usuario con una identidad que ha iniciado sesión

La clase Zend_OpenId_Provider no intenta cubrir todas las posibles características que pueden implementar los servidores OpenID, por ejemplo, certificados digitales, pero puede extenderse fácilmente usando Zend_OpenId_Extensions o mediante la extensión orientada a objetos estándar.