+<?php
+
+/*-------------------------------------------------------------------------------------
+ *
+ * Filename : Authentication_Delegated.php
+ * Date : 11th July 2012
+ *
+ * Copyright (C) 2012 Melvin Carvalho, Akbar Hossain, László Török
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Everything should be made as simple as possible, but no simpler."
+ * -- Albert Einstein
+ */
+//-------------------------------------------------------------------------------------
+require_once(dirname(__FILE__)."/Authentication_URL.php");
+require_once(dirname(__FILE__)."/Authentication_X509CertRepo.php");
+require_once(dirname(__FILE__)."/Authentication_Session.php");
+/**
+ * Implements WebID Delegated Authentication using an Identity Provider
+ *
+ * @author Akbar Hossain
+ * @modified Andrei Sambra
+ */
+class Authentication_Delegated {
+ /**
+ * After succesful authentication contains the webid
+ * (e.g. http://foaf.me/tl73#me)
+ * @var string
+ */
+ public $webid = NULL;
+ public $isAuthenticated = 0;
+ /**
+ * Always contains the diagnostic message for the last authentication attempt
+ * @var string
+ */
+ public $authnDiagnostic = NULL;
+ /** @var Authentication_SignedURL */
+ private $requestURI = NULL;
+ /** @var Authentication_URL */
+ private $referer = NULL;
+ private $ts = NULL;
+ private $allowedTimeWindow = 0;
+ private $elapsedTime = 0;
+
+ const STATUS_AUTH_VIA_SESSION =
+ "Authenticated via a session";
+
+ const STATUS_DELEGATED_LOGIN_OK =
+ "Delegated WebID Login response has been authenticated";
+
+ const STATUS_SIGNATURE_VERIFICATION_ERR =
+ "Signature on response could not be verified";
+
+ const STATUS_UNSUPPORTED_SIGNATURE_ALG_ERR =
+ "Unsupported signature algorithm";
+
+ const STATUS_IDP_RESPONSE_TIMEOUT_ERR =
+ "Response from delegate IdP was outside of the allowed time window";
+
+ const STATUS_OPENSSL_VERIFICATION_ERR =
+ "Openssl verification error";
+
+ const STATUS_IDP_CERTIFICATE_MISSING =
+ "Signing IdP's certificate not found";
+
+ const SIG_ALG_RSA_SHA1 = 'rsa-sha1';
+ /**
+ * Perform delegated WebID authentication relying on an Identity Provider
+ * @param Authentication_SignedURL $request (if not specified infered from _GET)
+ * @param Authentication_X509CertRepo $certRepository (if not default is used)
+ * @param bool $createSession
+ * @param string $sigAlg
+ * @param int $allowedTimeWindow
+ */
+ public function __construct($createSession = TRUE,
+ Authentication_SignedURL $request = NULL,
+ Authentication_URL $referer = NULL,
+ Authentication_X509CertRepo $certRepository = NULL,
+ $sigAlg = self::SIG_ALG_RSA_SHA1,
+ $allowedTimeWindow = 300)
+ {
+ if ($createSession)
+ {
+ $session = new Authentication_Session();
+ if ($session->isAuthenticated)
+ {
+ $this->webid = $session->webid;
+ $this->isAuthenticated = $session->isAuthenticated;
+ $this->authnDiagnostic = self::STATUS_AUTH_VIA_SESSION;
+ return;
+ }
+ }
+
+ if ( ! $certRepository)
+ $certRepository = new Authentication_X509CertRepo();
+
+ if ( ! $request) {
+ $request = Authentication_SignedURL::parse(
+ ((isset($_SERVER["HTTPS"]) && ($_SERVER["HTTPS"] == "on")) ? "https" : "http")
+ . "://".$_SERVER["SERVER_NAME"]
+ . ($_SERVER["SERVER_PORT"] != ((isset($_SERVER["HTTPS"])
+ && ($_SERVER["HTTPS"] == "on")) ? 443 : 80) ? ":"
+ .$_SERVER["SERVER_PORT"] : "")
+ . $_SERVER["REQUEST_URI"]
+ );
+ }
+
+ $error = null;
+ $sig = null;
+ $ts = null;
+
+ isset($_GET["error"]) and $error = $_GET["error"];
+
+ isset($_GET["sig"]) and $sig = $_GET["sig"];
+
+ isset($_GET["ts"]) and $ts = $_GET["ts"];
+
+ $error = $request->getQueryParameter('error', $error);
+ $sig = $request->getQueryParameter('sig', $sig);
+ $ts = $request->getQueryParameter('ts', $ts);
+
+ $this->requestURI = $request;
+ if (NULL != $referer)
+ {
+ $this->referer = $referer;
+ }
+ else if (isset($_GET["referer"]))
+ {
+ $this->referer = Authentication_URL::parse($_GET["referer"]);
+ }
+ else
+ {
+ $this->referer = new Authentication_URL();
+ }
+ $this->ts = $ts;
+
+ $webid = null;
+ isset($_GET["webid"]) and $webid = $_GET["webid"];
+
+ $this->webid = $request->getQueryParameter('webid', $webid);
+ $this->allowedTimeWindow = $allowedTimeWindow;
+ $this->elapsedTime = time() - strtotime($ts);
+
+ /*
+ * Loads the trusted certificate of the IdP: its public key is used to
+ * verify the integrity of the signed assertion.
+ */
+ $idpCertificate = $certRepository->getIdpCertificate($this->referer->host);
+ if ( ! $idpCertificate)
+ {
+ $this->isAuthenticated = 0;
+ $this->authnDiagnostic = self::STATUS_IDP_CERTIFICATE_MISSING;
+
+ }
+ else if (($this->elapsedTime < $this->allowedTimeWindow) && ( ! isset($error)))
+ {
+
+ $signedInfo = $this->requestURI->urlWithoutSignature();
+ // Extracts the signature
+ $signature = $this->requestURI->digitalSignature();
+ // TODO this may be removed in the future
+ if ( ! $signature)
+ $signature = $sig;
+
+ // Only rsa-sha1 is supported at the moment.
+ if ($sigAlg == self::SIG_ALG_RSA_SHA1)
+ {
+ $pubKeyId = openssl_get_publickey($idpCertificate);
+
+ // Verifies the signature
+ $verified = openssl_verify($signedInfo, $signature, $pubKeyId);
+ if ($verified == 1)
+ {
+ // The verification was successful.
+ $this->isAuthenticated = 1;
+ $this->authnDiagnostic = self::STATUS_DELEGATED_LOGIN_OK;
+ }
+ else if ($verified == 0)
+ {
+ // The signature didn't match.
+ $this->isAuthenticated = 0;
+ $this->authnDiagnostic = self::STATUS_SIGNATURE_VERIFICATION_ERR;
+ }
+ else
+ {
+ // Error during the verification.
+ $this->isAuthenticated = 0;
+ $this->authnDiagnostic = self::STATUS_OPENSSL_VERIFICATION_ERR;
+ }
+
+ openssl_free_key($pubKeyId);
+
+ }
+ else
+ {
+ // Unsupported signature algorithm.
+ $this->isAuthenticated = 0;
+ $this->authnDiagnostic = self::STATUS_UNSUPPORTED_SIGNATURE_ALG_ERR;
+ }
+ }
+ else
+ {
+ $this->isAuthenticated = 0;
+ if (isset($error))
+ $this->authnDiagnostic = $error;
+ else
+ $this->authnDiagnostic = self::STATUS_IDP_RESPONSE_TIMEOUT_ERR;
+ }
+
+ if ($createSession)
+ {
+ if ($this->isAuthenticated)
+ $session->setAuthenticatedWebid($this->webid);
+ else
+ $session->unsetAuthenticatedWebid();
+ }
+ }
+
+ /**
+ * Is the current user authenticated?
+ * @return bool
+ */
+ public function isAuthenticated()
+ {
+ return $this->isAuthenticated;
+ }
+ /**
+ * Leave the authenticated session
+ */
+ public function logout()
+ {
+ $this->isAuthenticated = 0;
+ $this->session->unsetAuthenticatedWebid();
+ }
+
+}
+?>