Start using SAML2 library from GitHub.

This patch also starts using Composer for other dependencies
(i.e. php-openid and xmlseclibs).

Thanks to Boy Baukema for implementing this!

git-svn-id: http://simplesamlphp.googlecode.com/svn/trunk@3290 44740490-163a-0410-bde0-09ae8108e29a
This commit is contained in:
olavmrk 2013-11-15 09:34:07 +00:00
parent 4dc5e5ff65
commit 84b37c93fd
112 changed files with 348 additions and 27836 deletions

View File

@ -15,8 +15,6 @@ fi
cd /tmp
REPOPATH="http://simplesamlphp.googlecode.com/svn/tags/$TAG/"
if [ -a "$TAG" ]; then
echo "$0: Destination already exists: $TAG" >&2
exit 1
@ -24,7 +22,21 @@ fi
umask 0022
REPOPATH="http://simplesamlphp.googlecode.com/svn/tags/$TAG/"
svn export "$REPOPATH"
# Use composer only on newer versions that have a composer.json
if [ -f "$TAG/composer.json" ]; then
if [ ! -x composer.phar ]; then
echo "$0: Composerfile detected, but Composer not installed?" >&2
exit 1
fi
# Install dependencies (without vcs history or dev tools)
php composer.phar install --no-dev --prefer-dist -o -d "$TAG"
fi
mkdir -p "$TAG/config" "$TAG/metadata"
cp -rv "$TAG/config-templates/"* "$TAG/config/"
cp -rv "$TAG/metadata-templates/"* "$TAG/metadata/"

50
composer.json Normal file
View File

@ -0,0 +1,50 @@
{
"name": "simplesamlphp/simplesamlphp",
"description": "A PHP implementation of SAML 2.0 service provider and identity provider functionality. And is also compatible with Shibboleth 1.3 and 2.0.",
"type": "project",
"keywords": [ "saml2", "shibboleth","aselect","openid","oauth","ws-federation","sp","idp" ],
"homepage": "http://simplesamlphp.org",
"license": "LGPL-2.1",
"authors": [
{
"name": "Andreas Åkre Solberg",
"email": "andreas.solberg@uninett.no"
},
{
"name": "Olav Morken",
"email": "olav.morken@uninett.no"
}
],
"autoload": {
"psr-0": {
"SimpleSAML_": "lib/"
},
"files": ["lib/_autoload_modules.php"]
},
"require": {
"php": ">=5.3.0",
"simplesamlphp/saml2": "0.2.0",
"openid/php-openid": "dev-master#ee669c6a9d4d95b58ecd9b6945627276807694fb as 2.2.2"
},
"support": {
"issues": "https://code.google.com/p/simplesamlphp/issues/list",
"source": "https://code.google.com/p/simplesamlphp"
},
"repositories": [
{
"type": "package",
"package": {
"name": "robrichards/xmlseclibs",
"version": "1.3.1",
"source": {
"type": "svn",
"url": "http://xmlseclibs.googlecode.com/svn",
"reference": "trunk@50"
},
"autoload": {
"files": ["xmlseclibs.php"]
}
}
}
]
}

225
composer.lock generated Normal file
View File

@ -0,0 +1,225 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
],
"hash": "608aa8b969b50e691e090388b39a33be",
"packages": [
{
"name": "openid/php-openid",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/openid/php-openid.git",
"reference": "ee669c6a9d4d95b58ecd9b6945627276807694fb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/openid/php-openid/zipball/ee669c6a9d4d95b58ecd9b6945627276807694fb",
"reference": "ee669c6a9d4d95b58ecd9b6945627276807694fb",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-dom": "*",
"ext-gmp": "*",
"php": ">=4.3"
},
"type": "library",
"autoload": {
"classmap": [
"Auth"
]
},
"notification-url": "https://packagist.org/downloads/",
"include-path": [
"."
],
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "JanRain Inc.",
"homepage": "http://www.openidenabled.com"
}
],
"description": "OpenID library for PHP5",
"homepage": "http://github.com/openid/php-openid",
"keywords": [
"Authentication",
"OpenId",
"auth",
"yadis"
],
"time": "2013-10-03 21:21:20"
},
{
"name": "pimple/pimple",
"version": "v1.0.2",
"source": {
"type": "git",
"url": "https://github.com/fabpot/Pimple.git",
"reference": "ae11e57e8c2bb414b2ff93396dbbfc0eb92feb94"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fabpot/Pimple/zipball/ae11e57e8c2bb414b2ff93396dbbfc0eb92feb94",
"reference": "ae11e57e8c2bb414b2ff93396dbbfc0eb92feb94",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-0": {
"Pimple": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "Pimple is a simple Dependency Injection Container for PHP 5.3",
"homepage": "http://pimple.sensiolabs.org",
"keywords": [
"container",
"dependency injection"
],
"time": "2013-03-08 08:21:40"
},
{
"name": "psr/log",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "fe0936ee26643249e916849d48e3a51d5f5e278b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b",
"reference": "fe0936ee26643249e916849d48e3a51d5f5e278b",
"shasum": ""
},
"type": "library",
"autoload": {
"psr-0": {
"Psr\\Log\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"keywords": [
"log",
"psr",
"psr-3"
],
"time": "2012-12-21 11:40:51"
},
{
"name": "robrichards/xmlseclibs",
"version": "1.3.1",
"source": {
"type": "svn",
"url": "http://xmlseclibs.googlecode.com/svn",
"reference": "trunk@50"
},
"type": "library",
"autoload": {
"files": [
"xmlseclibs.php"
]
}
},
{
"name": "simplesamlphp/saml2",
"version": "v0.2.0",
"source": {
"type": "git",
"url": "https://github.com/simplesamlphp/saml2.git",
"reference": "d4b833edc6fcbd6948e79eacdfee1b6c257691b7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/simplesamlphp/saml2/zipball/d4b833edc6fcbd6948e79eacdfee1b6c257691b7",
"reference": "d4b833edc6fcbd6948e79eacdfee1b6c257691b7",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-openssl": "*",
"php": ">=5.3.3",
"psr/log": "1.0.0",
"robrichards/xmlseclibs": "1.3.*"
},
"require-dev": {
"phpmd/phpmd": "~1.5",
"phpunit/phpunit": "~3.7",
"sebastian/phpcpd": "~1.4",
"sensiolabs/security-checker": "~1.1",
"squizlabs/php_codesniffer": "~1.4"
},
"type": "library",
"autoload": {
"psr-0": {
"SAML2_": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1"
],
"authors": [
{
"name": "Andreas Åkre Solberg",
"email": "andreas.solberg@uninett.no"
}
],
"description": "SAML2 PHP library from SimpleSAMLphp",
"time": "2013-11-12 15:07:13"
}
],
"packages-dev": [
],
"aliases": [
{
"alias": "2.2.2",
"alias_normalized": "2.2.2.0",
"version": "9999999-dev",
"package": "openid/php-openid"
}
],
"minimum-stability": "stable",
"stability-flags": {
"openid/php-openid": 20
},
"platform": {
"php": ">=5.3.0"
},
"platform-dev": [
]
}

View File

@ -20,6 +20,10 @@ Initialize configuration and metadata:
cp -r config-templates/* config/
cp -r metadata-templates/* metadata/
Install the external dependencies with Composer (http://getcomposer.org/):
php composer.phar install
Upgrading
---------
@ -29,3 +33,6 @@ Go to the root directory of your simpleSAMLphp installation:
Ask subversion to update to the latest version:
svn update
Install the external dependencies with Composer (http://getcomposer.org/):
php composer.phar install

View File

@ -1,563 +0,0 @@
<?php
/**
* This is the PHP OpenID library by JanRain, Inc.
*
* This module contains core utility functionality used by the
* library. See Consumer.php and Server.php for the consumer and
* server implementations.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* The library version string
*/
define('Auth_OpenID_VERSION', '2.2.2');
/**
* Require the fetcher code.
*/
require_once "Auth/Yadis/PlainHTTPFetcher.php";
require_once "Auth/Yadis/ParanoidHTTPFetcher.php";
require_once "Auth/OpenID/BigMath.php";
require_once "Auth/OpenID/URINorm.php";
/**
* Status code returned by the server when the only option is to show
* an error page, since we do not have enough information to redirect
* back to the consumer. The associated value is an error message that
* should be displayed on an HTML error page.
*
* @see Auth_OpenID_Server
*/
define('Auth_OpenID_LOCAL_ERROR', 'local_error');
/**
* Status code returned when there is an error to return in key-value
* form to the consumer. The caller should return a 400 Bad Request
* response with content-type text/plain and the value as the body.
*
* @see Auth_OpenID_Server
*/
define('Auth_OpenID_REMOTE_ERROR', 'remote_error');
/**
* Status code returned when there is a key-value form OK response to
* the consumer. The value associated with this code is the
* response. The caller should return a 200 OK response with
* content-type text/plain and the value as the body.
*
* @see Auth_OpenID_Server
*/
define('Auth_OpenID_REMOTE_OK', 'remote_ok');
/**
* Status code returned when there is a redirect back to the
* consumer. The value is the URL to redirect back to. The caller
* should return a 302 Found redirect with a Location: header
* containing the URL.
*
* @see Auth_OpenID_Server
*/
define('Auth_OpenID_REDIRECT', 'redirect');
/**
* Status code returned when the caller needs to authenticate the
* user. The associated value is a {@link Auth_OpenID_ServerRequest}
* object that can be used to complete the authentication. If the user
* has taken some authentication action, use the retry() method of the
* {@link Auth_OpenID_ServerRequest} object to complete the request.
*
* @see Auth_OpenID_Server
*/
define('Auth_OpenID_DO_AUTH', 'do_auth');
/**
* Status code returned when there were no OpenID arguments
* passed. This code indicates that the caller should return a 200 OK
* response and display an HTML page that says that this is an OpenID
* server endpoint.
*
* @see Auth_OpenID_Server
*/
define('Auth_OpenID_DO_ABOUT', 'do_about');
/**
* Defines for regexes and format checking.
*/
define('Auth_OpenID_letters',
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
define('Auth_OpenID_digits',
"0123456789");
define('Auth_OpenID_punct',
"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~");
Auth_OpenID_include_init();
/**
* The OpenID utility function class.
*
* @package OpenID
* @access private
*/
class Auth_OpenID {
/**
* Return true if $thing is an Auth_OpenID_FailureResponse object;
* false if not.
*
* @access private
*/
static function isFailure($thing)
{
return is_a($thing, 'Auth_OpenID_FailureResponse');
}
/**
* Gets the query data from the server environment based on the
* request method used. If GET was used, this looks at
* $_SERVER['QUERY_STRING'] directly. If POST was used, this
* fetches data from the special php://input file stream.
*
* Returns an associative array of the query arguments.
*
* Skips invalid key/value pairs (i.e. keys with no '=value'
* portion).
*
* Returns an empty array if neither GET nor POST was used, or if
* POST was used but php://input cannot be opened.
*
* See background:
* http://lists.openidenabled.com/pipermail/dev/2007-March/000395.html
*
* @access private
*/
static function getQuery($query_str=null)
{
$data = array();
if ($query_str !== null) {
$data = Auth_OpenID::params_from_string($query_str);
} else if (!array_key_exists('REQUEST_METHOD', $_SERVER)) {
// Do nothing.
} else {
// XXX HACK FIXME HORRIBLE.
//
// POSTing to a URL with query parameters is acceptable, but
// we don't have a clean way to distinguish those parameters
// when we need to do things like return_to verification
// which only want to look at one kind of parameter. We're
// going to emulate the behavior of some other environments
// by defaulting to GET and overwriting with POST if POST
// data is available.
$data = Auth_OpenID::params_from_string($_SERVER['QUERY_STRING']);
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$str = file_get_contents('php://input');
if ($str === false) {
$post = array();
} else {
$post = Auth_OpenID::params_from_string($str);
}
$data = array_merge($data, $post);
}
}
return $data;
}
static function params_from_string($str)
{
$chunks = explode("&", $str);
$data = array();
foreach ($chunks as $chunk) {
$parts = explode("=", $chunk, 2);
if (count($parts) != 2) {
continue;
}
list($k, $v) = $parts;
$data[urldecode($k)] = urldecode($v);
}
return $data;
}
/**
* Create dir_name as a directory if it does not exist. If it
* exists, make sure that it is, in fact, a directory. Returns
* true if the operation succeeded; false if not.
*
* @access private
*/
static function ensureDir($dir_name)
{
if (is_dir($dir_name) || @mkdir($dir_name)) {
return true;
} else {
$parent_dir = dirname($dir_name);
// Terminal case; there is no parent directory to create.
if ($parent_dir == $dir_name) {
return true;
}
return (Auth_OpenID::ensureDir($parent_dir) && @mkdir($dir_name));
}
}
/**
* Adds a string prefix to all values of an array. Returns a new
* array containing the prefixed values.
*
* @access private
*/
static function addPrefix($values, $prefix)
{
$new_values = array();
foreach ($values as $s) {
$new_values[] = $prefix . $s;
}
return $new_values;
}
/**
* Convenience function for getting array values. Given an array
* $arr and a key $key, get the corresponding value from the array
* or return $default if the key is absent.
*
* @access private
*/
static function arrayGet($arr, $key, $fallback = null)
{
if (is_array($arr)) {
if (array_key_exists($key, $arr)) {
return $arr[$key];
} else {
return $fallback;
}
} else {
trigger_error("Auth_OpenID::arrayGet (key = ".$key.") expected " .
"array as first parameter, got " .
gettype($arr), E_USER_WARNING);
return false;
}
}
/**
* Replacement for PHP's broken parse_str.
*/
static function parse_str($query)
{
if ($query === null) {
return null;
}
$parts = explode('&', $query);
$new_parts = array();
for ($i = 0; $i < count($parts); $i++) {
$pair = explode('=', $parts[$i]);
if (count($pair) != 2) {
continue;
}
list($key, $value) = $pair;
$new_parts[urldecode($key)] = urldecode($value);
}
return $new_parts;
}
/**
* Implements the PHP 5 'http_build_query' functionality.
*
* @access private
* @param array $data Either an array key/value pairs or an array
* of arrays, each of which holding two values: a key and a value,
* sequentially.
* @return string $result The result of url-encoding the key/value
* pairs from $data into a URL query string
* (e.g. "username=bob&id=56").
*/
static function httpBuildQuery($data)
{
$pairs = array();
foreach ($data as $key => $value) {
if (is_array($value)) {
$pairs[] = urlencode($value[0])."=".urlencode($value[1]);
} else {
$pairs[] = urlencode($key)."=".urlencode($value);
}
}
return implode("&", $pairs);
}
/**
* "Appends" query arguments onto a URL. The URL may or may not
* already have arguments (following a question mark).
*
* @access private
* @param string $url A URL, which may or may not already have
* arguments.
* @param array $args Either an array key/value pairs or an array of
* arrays, each of which holding two values: a key and a value,
* sequentially. If $args is an ordinary key/value array, the
* parameters will be added to the URL in sorted alphabetical order;
* if $args is an array of arrays, their order will be preserved.
* @return string $url The original URL with the new parameters added.
*
*/
static function appendArgs($url, $args)
{
if (count($args) == 0) {
return $url;
}
// Non-empty array; if it is an array of arrays, use
// multisort; otherwise use sort.
if (array_key_exists(0, $args) &&
is_array($args[0])) {
// Do nothing here.
} else {
$keys = array_keys($args);
sort($keys);
$new_args = array();
foreach ($keys as $key) {
$new_args[] = array($key, $args[$key]);
}
$args = $new_args;
}
$sep = '?';
if (strpos($url, '?') !== false) {
$sep = '&';
}
return $url . $sep . Auth_OpenID::httpBuildQuery($args);
}
/**
* Implements python's urlunparse, which is not available in PHP.
* Given the specified components of a URL, this function rebuilds
* and returns the URL.
*
* @access private
* @param string $scheme The scheme (e.g. 'http'). Defaults to 'http'.
* @param string $host The host. Required.
* @param string $port The port.
* @param string $path The path.
* @param string $query The query.
* @param string $fragment The fragment.
* @return string $url The URL resulting from assembling the
* specified components.
*/
static function urlunparse($scheme, $host, $port = null, $path = '/',
$query = '', $fragment = '')
{
if (!$scheme) {
$scheme = 'http';
}
if (!$host) {
return false;
}
if (!$path) {
$path = '';
}
$result = $scheme . "://" . $host;
if ($port) {
$result .= ":" . $port;
}
$result .= $path;
if ($query) {
$result .= "?" . $query;
}
if ($fragment) {
$result .= "#" . $fragment;
}
return $result;
}
/**
* Given a URL, this "normalizes" it by adding a trailing slash
* and / or a leading http:// scheme where necessary. Returns
* null if the original URL is malformed and cannot be normalized.
*
* @access private
* @param string $url The URL to be normalized.
* @return mixed $new_url The URL after normalization, or null if
* $url was malformed.
*/
static function normalizeUrl($url)
{
@$parsed = parse_url($url);
if (!$parsed) {
return null;
}
if (isset($parsed['scheme']) &&
isset($parsed['host'])) {
$scheme = strtolower($parsed['scheme']);
if (!in_array($scheme, array('http', 'https'))) {
return null;
}
} else {
$url = 'http://' . $url;
}
$normalized = Auth_OpenID_urinorm($url);
if ($normalized === null) {
return null;
}
list($defragged, $frag) = Auth_OpenID::urldefrag($normalized);
return $defragged;
}
/**
* Replacement (wrapper) for PHP's intval() because it's broken.
*
* @access private
*/
static function intval($value)
{
$re = "/^\\d+$/";
if (!preg_match($re, $value)) {
return false;
}
return intval($value);
}
/**
* Count the number of bytes in a string independently of
* multibyte support conditions.
*
* @param string $str The string of bytes to count.
* @return int The number of bytes in $str.
*/
static function bytes($str)
{
return strlen(bin2hex($str)) / 2;
}
/**
* Get the bytes in a string independently of multibyte support
* conditions.
*/
static function toBytes($str)
{
$hex = bin2hex($str);
if (!$hex) {
return array();
}
$b = array();
for ($i = 0; $i < strlen($hex); $i += 2) {
$b[] = chr(base_convert(substr($hex, $i, 2), 16, 10));
}
return $b;
}
static function urldefrag($url)
{
$parts = explode("#", $url, 2);
if (count($parts) == 1) {
return array($parts[0], "");
} else {
return $parts;
}
}
static function filter($callback, &$sequence)
{
$result = array();
foreach ($sequence as $item) {
if (call_user_func_array($callback, array($item))) {
$result[] = $item;
}
}
return $result;
}
static function update(&$dest, &$src)
{
foreach ($src as $k => $v) {
$dest[$k] = $v;
}
}
/**
* Wrap PHP's standard error_log functionality. Use this to
* perform all logging. It will interpolate any additional
* arguments into the format string before logging.
*
* @param string $format_string The sprintf format for the message
*/
static function log($format_string)
{
$args = func_get_args();
$message = call_user_func_array('sprintf', $args);
error_log($message);
}
static function autoSubmitHTML($form, $title="OpenId transaction in progress")
{
return("<html>".
"<head><title>".
$title .
"</title></head>".
"<body onload='document.forms[0].submit();'>".
$form .
"<script>".
"var elements = document.forms[0].elements;".
"for (var i = 0; i < elements.length; i++) {".
" elements[i].style.display = \"none\";".
"}".
"</script>".
"</body>".
"</html>");
}
}
/*
* Function to run when this file is included.
* Abstracted to a function to make life easier
* for some PHP optimizers.
*/
function Auth_OpenID_include_init() {
if (Auth_OpenID_getMathLib() === null) {
Auth_OpenID_setNoMathSupport();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,610 +0,0 @@
<?php
/**
* This module contains code for dealing with associations between
* consumers and servers.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* @access private
*/
require_once 'Auth/OpenID/CryptUtil.php';
/**
* @access private
*/
require_once 'Auth/OpenID/KVForm.php';
/**
* @access private
*/
require_once 'Auth/OpenID/HMAC.php';
/**
* This class represents an association between a server and a
* consumer. In general, users of this library will never see
* instances of this object. The only exception is if you implement a
* custom {@link Auth_OpenID_OpenIDStore}.
*
* If you do implement such a store, it will need to store the values
* of the handle, secret, issued, lifetime, and assoc_type instance
* variables.
*
* @package OpenID
*/
class Auth_OpenID_Association {
/**
* This is a HMAC-SHA1 specific value.
*
* @access private
*/
var $SIG_LENGTH = 20;
/**
* The ordering and name of keys as stored by serialize.
*
* @access private
*/
var $assoc_keys = array(
'version',
'handle',
'secret',
'issued',
'lifetime',
'assoc_type'
);
var $_macs = array(
'HMAC-SHA1' => 'Auth_OpenID_HMACSHA1',
'HMAC-SHA256' => 'Auth_OpenID_HMACSHA256'
);
/**
* This is an alternate constructor (factory method) used by the
* OpenID consumer library to create associations. OpenID store
* implementations shouldn't use this constructor.
*
* @access private
*
* @param integer $expires_in This is the amount of time this
* association is good for, measured in seconds since the
* association was issued.
*
* @param string $handle This is the handle the server gave this
* association.
*
* @param string secret This is the shared secret the server
* generated for this association.
*
* @param assoc_type This is the type of association this
* instance represents. The only valid values of this field at
* this time is 'HMAC-SHA1' and 'HMAC-SHA256', but new types may
* be defined in the future.
*
* @return association An {@link Auth_OpenID_Association}
* instance.
*/
static function fromExpiresIn($expires_in, $handle, $secret, $assoc_type)
{
$issued = time();
$lifetime = $expires_in;
return new Auth_OpenID_Association($handle, $secret,
$issued, $lifetime, $assoc_type);
}
/**
* This is the standard constructor for creating an association.
* The library should create all of the necessary associations, so
* this constructor is not part of the external API.
*
* @access private
*
* @param string $handle This is the handle the server gave this
* association.
*
* @param string $secret This is the shared secret the server
* generated for this association.
*
* @param integer $issued This is the time this association was
* issued, in seconds since 00:00 GMT, January 1, 1970. (ie, a
* unix timestamp)
*
* @param integer $lifetime This is the amount of time this
* association is good for, measured in seconds since the
* association was issued.
*
* @param string $assoc_type This is the type of association this
* instance represents. The only valid values of this field at
* this time is 'HMAC-SHA1' and 'HMAC-SHA256', but new types may
* be defined in the future.
*/
function Auth_OpenID_Association(
$handle, $secret, $issued, $lifetime, $assoc_type)
{
if (!in_array($assoc_type,
Auth_OpenID_getSupportedAssociationTypes(), true)) {
$fmt = 'Unsupported association type (%s)';
trigger_error(sprintf($fmt, $assoc_type), E_USER_ERROR);
}
$this->handle = $handle;
$this->secret = $secret;
$this->issued = $issued;
$this->lifetime = $lifetime;
$this->assoc_type = $assoc_type;
}
/**
* This returns the number of seconds this association is still
* valid for, or 0 if the association is no longer valid.
*
* @return integer $seconds The number of seconds this association
* is still valid for, or 0 if the association is no longer valid.
*/
function getExpiresIn($now = null)
{
if ($now == null) {
$now = time();
}
return max(0, $this->issued + $this->lifetime - $now);
}
/**
* This checks to see if two {@link Auth_OpenID_Association}
* instances represent the same association.
*
* @return bool $result true if the two instances represent the
* same association, false otherwise.
*/
function equal($other)
{
return ((gettype($this) == gettype($other))
&& ($this->handle == $other->handle)
&& ($this->secret == $other->secret)
&& ($this->issued == $other->issued)
&& ($this->lifetime == $other->lifetime)
&& ($this->assoc_type == $other->assoc_type));
}
/**
* Convert an association to KV form.
*
* @return string $result String in KV form suitable for
* deserialization by deserialize.
*/
function serialize()
{
$data = array(
'version' => '2',
'handle' => $this->handle,
'secret' => base64_encode($this->secret),
'issued' => strval(intval($this->issued)),
'lifetime' => strval(intval($this->lifetime)),
'assoc_type' => $this->assoc_type
);
assert(array_keys($data) == $this->assoc_keys);
return Auth_OpenID_KVForm::fromArray($data, $strict = true);
}
/**
* Parse an association as stored by serialize(). This is the
* inverse of serialize.
*
* @param string $assoc_s Association as serialized by serialize()
* @return Auth_OpenID_Association $result instance of this class
*/
static function deserialize($class_name, $assoc_s)
{
$pairs = Auth_OpenID_KVForm::toArray($assoc_s, $strict = true);
$keys = array();
$values = array();
foreach ($pairs as $key => $value) {
if (is_array($value)) {
list($key, $value) = $value;
}
$keys[] = $key;
$values[] = $value;
}
$class_vars = get_class_vars($class_name);
$class_assoc_keys = $class_vars['assoc_keys'];
sort($keys);
sort($class_assoc_keys);
if ($keys != $class_assoc_keys) {
trigger_error('Unexpected key values: ' . var_export($keys, true),
E_USER_WARNING);
return null;
}
$version = $pairs['version'];
$handle = $pairs['handle'];
$secret = $pairs['secret'];
$issued = $pairs['issued'];
$lifetime = $pairs['lifetime'];
$assoc_type = $pairs['assoc_type'];
if ($version != '2') {
trigger_error('Unknown version: ' . $version, E_USER_WARNING);
return null;
}
$issued = intval($issued);
$lifetime = intval($lifetime);
$secret = base64_decode($secret);
return new $class_name(
$handle, $secret, $issued, $lifetime, $assoc_type);
}
/**
* Generate a signature for a sequence of (key, value) pairs
*
* @access private
* @param array $pairs The pairs to sign, in order. This is an
* array of two-tuples.
* @return string $signature The binary signature of this sequence
* of pairs
*/
function sign($pairs)
{
$kv = Auth_OpenID_KVForm::fromArray($pairs);
/* Invalid association types should be caught at constructor */
$callback = $this->_macs[$this->assoc_type];
return call_user_func_array($callback, array($this->secret, $kv));
}
/**
* Generate a signature for some fields in a dictionary
*
* @access private
* @param array $fields The fields to sign, in order; this is an
* array of strings.
* @param array $data Dictionary of values to sign (an array of
* string => string pairs).
* @return string $signature The signature, base64 encoded
*/
function signMessage($message)
{
if ($message->hasKey(Auth_OpenID_OPENID_NS, 'sig') ||
$message->hasKey(Auth_OpenID_OPENID_NS, 'signed')) {
// Already has a sig
return null;
}
$extant_handle = $message->getArg(Auth_OpenID_OPENID_NS,
'assoc_handle');
if ($extant_handle && ($extant_handle != $this->handle)) {
// raise ValueError("Message has a different association handle")
return null;
}
$signed_message = $message;
$signed_message->setArg(Auth_OpenID_OPENID_NS, 'assoc_handle',
$this->handle);
$message_keys = array_keys($signed_message->toPostArgs());
$signed_list = array();
$signed_prefix = 'openid.';
foreach ($message_keys as $k) {
if (strpos($k, $signed_prefix) === 0) {
$signed_list[] = substr($k, strlen($signed_prefix));
}
}
$signed_list[] = 'signed';
sort($signed_list);
$signed_message->setArg(Auth_OpenID_OPENID_NS, 'signed',
implode(',', $signed_list));
$sig = $this->getMessageSignature($signed_message);
$signed_message->setArg(Auth_OpenID_OPENID_NS, 'sig', $sig);
return $signed_message;
}
/**
* Given a {@link Auth_OpenID_Message}, return the key/value pairs
* to be signed according to the signed list in the message. If
* the message lacks a signed list, return null.
*
* @access private
*/
function _makePairs($message)
{
$signed = $message->getArg(Auth_OpenID_OPENID_NS, 'signed');
if (!$signed || Auth_OpenID::isFailure($signed)) {
// raise ValueError('Message has no signed list: %s' % (message,))
return null;
}
$signed_list = explode(',', $signed);
$pairs = array();
$data = $message->toPostArgs();
foreach ($signed_list as $field) {
$pairs[] = array($field, Auth_OpenID::arrayGet($data,
'openid.' .
$field, ''));
}
return $pairs;
}
/**
* Given an {@link Auth_OpenID_Message}, return the signature for
* the signed list in the message.
*
* @access private
*/
function getMessageSignature($message)
{
$pairs = $this->_makePairs($message);
return base64_encode($this->sign($pairs));
}
/**
* Confirm that the signature of these fields matches the
* signature contained in the data.
*
* @access private
*/
function checkMessageSignature($message)
{
$sig = $message->getArg(Auth_OpenID_OPENID_NS,
'sig');
if (!$sig || Auth_OpenID::isFailure($sig)) {
return false;
}
$calculated_sig = $this->getMessageSignature($message);
return Auth_OpenID_CryptUtil::constEq($calculated_sig, $sig);
}
}
function Auth_OpenID_getSecretSize($assoc_type)
{
if ($assoc_type == 'HMAC-SHA1') {
return 20;
} else if ($assoc_type == 'HMAC-SHA256') {
return 32;
} else {
return null;
}
}
function Auth_OpenID_getAllAssociationTypes()
{
return array('HMAC-SHA1', 'HMAC-SHA256');
}
function Auth_OpenID_getSupportedAssociationTypes()
{
$a = array('HMAC-SHA1');
if (Auth_OpenID_HMACSHA256_SUPPORTED) {
$a[] = 'HMAC-SHA256';
}
return $a;
}
function Auth_OpenID_getSessionTypes($assoc_type)
{
$assoc_to_session = array(
'HMAC-SHA1' => array('DH-SHA1', 'no-encryption'));
if (Auth_OpenID_HMACSHA256_SUPPORTED) {
$assoc_to_session['HMAC-SHA256'] =
array('DH-SHA256', 'no-encryption');
}
return Auth_OpenID::arrayGet($assoc_to_session, $assoc_type, array());
}
function Auth_OpenID_checkSessionType($assoc_type, $session_type)
{
if (!in_array($session_type,
Auth_OpenID_getSessionTypes($assoc_type))) {
return false;
}
return true;
}
function Auth_OpenID_getDefaultAssociationOrder()
{
$order = array();
if (!Auth_OpenID_noMathSupport()) {
$order[] = array('HMAC-SHA1', 'DH-SHA1');
if (Auth_OpenID_HMACSHA256_SUPPORTED) {
$order[] = array('HMAC-SHA256', 'DH-SHA256');
}
}
$order[] = array('HMAC-SHA1', 'no-encryption');
if (Auth_OpenID_HMACSHA256_SUPPORTED) {
$order[] = array('HMAC-SHA256', 'no-encryption');
}
return $order;
}
function Auth_OpenID_getOnlyEncryptedOrder()
{
$result = array();
foreach (Auth_OpenID_getDefaultAssociationOrder() as $pair) {
list($assoc, $session) = $pair;
if ($session != 'no-encryption') {
if (Auth_OpenID_HMACSHA256_SUPPORTED &&
($assoc == 'HMAC-SHA256')) {
$result[] = $pair;
} else if ($assoc != 'HMAC-SHA256') {
$result[] = $pair;
}
}
}
return $result;
}
function Auth_OpenID_getDefaultNegotiator()
{
return new Auth_OpenID_SessionNegotiator(
Auth_OpenID_getDefaultAssociationOrder());
}
function Auth_OpenID_getEncryptedNegotiator()
{
return new Auth_OpenID_SessionNegotiator(
Auth_OpenID_getOnlyEncryptedOrder());
}
/**
* A session negotiator controls the allowed and preferred association
* types and association session types. Both the {@link
* Auth_OpenID_Consumer} and {@link Auth_OpenID_Server} use
* negotiators when creating associations.
*
* You can create and use negotiators if you:
* - Do not want to do Diffie-Hellman key exchange because you use
* transport-layer encryption (e.g. SSL)
*
* - Want to use only SHA-256 associations
*
* - Do not want to support plain-text associations over a non-secure
* channel
*
* It is up to you to set a policy for what kinds of associations to
* accept. By default, the library will make any kind of association
* that is allowed in the OpenID 2.0 specification.
*
* Use of negotiators in the library
* =================================
*
* When a consumer makes an association request, it calls {@link
* getAllowedType} to get the preferred association type and
* association session type.
*
* The server gets a request for a particular association/session type
* and calls {@link isAllowed} to determine if it should create an
* association. If it is supported, negotiation is complete. If it is
* not, the server calls {@link getAllowedType} to get an allowed
* association type to return to the consumer.
*
* If the consumer gets an error response indicating that the
* requested association/session type is not supported by the server
* that contains an assocation/session type to try, it calls {@link
* isAllowed} to determine if it should try again with the given
* combination of association/session type.
*
* @package OpenID
*/
class Auth_OpenID_SessionNegotiator {
function Auth_OpenID_SessionNegotiator($allowed_types)
{
$this->allowed_types = array();
$this->setAllowedTypes($allowed_types);
}
/**
* Set the allowed association types, checking to make sure each
* combination is valid.
*
* @access private
*/
function setAllowedTypes($allowed_types)
{
foreach ($allowed_types as $pair) {
list($assoc_type, $session_type) = $pair;
if (!Auth_OpenID_checkSessionType($assoc_type, $session_type)) {
return false;
}
}
$this->allowed_types = $allowed_types;
return true;
}
/**
* Add an association type and session type to the allowed types
* list. The assocation/session pairs are tried in the order that
* they are added.
*
* @access private
*/
function addAllowedType($assoc_type, $session_type = null)
{
if ($this->allowed_types === null) {
$this->allowed_types = array();
}
if ($session_type === null) {
$available = Auth_OpenID_getSessionTypes($assoc_type);
if (!$available) {
return false;
}
foreach ($available as $session_type) {
$this->addAllowedType($assoc_type, $session_type);
}
} else {
if (Auth_OpenID_checkSessionType($assoc_type, $session_type)) {
$this->allowed_types[] = array($assoc_type, $session_type);
} else {
return false;
}
}
return true;
}
// Is this combination of association type and session type allowed?
function isAllowed($assoc_type, $session_type)
{
$assoc_good = in_array(array($assoc_type, $session_type),
$this->allowed_types);
$matches = in_array($session_type,
Auth_OpenID_getSessionTypes($assoc_type));
return ($assoc_good && $matches);
}
/**
* Get a pair of assocation type and session type that are
* supported.
*/
function getAllowedType()
{
if (!$this->allowed_types) {
return array(null, null);
}
return $this->allowed_types[0];
}
}

View File

@ -1,451 +0,0 @@
<?php
/**
* BigMath: A math library wrapper that abstracts out the underlying
* long integer library.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @access private
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* Needed for random number generation
*/
require_once 'Auth/OpenID/CryptUtil.php';
/**
* Need Auth_OpenID::bytes().
*/
require_once 'Auth/OpenID.php';
/**
* The superclass of all big-integer math implementations
* @access private
* @package OpenID
*/
class Auth_OpenID_MathLibrary {
/**
* Given a long integer, returns the number converted to a binary
* string. This function accepts long integer values of arbitrary
* magnitude and uses the local large-number math library when
* available.
*
* @param integer $long The long number (can be a normal PHP
* integer or a number created by one of the available long number
* libraries)
* @return string $binary The binary version of $long
*/
function longToBinary($long)
{
$cmp = $this->cmp($long, 0);
if ($cmp < 0) {
$msg = __FUNCTION__ . " takes only positive integers.";
trigger_error($msg, E_USER_ERROR);
return null;
}
if ($cmp == 0) {
return "\x00";
}
$bytes = array();
while ($this->cmp($long, 0) > 0) {
array_unshift($bytes, $this->mod($long, 256));
$long = $this->div($long, pow(2, 8));
}
if ($bytes && ($bytes[0] > 127)) {
array_unshift($bytes, 0);
}
$string = '';
foreach ($bytes as $byte) {
$string .= pack('C', $byte);
}
return $string;
}
/**
* Given a binary string, returns the binary string converted to a
* long number.
*
* @param string $binary The binary version of a long number,
* probably as a result of calling longToBinary
* @return integer $long The long number equivalent of the binary
* string $str
*/
function binaryToLong($str)
{
if ($str === null) {
return null;
}
// Use array_merge to return a zero-indexed array instead of a
// one-indexed array.
$bytes = array_merge(unpack('C*', $str));
$n = $this->init(0);
if ($bytes && ($bytes[0] > 127)) {
trigger_error("bytesToNum works only for positive integers.",
E_USER_WARNING);
return null;
}
foreach ($bytes as $byte) {
$n = $this->mul($n, pow(2, 8));
$n = $this->add($n, $byte);
}
return $n;
}
function base64ToLong($str)
{
$b64 = base64_decode($str);
if ($b64 === false) {
return false;
}
return $this->binaryToLong($b64);
}
function longToBase64($str)
{
return base64_encode($this->longToBinary($str));
}
/**
* Returns a random number in the specified range. This function
* accepts $start, $stop, and $step values of arbitrary magnitude
* and will utilize the local large-number math library when
* available.
*
* @param integer $start The start of the range, or the minimum
* random number to return
* @param integer $stop The end of the range, or the maximum
* random number to return
* @param integer $step The step size, such that $result - ($step
* * N) = $start for some N
* @return integer $result The resulting randomly-generated number
*/
function rand($stop)
{
static $duplicate_cache = array();
// Used as the key for the duplicate cache
$rbytes = $this->longToBinary($stop);
if (array_key_exists($rbytes, $duplicate_cache)) {
list($duplicate, $nbytes) = $duplicate_cache[$rbytes];
} else {
if ($rbytes[0] == "\x00") {
$nbytes = Auth_OpenID::bytes($rbytes) - 1;
} else {
$nbytes = Auth_OpenID::bytes($rbytes);
}
$mxrand = $this->pow(256, $nbytes);
// If we get a number less than this, then it is in the
// duplicated range.
$duplicate = $this->mod($mxrand, $stop);
if (count($duplicate_cache) > 10) {
$duplicate_cache = array();
}
$duplicate_cache[$rbytes] = array($duplicate, $nbytes);
}
do {
$bytes = "\x00" . Auth_OpenID_CryptUtil::getBytes($nbytes);
$n = $this->binaryToLong($bytes);
// Keep looping if this value is in the low duplicated range
} while ($this->cmp($n, $duplicate) < 0);
return $this->mod($n, $stop);
}
}
/**
* Exposes BCmath math library functionality.
*
* {@link Auth_OpenID_BcMathWrapper} wraps the functionality provided
* by the BCMath extension.
*
* @access private
* @package OpenID
*/
class Auth_OpenID_BcMathWrapper extends Auth_OpenID_MathLibrary{
var $type = 'bcmath';
function add($x, $y)
{
return bcadd($x, $y);
}
function sub($x, $y)
{
return bcsub($x, $y);
}
function pow($base, $exponent)
{
return bcpow($base, $exponent);
}
function cmp($x, $y)
{
return bccomp($x, $y);
}
function init($number, $base = 10)
{
return $number;
}
function mod($base, $modulus)
{
return bcmod($base, $modulus);
}
function mul($x, $y)
{
return bcmul($x, $y);
}
function div($x, $y)
{
return bcdiv($x, $y);
}
/**
* Same as bcpowmod when bcpowmod is missing
*
* @access private
*/
function _powmod($base, $exponent, $modulus)
{
$square = $this->mod($base, $modulus);
$result = 1;
while($this->cmp($exponent, 0) > 0) {
if ($this->mod($exponent, 2)) {
$result = $this->mod($this->mul($result, $square), $modulus);
}
$square = $this->mod($this->mul($square, $square), $modulus);
$exponent = $this->div($exponent, 2);
}
return $result;
}
function powmod($base, $exponent, $modulus)
{
if (function_exists('bcpowmod')) {
return bcpowmod($base, $exponent, $modulus);
} else {
return $this->_powmod($base, $exponent, $modulus);
}
}
function toString($num)
{
return $num;
}
}
/**
* Exposes GMP math library functionality.
*
* {@link Auth_OpenID_GmpMathWrapper} wraps the functionality provided
* by the GMP extension.
*
* @access private
* @package OpenID
*/
class Auth_OpenID_GmpMathWrapper extends Auth_OpenID_MathLibrary{
var $type = 'gmp';
function add($x, $y)
{
return gmp_add($x, $y);
}
function sub($x, $y)
{
return gmp_sub($x, $y);
}
function pow($base, $exponent)
{
return gmp_pow($base, $exponent);
}
function cmp($x, $y)
{
return gmp_cmp($x, $y);
}
function init($number, $base = 10)
{
return gmp_init($number, $base);
}
function mod($base, $modulus)
{
return gmp_mod($base, $modulus);
}
function mul($x, $y)
{
return gmp_mul($x, $y);
}
function div($x, $y)
{
return gmp_div_q($x, $y);
}
function powmod($base, $exponent, $modulus)
{
return gmp_powm($base, $exponent, $modulus);
}
function toString($num)
{
return gmp_strval($num);
}
}
/**
* Define the supported extensions. An extension array has keys
* 'modules', 'extension', and 'class'. 'modules' is an array of PHP
* module names which the loading code will attempt to load. These
* values will be suffixed with a library file extension (e.g. ".so").
* 'extension' is the name of a PHP extension which will be tested
* before 'modules' are loaded. 'class' is the string name of a
* {@link Auth_OpenID_MathWrapper} subclass which should be
* instantiated if a given extension is present.
*
* You can define new math library implementations and add them to
* this array.
*/
function Auth_OpenID_math_extensions()
{
$result = array();
if (!defined('Auth_OpenID_BUGGY_GMP')) {
$result[] =
array('modules' => array('gmp', 'php_gmp'),
'extension' => 'gmp',
'class' => 'Auth_OpenID_GmpMathWrapper');
}
$result[] = array('modules' => array('bcmath', 'php_bcmath'),
'extension' => 'bcmath',
'class' => 'Auth_OpenID_BcMathWrapper');
return $result;
}
/**
* Detect which (if any) math library is available
*/
function Auth_OpenID_detectMathLibrary($exts)
{
$loaded = false;
foreach ($exts as $extension) {
if (extension_loaded($extension['extension'])) {
return $extension;
}
}
return false;
}
/**
* {@link Auth_OpenID_getMathLib} checks for the presence of long
* number extension modules and returns an instance of
* {@link Auth_OpenID_MathWrapper} which exposes the module's
* functionality.
*
* Checks for the existence of an extension module described by the
* result of {@link Auth_OpenID_math_extensions()} and returns an
* instance of a wrapper for that extension module. If no extension
* module is found, an instance of {@link Auth_OpenID_MathWrapper} is
* returned, which wraps the native PHP integer implementation. The
* proper calling convention for this method is $lib =
* Auth_OpenID_getMathLib().
*
* This function checks for the existence of specific long number
* implementations in the following order: GMP followed by BCmath.
*
* @return Auth_OpenID_MathWrapper $instance An instance of
* {@link Auth_OpenID_MathWrapper} or one of its subclasses
*
* @package OpenID
*/
function Auth_OpenID_getMathLib()
{
// The instance of Auth_OpenID_MathWrapper that we choose to
// supply will be stored here, so that subseqent calls to this
// method will return a reference to the same object.
static $lib = null;
if (isset($lib)) {
return $lib;
}
if (Auth_OpenID_noMathSupport()) {
$null = null;
return $null;
}
// If this method has not been called before, look at
// Auth_OpenID_math_extensions and try to find an extension that
// works.
$ext = Auth_OpenID_detectMathLibrary(Auth_OpenID_math_extensions());
if ($ext === false) {
$tried = array();
foreach (Auth_OpenID_math_extensions() as $extinfo) {
$tried[] = $extinfo['extension'];
}
$triedstr = implode(", ", $tried);
Auth_OpenID_setNoMathSupport();
$result = null;
return $result;
}
// Instantiate a new wrapper
$class = $ext['class'];
$lib = new $class();
return $lib;
}
function Auth_OpenID_setNoMathSupport()
{
if (!defined('Auth_OpenID_NO_MATH_SUPPORT')) {
define('Auth_OpenID_NO_MATH_SUPPORT', true);
}
}
function Auth_OpenID_noMathSupport()
{
return defined('Auth_OpenID_NO_MATH_SUPPORT');
}

File diff suppressed because it is too large Load Diff

View File

@ -1,122 +0,0 @@
<?php
/**
* CryptUtil: A suite of wrapper utility functions for the OpenID
* library.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @access private
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
if (!defined('Auth_OpenID_RAND_SOURCE')) {
/**
* The filename for a source of random bytes. Define this yourself
* if you have a different source of randomness.
*/
define('Auth_OpenID_RAND_SOURCE', '/dev/urandom');
}
class Auth_OpenID_CryptUtil {
/**
* Get the specified number of random bytes.
*
* Attempts to use a cryptographically secure (not predictable)
* source of randomness if available. If there is no high-entropy
* randomness source available, it will fail. As a last resort,
* for non-critical systems, define
* <code>Auth_OpenID_RAND_SOURCE</code> as <code>null</code>, and
* the code will fall back on a pseudo-random number generator.
*
* @param int $num_bytes The length of the return value
* @return string $bytes random bytes
*/
static function getBytes($num_bytes)
{
static $f = null;
$bytes = '';
if ($f === null) {
if (Auth_OpenID_RAND_SOURCE === null) {
$f = false;
} else {
$f = @fopen(Auth_OpenID_RAND_SOURCE, "r");
if ($f === false) {
$msg = 'Define Auth_OpenID_RAND_SOURCE as null to ' .
' continue with an insecure random number generator.';
trigger_error($msg, E_USER_ERROR);
}
}
}
if ($f === false) {
// pseudorandom used
$bytes = '';
for ($i = 0; $i < $num_bytes; $i += 4) {
$bytes .= pack('L', mt_rand());
}
$bytes = substr($bytes, 0, $num_bytes);
} else {
$bytes = fread($f, $num_bytes);
}
return $bytes;
}
/**
* Produce a string of length random bytes, chosen from chrs. If
* $chrs is null, the resulting string may contain any characters.
*
* @param integer $length The length of the resulting
* randomly-generated string
* @param string $chrs A string of characters from which to choose
* to build the new string
* @return string $result A string of randomly-chosen characters
* from $chrs
*/
static function randomString($length, $population = null)
{
if ($population === null) {
return Auth_OpenID_CryptUtil::getBytes($length);
}
$popsize = strlen($population);
if ($popsize > 256) {
$msg = 'More than 256 characters supplied to ' . __FUNCTION__;
trigger_error($msg, E_USER_ERROR);
}
$duplicate = 256 % $popsize;
$str = "";
for ($i = 0; $i < $length; $i++) {
do {
$n = ord(Auth_OpenID_CryptUtil::getBytes(1));
} while ($n < $duplicate);
$n %= $popsize;
$str .= $population[$n];
}
return $str;
}
static function constEq($s1, $s2)
{
if (strlen($s1) != strlen($s2)) {
return false;
}
$result = true;
$length = strlen($s1);
for ($i = 0; $i < $length; $i++) {
$result &= ($s1[$i] == $s2[$i]);
}
return $result;
}
}

View File

@ -1,130 +0,0 @@
<?php
/**
* The Auth_OpenID_DatabaseConnection class, which is used to emulate
* a PEAR database connection.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* An empty base class intended to emulate PEAR connection
* functionality in applications that supply their own database
* abstraction mechanisms. See {@link Auth_OpenID_SQLStore} for more
* information. You should subclass this class if you need to create
* an SQL store that needs to access its database using an
* application's database abstraction layer instead of a PEAR database
* connection. Any subclass of Auth_OpenID_DatabaseConnection MUST
* adhere to the interface specified here.
*
* @package OpenID
*/
class Auth_OpenID_DatabaseConnection {
/**
* Sets auto-commit mode on this database connection.
*
* @param bool $mode True if auto-commit is to be used; false if
* not.
*/
function autoCommit($mode)
{
}
/**
* Run an SQL query with the specified parameters, if any.
*
* @param string $sql An SQL string with placeholders. The
* placeholders are assumed to be specific to the database engine
* for this connection.
*
* @param array $params An array of parameters to insert into the
* SQL string using this connection's escaping mechanism.
*
* @return mixed $result The result of calling this connection's
* internal query function. The type of result depends on the
* underlying database engine. This method is usually used when
* the result of a query is not important, like a DDL query.
*/
function query($sql, $params = array())
{
}
/**
* Starts a transaction on this connection, if supported.
*/
function begin()
{
}
/**
* Commits a transaction on this connection, if supported.
*/
function commit()
{
}
/**
* Performs a rollback on this connection, if supported.
*/
function rollback()
{
}
/**
* Run an SQL query and return the first column of the first row
* of the result set, if any.
*
* @param string $sql An SQL string with placeholders. The
* placeholders are assumed to be specific to the database engine
* for this connection.
*
* @param array $params An array of parameters to insert into the
* SQL string using this connection's escaping mechanism.
*
* @return mixed $result The value of the first column of the
* first row of the result set. False if no such result was
* found.
*/
function getOne($sql, $params = array())
{
}
/**
* Run an SQL query and return the first row of the result set, if
* any.
*
* @param string $sql An SQL string with placeholders. The
* placeholders are assumed to be specific to the database engine
* for this connection.
*
* @param array $params An array of parameters to insert into the
* SQL string using this connection's escaping mechanism.
*
* @return array $result The first row of the result set, if any,
* keyed on column name. False if no such result was found.
*/
function getRow($sql, $params = array())
{
}
/**
* Run an SQL query with the specified parameters, if any.
*
* @param string $sql An SQL string with placeholders. The
* placeholders are assumed to be specific to the database engine
* for this connection.
*
* @param array $params An array of parameters to insert into the
* SQL string using this connection's escaping mechanism.
*
* @return array $result An array of arrays representing the
* result of the query; each array is keyed on column name.
*/
function getAll($sql, $params = array())
{
}
}

View File

@ -1,113 +0,0 @@
<?php
/**
* The OpenID library's Diffie-Hellman implementation.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @access private
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
require_once 'Auth/OpenID.php';
require_once 'Auth/OpenID/BigMath.php';
function Auth_OpenID_getDefaultMod()
{
return '155172898181473697471232257763715539915724801'.
'966915404479707795314057629378541917580651227423'.
'698188993727816152646631438561595825688188889951'.
'272158842675419950341258706556549803580104870537'.
'681476726513255747040765857479291291572334510643'.
'245094715007229621094194349783925984760375594985'.
'848253359305585439638443';
}
function Auth_OpenID_getDefaultGen()
{
return '2';
}
/**
* The Diffie-Hellman key exchange class. This class relies on
* {@link Auth_OpenID_MathLibrary} to perform large number operations.
*
* @access private
* @package OpenID
*/
class Auth_OpenID_DiffieHellman {
var $mod;
var $gen;
var $private;
var $lib = null;
function Auth_OpenID_DiffieHellman($mod = null, $gen = null,
$private = null, $lib = null)
{
if ($lib === null) {
$this->lib = Auth_OpenID_getMathLib();
} else {
$this->lib = $lib;
}
if ($mod === null) {
$this->mod = $this->lib->init(Auth_OpenID_getDefaultMod());
} else {
$this->mod = $mod;
}
if ($gen === null) {
$this->gen = $this->lib->init(Auth_OpenID_getDefaultGen());
} else {
$this->gen = $gen;
}
if ($private === null) {
$r = $this->lib->rand($this->mod);
$this->private = $this->lib->add($r, 1);
} else {
$this->private = $private;
}
$this->public = $this->lib->powmod($this->gen, $this->private,
$this->mod);
}
function getSharedSecret($composite)
{
return $this->lib->powmod($composite, $this->private, $this->mod);
}
function getPublicKey()
{
return $this->public;
}
function usingDefaultValues()
{
return ($this->mod == Auth_OpenID_getDefaultMod() &&
$this->gen == Auth_OpenID_getDefaultGen());
}
function xorSecret($composite, $secret, $hash_func)
{
$dh_shared = $this->getSharedSecret($composite);
$dh_shared_str = $this->lib->longToBinary($dh_shared);
$hash_dh_shared = $hash_func($dh_shared_str);
$xsecret = "";
for ($i = 0; $i < Auth_OpenID::bytes($secret); $i++) {
$xsecret .= chr(ord($secret[$i]) ^ ord($hash_dh_shared[$i]));
}
return $xsecret;
}
}

View File

@ -1,606 +0,0 @@
<?php
/**
* The OpenID and Yadis discovery implementation for OpenID 1.2.
*/
require_once "Auth/OpenID.php";
require_once "Auth/OpenID/Parse.php";
require_once "Auth/OpenID/Message.php";
require_once "Auth/Yadis/XRIRes.php";
require_once "Auth/Yadis/Yadis.php";
// XML namespace value
define('Auth_OpenID_XMLNS_1_0', 'http://openid.net/xmlns/1.0');
// Yadis service types
define('Auth_OpenID_TYPE_1_2', 'http://openid.net/signon/1.2');
define('Auth_OpenID_TYPE_1_1', 'http://openid.net/signon/1.1');
define('Auth_OpenID_TYPE_1_0', 'http://openid.net/signon/1.0');
define('Auth_OpenID_TYPE_2_0_IDP', 'http://specs.openid.net/auth/2.0/server');
define('Auth_OpenID_TYPE_2_0', 'http://specs.openid.net/auth/2.0/signon');
define('Auth_OpenID_RP_RETURN_TO_URL_TYPE',
'http://specs.openid.net/auth/2.0/return_to');
function Auth_OpenID_getOpenIDTypeURIs()
{
return array(Auth_OpenID_TYPE_2_0_IDP,
Auth_OpenID_TYPE_2_0,
Auth_OpenID_TYPE_1_2,
Auth_OpenID_TYPE_1_1,
Auth_OpenID_TYPE_1_0);
}
function Auth_OpenID_getOpenIDConsumerTypeURIs()
{
return array(Auth_OpenID_RP_RETURN_TO_URL_TYPE);
}
/*
* Provides a user-readable interpretation of a type uri.
* Useful for error messages.
*/
function Auth_OpenID_getOpenIDTypeName($type_uri) {
switch ($type_uri) {
case Auth_OpenID_TYPE_2_0_IDP:
return 'OpenID 2.0 IDP';
case Auth_OpenID_TYPE_2_0:
return 'OpenID 2.0';
case Auth_OpenID_TYPE_1_2:
return 'OpenID 1.2';
case Auth_OpenID_TYPE_1_1:
return 'OpenID 1.1';
case Auth_OpenID_TYPE_1_0:
return 'OpenID 1.0';
case Auth_OpenID_RP_RETURN_TO_URL_TYPE:
return 'OpenID relying party';
}
}
/**
* Object representing an OpenID service endpoint.
*/
class Auth_OpenID_ServiceEndpoint {
function Auth_OpenID_ServiceEndpoint()
{
$this->claimed_id = null;
$this->server_url = null;
$this->type_uris = array();
$this->local_id = null;
$this->canonicalID = null;
$this->used_yadis = false; // whether this came from an XRDS
$this->display_identifier = null;
}
function getDisplayIdentifier()
{
if ($this->display_identifier) {
return $this->display_identifier;
}
if (! $this->claimed_id) {
return $this->claimed_id;
}
$parsed = parse_url($this->claimed_id);
$scheme = $parsed['scheme'];
$host = $parsed['host'];
$path = $parsed['path'];
if (array_key_exists('query', $parsed)) {
$query = $parsed['query'];
$no_frag = "$scheme://$host$path?$query";
} else {
$no_frag = "$scheme://$host$path";
}
return $no_frag;
}
function usesExtension($extension_uri)
{
return in_array($extension_uri, $this->type_uris);
}
function preferredNamespace()
{
if (in_array(Auth_OpenID_TYPE_2_0_IDP, $this->type_uris) ||
in_array(Auth_OpenID_TYPE_2_0, $this->type_uris)) {
return Auth_OpenID_OPENID2_NS;
} else {
return Auth_OpenID_OPENID1_NS;
}
}
/*
* Query this endpoint to see if it has any of the given type
* URIs. This is useful for implementing other endpoint classes
* that e.g. need to check for the presence of multiple versions
* of a single protocol.
*
* @param $type_uris The URIs that you wish to check
*
* @return all types that are in both in type_uris and
* $this->type_uris
*/
function matchTypes($type_uris)
{
$result = array();
foreach ($type_uris as $test_uri) {
if ($this->supportsType($test_uri)) {
$result[] = $test_uri;
}
}
return $result;
}
function supportsType($type_uri)
{
// Does this endpoint support this type?
return ((in_array($type_uri, $this->type_uris)) ||
(($type_uri == Auth_OpenID_TYPE_2_0) &&
$this->isOPIdentifier()));
}
function compatibilityMode()
{
return $this->preferredNamespace() != Auth_OpenID_OPENID2_NS;
}
function isOPIdentifier()
{
return in_array(Auth_OpenID_TYPE_2_0_IDP, $this->type_uris);
}
static function fromOPEndpointURL($op_endpoint_url)
{
// Construct an OP-Identifier OpenIDServiceEndpoint object for
// a given OP Endpoint URL
$obj = new Auth_OpenID_ServiceEndpoint();
$obj->server_url = $op_endpoint_url;
$obj->type_uris = array(Auth_OpenID_TYPE_2_0_IDP);
return $obj;
}
function parseService($yadis_url, $uri, $type_uris, $service_element)
{
// Set the state of this object based on the contents of the
// service element. Return true if successful, false if not
// (if findOPLocalIdentifier returns false).
$this->type_uris = $type_uris;
$this->server_url = $uri;
$this->used_yadis = true;
if (!$this->isOPIdentifier()) {
$this->claimed_id = $yadis_url;
$this->local_id = Auth_OpenID_findOPLocalIdentifier(
$service_element,
$this->type_uris);
if ($this->local_id === false) {
return false;
}
}
return true;
}
function getLocalID()
{
// Return the identifier that should be sent as the
// openid.identity_url parameter to the server.
if ($this->local_id === null && $this->canonicalID === null) {
return $this->claimed_id;
} else {
if ($this->local_id) {
return $this->local_id;
} else {
return $this->canonicalID;
}
}
}
/*
* Parse the given document as XRDS looking for OpenID consumer services.
*
* @return array of Auth_OpenID_ServiceEndpoint or null if the
* document cannot be parsed.
*/
function consumerFromXRDS($uri, $xrds_text)
{
$xrds =& Auth_Yadis_XRDS::parseXRDS($xrds_text);
if ($xrds) {
$yadis_services =
$xrds->services(array('filter_MatchesAnyOpenIDConsumerType'));
return Auth_OpenID_makeOpenIDEndpoints($uri, $yadis_services);
}
return null;
}
/*
* Parse the given document as XRDS looking for OpenID services.
*
* @return array of Auth_OpenID_ServiceEndpoint or null if the
* document cannot be parsed.
*/
static function fromXRDS($uri, $xrds_text)
{
$xrds = Auth_Yadis_XRDS::parseXRDS($xrds_text);
if ($xrds) {
$yadis_services =
$xrds->services(array('filter_MatchesAnyOpenIDType'));
return Auth_OpenID_makeOpenIDEndpoints($uri, $yadis_services);
}
return null;
}
/*
* Create endpoints from a DiscoveryResult.
*
* @param discoveryResult Auth_Yadis_DiscoveryResult
* @return array of Auth_OpenID_ServiceEndpoint or null if
* endpoints cannot be created.
*/
static function fromDiscoveryResult($discoveryResult)
{
if ($discoveryResult->isXRDS()) {
return Auth_OpenID_ServiceEndpoint::fromXRDS(
$discoveryResult->normalized_uri,
$discoveryResult->response_text);
} else {
return Auth_OpenID_ServiceEndpoint::fromHTML(
$discoveryResult->normalized_uri,
$discoveryResult->response_text);
}
}
static function fromHTML($uri, $html)
{
$discovery_types = array(
array(Auth_OpenID_TYPE_2_0,
'openid2.provider', 'openid2.local_id'),
array(Auth_OpenID_TYPE_1_1,
'openid.server', 'openid.delegate')
);
$services = array();
foreach ($discovery_types as $triple) {
list($type_uri, $server_rel, $delegate_rel) = $triple;
$urls = Auth_OpenID_legacy_discover($html, $server_rel,
$delegate_rel);
if ($urls === false) {
continue;
}
list($delegate_url, $server_url) = $urls;
$service = new Auth_OpenID_ServiceEndpoint();
$service->claimed_id = $uri;
$service->local_id = $delegate_url;
$service->server_url = $server_url;
$service->type_uris = array($type_uri);
$services[] = $service;
}
return $services;
}
function copy()
{
$x = new Auth_OpenID_ServiceEndpoint();
$x->claimed_id = $this->claimed_id;
$x->server_url = $this->server_url;
$x->type_uris = $this->type_uris;
$x->local_id = $this->local_id;
$x->canonicalID = $this->canonicalID;
$x->used_yadis = $this->used_yadis;
return $x;
}
}
function Auth_OpenID_findOPLocalIdentifier($service, $type_uris)
{
// Extract a openid:Delegate value from a Yadis Service element.
// If no delegate is found, returns null. Returns false on
// discovery failure (when multiple delegate/localID tags have
// different values).
$service->parser->registerNamespace('openid',
Auth_OpenID_XMLNS_1_0);
$service->parser->registerNamespace('xrd',
Auth_Yadis_XMLNS_XRD_2_0);
$parser = $service->parser;
$permitted_tags = array();
if (in_array(Auth_OpenID_TYPE_1_1, $type_uris) ||
in_array(Auth_OpenID_TYPE_1_0, $type_uris)) {
$permitted_tags[] = 'openid:Delegate';
}
if (in_array(Auth_OpenID_TYPE_2_0, $type_uris)) {
$permitted_tags[] = 'xrd:LocalID';
}
$local_id = null;
foreach ($permitted_tags as $tag_name) {
$tags = $service->getElements($tag_name);
foreach ($tags as $tag) {
$content = $parser->content($tag);
if ($local_id === null) {
$local_id = $content;
} else if ($local_id != $content) {
return false;
}
}
}
return $local_id;
}
function filter_MatchesAnyOpenIDType($service)
{
$uris = $service->getTypes();
foreach ($uris as $uri) {
if (in_array($uri, Auth_OpenID_getOpenIDTypeURIs())) {
return true;
}
}
return false;
}
function filter_MatchesAnyOpenIDConsumerType(&$service)
{
$uris = $service->getTypes();
foreach ($uris as $uri) {
if (in_array($uri, Auth_OpenID_getOpenIDConsumerTypeURIs())) {
return true;
}
}
return false;
}
function Auth_OpenID_bestMatchingService($service, $preferred_types)
{
// Return the index of the first matching type, or something
// higher if no type matches.
//
// This provides an ordering in which service elements that
// contain a type that comes earlier in the preferred types list
// come before service elements that come later. If a service
// element has more than one type, the most preferred one wins.
foreach ($preferred_types as $index => $typ) {
if (in_array($typ, $service->type_uris)) {
return $index;
}
}
return count($preferred_types);
}
function Auth_OpenID_arrangeByType($service_list, $preferred_types)
{
// Rearrange service_list in a new list so services are ordered by
// types listed in preferred_types. Return the new list.
// Build a list with the service elements in tuples whose
// comparison will prefer the one with the best matching service
$prio_services = array();
foreach ($service_list as $index => $service) {
$prio_services[] = array(Auth_OpenID_bestMatchingService($service,
$preferred_types),
$index, $service);
}
sort($prio_services);
// Now that the services are sorted by priority, remove the sort
// keys from the list.
foreach ($prio_services as $index => $s) {
$prio_services[$index] = $prio_services[$index][2];
}
return $prio_services;
}
// Extract OP Identifier services. If none found, return the rest,
// sorted with most preferred first according to
// OpenIDServiceEndpoint.openid_type_uris.
//
// openid_services is a list of OpenIDServiceEndpoint objects.
//
// Returns a list of OpenIDServiceEndpoint objects."""
function Auth_OpenID_getOPOrUserServices($openid_services)
{
$op_services = Auth_OpenID_arrangeByType($openid_services,
array(Auth_OpenID_TYPE_2_0_IDP));
$openid_services = Auth_OpenID_arrangeByType($openid_services,
Auth_OpenID_getOpenIDTypeURIs());
if ($op_services) {
return $op_services;
} else {
return $openid_services;
}
}
function Auth_OpenID_makeOpenIDEndpoints($uri, $yadis_services)
{
$s = array();
if (!$yadis_services) {
return $s;
}
foreach ($yadis_services as $service) {
$type_uris = $service->getTypes();
$uris = $service->getURIs();
// If any Type URIs match and there is an endpoint URI
// specified, then this is an OpenID endpoint
if ($type_uris &&
$uris) {
foreach ($uris as $service_uri) {
$openid_endpoint = new Auth_OpenID_ServiceEndpoint();
if ($openid_endpoint->parseService($uri,
$service_uri,
$type_uris,
$service)) {
$s[] = $openid_endpoint;
}
}
}
}
return $s;
}
function Auth_OpenID_discoverWithYadis($uri, $fetcher,
$endpoint_filter='Auth_OpenID_getOPOrUserServices',
$discover_function=null)
{
// Discover OpenID services for a URI. Tries Yadis and falls back
// on old-style <link rel='...'> discovery if Yadis fails.
// Might raise a yadis.discover.DiscoveryFailure if no document
// came back for that URI at all. I don't think falling back to
// OpenID 1.0 discovery on the same URL will help, so don't bother
// to catch it.
if ($discover_function === null) {
$discover_function = array('Auth_Yadis_Yadis', 'discover');
}
$openid_services = array();
$response = call_user_func_array($discover_function,
array($uri, $fetcher));
$yadis_url = $response->normalized_uri;
$yadis_services = array();
if ($response->isFailure() && !$response->isXRDS()) {
return array($uri, array());
}
$openid_services = Auth_OpenID_ServiceEndpoint::fromXRDS(
$yadis_url,
$response->response_text);
if (!$openid_services) {
if ($response->isXRDS()) {
return Auth_OpenID_discoverWithoutYadis($uri,
$fetcher);
}
// Try to parse the response as HTML to get OpenID 1.0/1.1
// <link rel="...">
$openid_services = Auth_OpenID_ServiceEndpoint::fromHTML(
$yadis_url,
$response->response_text);
}
$openid_services = call_user_func_array($endpoint_filter,
array($openid_services));
return array($yadis_url, $openid_services);
}
function Auth_OpenID_discoverURI($uri, $fetcher)
{
$uri = Auth_OpenID::normalizeUrl($uri);
return Auth_OpenID_discoverWithYadis($uri, $fetcher);
}
function Auth_OpenID_discoverWithoutYadis($uri, $fetcher)
{
$http_resp = @$fetcher->get($uri);
if ($http_resp->status != 200 and $http_resp->status != 206) {
return array($uri, array());
}
$identity_url = $http_resp->final_url;
// Try to parse the response as HTML to get OpenID 1.0/1.1 <link
// rel="...">
$openid_services = Auth_OpenID_ServiceEndpoint::fromHTML(
$identity_url,
$http_resp->body);
return array($identity_url, $openid_services);
}
function Auth_OpenID_discoverXRI($iname, $fetcher)
{
$resolver = new Auth_Yadis_ProxyResolver($fetcher);
list($canonicalID, $yadis_services) =
$resolver->query($iname,
Auth_OpenID_getOpenIDTypeURIs(),
array('filter_MatchesAnyOpenIDType'));
$openid_services = Auth_OpenID_makeOpenIDEndpoints($iname,
$yadis_services);
$openid_services = Auth_OpenID_getOPOrUserServices($openid_services);
for ($i = 0; $i < count($openid_services); $i++) {
$openid_services[$i]->canonicalID = $canonicalID;
$openid_services[$i]->claimed_id = $canonicalID;
$openid_services[$i]->display_identifier = $iname;
}
// FIXME: returned xri should probably be in some normal form
return array($iname, $openid_services);
}
function Auth_OpenID_discover($uri, $fetcher)
{
// If the fetcher (i.e., PHP) doesn't support SSL, we can't do
// discovery on an HTTPS URL.
if ($fetcher->isHTTPS($uri) && !$fetcher->supportsSSL()) {
return array($uri, array());
}
if (Auth_Yadis_identifierScheme($uri) == 'XRI') {
$result = Auth_OpenID_discoverXRI($uri, $fetcher);
} else {
$result = Auth_OpenID_discoverURI($uri, $fetcher);
}
// If the fetcher doesn't support SSL, we can't interact with
// HTTPS server URLs; remove those endpoints from the list.
if (!$fetcher->supportsSSL()) {
$http_endpoints = array();
list($new_uri, $endpoints) = $result;
foreach ($endpoints as $e) {
if (!$fetcher->isHTTPS($e->server_url)) {
$http_endpoints[] = $e;
}
}
$result = array($new_uri, $http_endpoints);
}
return $result;
}

View File

@ -1,99 +0,0 @@
<?php
/**
* This file supplies a dumb store backend for OpenID servers and
* consumers.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* Import the interface for creating a new store class.
*/
require_once 'Auth/OpenID/Interface.php';
require_once 'Auth/OpenID/HMAC.php';
/**
* This is a store for use in the worst case, when you have no way of
* saving state on the consumer site. Using this store makes the
* consumer vulnerable to replay attacks, as it's unable to use
* nonces. Avoid using this store if it is at all possible.
*
* Most of the methods of this class are implementation details.
* Users of this class need to worry only about the constructor.
*
* @package OpenID
*/
class Auth_OpenID_DumbStore extends Auth_OpenID_OpenIDStore {
/**
* Creates a new {@link Auth_OpenID_DumbStore} instance. For the security
* of the tokens generated by the library, this class attempts to
* at least have a secure implementation of getAuthKey.
*
* When you create an instance of this class, pass in a secret
* phrase. The phrase is hashed with sha1 to make it the correct
* length and form for an auth key. That allows you to use a long
* string as the secret phrase, which means you can make it very
* difficult to guess.
*
* Each {@link Auth_OpenID_DumbStore} instance that is created for use by
* your consumer site needs to use the same $secret_phrase.
*
* @param string secret_phrase The phrase used to create the auth
* key returned by getAuthKey
*/
function Auth_OpenID_DumbStore($secret_phrase)
{
$this->auth_key = Auth_OpenID_SHA1($secret_phrase);
}
/**
* This implementation does nothing.
*/
function storeAssociation($server_url, $association)
{
}
/**
* This implementation always returns null.
*/
function getAssociation($server_url, $handle = null)
{
return null;
}
/**
* This implementation always returns false.
*/
function removeAssociation($server_url, $handle)
{
return false;
}
/**
* In a system truly limited to dumb mode, nonces must all be
* accepted. This therefore always returns true, which makes
* replay attacks feasible.
*/
function useNonce($server_url, $timestamp, $salt)
{
return true;
}
/**
* This method returns the auth key generated by the constructor.
*/
function getAuthKey()
{
return $this->auth_key;
}
}

View File

@ -1,61 +0,0 @@
<?php
/**
* An interface for OpenID extensions.
*
* @package OpenID
*/
/**
* Require the Message implementation.
*/
require_once 'Auth/OpenID/Message.php';
/**
* A base class for accessing extension request and response data for
* the OpenID 2 protocol.
*
* @package OpenID
*/
class Auth_OpenID_Extension {
/**
* ns_uri: The namespace to which to add the arguments for this
* extension
*/
var $ns_uri = null;
var $ns_alias = null;
/**
* Get the string arguments that should be added to an OpenID
* message for this extension.
*/
function getExtensionArgs()
{
return null;
}
/**
* Add the arguments from this extension to the provided message.
*
* Returns the message with the extension arguments added.
*/
function toMessage($message)
{
$implicit = $message->isOpenID1();
$added = $message->namespaces->addAlias($this->ns_uri,
$this->ns_alias,
$implicit);
if ($added === null) {
if ($message->namespaces->getAlias($this->ns_uri) !=
$this->ns_alias) {
return null;
}
}
$message->updateArgs($this->ns_uri,
$this->getExtensionArgs());
return $message;
}
}

View File

@ -1,618 +0,0 @@
<?php
/**
* This file supplies a Memcached store backend for OpenID servers and
* consumers.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* Require base class for creating a new interface.
*/
require_once 'Auth/OpenID.php';
require_once 'Auth/OpenID/Interface.php';
require_once 'Auth/OpenID/HMAC.php';
require_once 'Auth/OpenID/Nonce.php';
/**
* This is a filesystem-based store for OpenID associations and
* nonces. This store should be safe for use in concurrent systems on
* both windows and unix (excluding NFS filesystems). There are a
* couple race conditions in the system, but those failure cases have
* been set up in such a way that the worst-case behavior is someone
* having to try to log in a second time.
*
* Most of the methods of this class are implementation details.
* People wishing to just use this store need only pay attention to
* the constructor.
*
* @package OpenID
*/
class Auth_OpenID_FileStore extends Auth_OpenID_OpenIDStore {
/**
* Initializes a new {@link Auth_OpenID_FileStore}. This
* initializes the nonce and association directories, which are
* subdirectories of the directory passed in.
*
* @param string $directory This is the directory to put the store
* directories in.
*/
function Auth_OpenID_FileStore($directory)
{
if (!Auth_OpenID::ensureDir($directory)) {
trigger_error('Not a directory and failed to create: '
. $directory, E_USER_ERROR);
}
$directory = realpath($directory);
$this->directory = $directory;
$this->active = true;
$this->nonce_dir = $directory . DIRECTORY_SEPARATOR . 'nonces';
$this->association_dir = $directory . DIRECTORY_SEPARATOR .
'associations';
// Temp dir must be on the same filesystem as the assciations
// $directory.
$this->temp_dir = $directory . DIRECTORY_SEPARATOR . 'temp';
$this->max_nonce_age = 6 * 60 * 60; // Six hours, in seconds
if (!$this->_setup()) {
trigger_error('Failed to initialize OpenID file store in ' .
$directory, E_USER_ERROR);
}
}
function destroy()
{
Auth_OpenID_FileStore::_rmtree($this->directory);
$this->active = false;
}
/**
* Make sure that the directories in which we store our data
* exist.
*
* @access private
*/
function _setup()
{
return (Auth_OpenID::ensureDir($this->nonce_dir) &&
Auth_OpenID::ensureDir($this->association_dir) &&
Auth_OpenID::ensureDir($this->temp_dir));
}
/**
* Create a temporary file on the same filesystem as
* $this->association_dir.
*
* The temporary directory should not be cleaned if there are any
* processes using the store. If there is no active process using
* the store, it is safe to remove all of the files in the
* temporary directory.
*
* @return array ($fd, $filename)
* @access private
*/
function _mktemp()
{
$name = Auth_OpenID_FileStore::_mkstemp($dir = $this->temp_dir);
$file_obj = @fopen($name, 'wb');
if ($file_obj !== false) {
return array($file_obj, $name);
} else {
Auth_OpenID_FileStore::_removeIfPresent($name);
}
}
function cleanupNonces()
{
global $Auth_OpenID_SKEW;
$nonces = Auth_OpenID_FileStore::_listdir($this->nonce_dir);
$now = time();
$removed = 0;
// Check all nonces for expiry
foreach ($nonces as $nonce_fname) {
$base = basename($nonce_fname);
$parts = explode('-', $base, 2);
$timestamp = $parts[0];
$timestamp = intval($timestamp, 16);
if (abs($timestamp - $now) > $Auth_OpenID_SKEW) {
Auth_OpenID_FileStore::_removeIfPresent($nonce_fname);
$removed += 1;
}
}
return $removed;
}
/**
* Create a unique filename for a given server url and
* handle. This implementation does not assume anything about the
* format of the handle. The filename that is returned will
* contain the domain name from the server URL for ease of human
* inspection of the data directory.
*
* @return string $filename
*/
function getAssociationFilename($server_url, $handle)
{
if (!$this->active) {
trigger_error("FileStore no longer active", E_USER_ERROR);
return null;
}
if (strpos($server_url, '://') === false) {
trigger_error(sprintf("Bad server URL: %s", $server_url),
E_USER_WARNING);
return null;
}
list($proto, $rest) = explode('://', $server_url, 2);
$parts = explode('/', $rest);
$domain = Auth_OpenID_FileStore::_filenameEscape($parts[0]);
$url_hash = Auth_OpenID_FileStore::_safe64($server_url);
if ($handle) {
$handle_hash = Auth_OpenID_FileStore::_safe64($handle);
} else {
$handle_hash = '';
}
$filename = sprintf('%s-%s-%s-%s', $proto, $domain, $url_hash,
$handle_hash);
return $this->association_dir. DIRECTORY_SEPARATOR . $filename;
}
/**
* Store an association in the association directory.
*/
function storeAssociation($server_url, $association)
{
if (!$this->active) {
trigger_error("FileStore no longer active", E_USER_ERROR);
return false;
}
$association_s = $association->serialize();
$filename = $this->getAssociationFilename($server_url,
$association->handle);
list($tmp_file, $tmp) = $this->_mktemp();
if (!$tmp_file) {
trigger_error("_mktemp didn't return a valid file descriptor",
E_USER_WARNING);
return false;
}
fwrite($tmp_file, $association_s);
fflush($tmp_file);
fclose($tmp_file);
if (@rename($tmp, $filename)) {
return true;
} else {
// In case we are running on Windows, try unlinking the
// file in case it exists.
@unlink($filename);
// Now the target should not exist. Try renaming again,
// giving up if it fails.
if (@rename($tmp, $filename)) {
return true;
}
}
// If there was an error, don't leave the temporary file
// around.
Auth_OpenID_FileStore::_removeIfPresent($tmp);
return false;
}
/**
* Retrieve an association. If no handle is specified, return the
* association with the most recent issue time.
*
* @return mixed $association
*/
function getAssociation($server_url, $handle = null)
{
if (!$this->active) {
trigger_error("FileStore no longer active", E_USER_ERROR);
return null;
}
if ($handle === null) {
$handle = '';
}
// The filename with the empty handle is a prefix of all other
// associations for the given server URL.
$filename = $this->getAssociationFilename($server_url, $handle);
if ($handle) {
return $this->_getAssociation($filename);
} else {
$association_files =
Auth_OpenID_FileStore::_listdir($this->association_dir);
$matching_files = array();
// strip off the path to do the comparison
$name = basename($filename);
foreach ($association_files as $association_file) {
$base = basename($association_file);
if (strpos($base, $name) === 0) {
$matching_files[] = $association_file;
}
}
$matching_associations = array();
// read the matching files and sort by time issued
foreach ($matching_files as $full_name) {
$association = $this->_getAssociation($full_name);
if ($association !== null) {
$matching_associations[] = array($association->issued,
$association);
}
}
$issued = array();
$assocs = array();
foreach ($matching_associations as $key => $assoc) {
$issued[$key] = $assoc[0];
$assocs[$key] = $assoc[1];
}
array_multisort($issued, SORT_DESC, $assocs, SORT_DESC,
$matching_associations);
// return the most recently issued one.
if ($matching_associations) {
list($issued, $assoc) = $matching_associations[0];
return $assoc;
} else {
return null;
}
}
}
/**
* @access private
*/
function _getAssociation($filename)
{
if (!$this->active) {
trigger_error("FileStore no longer active", E_USER_ERROR);
return null;
}
$assoc_file = @fopen($filename, 'rb');
if ($assoc_file === false) {
return null;
}
$assoc_s = fread($assoc_file, filesize($filename));
fclose($assoc_file);
if (!$assoc_s) {
return null;
}
$association =
Auth_OpenID_Association::deserialize('Auth_OpenID_Association',
$assoc_s);
if (!$association) {
Auth_OpenID_FileStore::_removeIfPresent($filename);
return null;
}
if ($association->getExpiresIn() == 0) {
Auth_OpenID_FileStore::_removeIfPresent($filename);
return null;
} else {
return $association;
}
}
/**
* Remove an association if it exists. Do nothing if it does not.
*
* @return bool $success
*/
function removeAssociation($server_url, $handle)
{
if (!$this->active) {
trigger_error("FileStore no longer active", E_USER_ERROR);
return null;
}
$assoc = $this->getAssociation($server_url, $handle);
if ($assoc === null) {
return false;
} else {
$filename = $this->getAssociationFilename($server_url, $handle);
return Auth_OpenID_FileStore::_removeIfPresent($filename);
}
}
/**
* Return whether this nonce is present. As a side effect, mark it
* as no longer present.
*
* @return bool $present
*/
function useNonce($server_url, $timestamp, $salt)
{
global $Auth_OpenID_SKEW;
if (!$this->active) {
trigger_error("FileStore no longer active", E_USER_ERROR);
return null;
}
if ( abs($timestamp - time()) > $Auth_OpenID_SKEW ) {
return false;
}
if ($server_url) {
list($proto, $rest) = explode('://', $server_url, 2);
} else {
$proto = '';
$rest = '';
}
$parts = explode('/', $rest, 2);
$domain = $this->_filenameEscape($parts[0]);
$url_hash = $this->_safe64($server_url);
$salt_hash = $this->_safe64($salt);
$filename = sprintf('%08x-%s-%s-%s-%s', $timestamp, $proto,
$domain, $url_hash, $salt_hash);
$filename = $this->nonce_dir . DIRECTORY_SEPARATOR . $filename;
$result = @fopen($filename, 'x');
if ($result === false) {
return false;
} else {
fclose($result);
return true;
}
}
/**
* Remove expired entries from the database. This is potentially
* expensive, so only run when it is acceptable to take time.
*
* @access private
*/
function _allAssocs()
{
$all_associations = array();
$association_filenames =
Auth_OpenID_FileStore::_listdir($this->association_dir);
foreach ($association_filenames as $association_filename) {
$association_file = fopen($association_filename, 'rb');
if ($association_file !== false) {
$assoc_s = fread($association_file,
filesize($association_filename));
fclose($association_file);
// Remove expired or corrupted associations
$association =
Auth_OpenID_Association::deserialize(
'Auth_OpenID_Association', $assoc_s);
if ($association === null) {
Auth_OpenID_FileStore::_removeIfPresent(
$association_filename);
} else {
if ($association->getExpiresIn() == 0) {
$all_associations[] = array($association_filename,
$association);
}
}
}
}
return $all_associations;
}
function clean()
{
if (!$this->active) {
trigger_error("FileStore no longer active", E_USER_ERROR);
return null;
}
$nonces = Auth_OpenID_FileStore::_listdir($this->nonce_dir);
$now = time();
// Check all nonces for expiry
foreach ($nonces as $nonce) {
if (!Auth_OpenID_checkTimestamp($nonce, $now)) {
$filename = $this->nonce_dir . DIRECTORY_SEPARATOR . $nonce;
Auth_OpenID_FileStore::_removeIfPresent($filename);
}
}
foreach ($this->_allAssocs() as $pair) {
list($assoc_filename, $assoc) = $pair;
if ($assoc->getExpiresIn() == 0) {
Auth_OpenID_FileStore::_removeIfPresent($assoc_filename);
}
}
}
/**
* @access private
*/
function _rmtree($dir)
{
if ($dir[strlen($dir) - 1] != DIRECTORY_SEPARATOR) {
$dir .= DIRECTORY_SEPARATOR;
}
if ($handle = opendir($dir)) {
while ($item = readdir($handle)) {
if (!in_array($item, array('.', '..'))) {
if (is_dir($dir . $item)) {
if (!Auth_OpenID_FileStore::_rmtree($dir . $item)) {
return false;
}
} else if (is_file($dir . $item)) {
if (!unlink($dir . $item)) {
return false;
}
}
}
}
closedir($handle);
if (!@rmdir($dir)) {
return false;
}
return true;
} else {
// Couldn't open directory.
return false;
}
}
/**
* @access private
*/
function _mkstemp($dir)
{
foreach (range(0, 4) as $i) {
$name = tempnam($dir, "php_openid_filestore_");
if ($name !== false) {
return $name;
}
}
return false;
}
/**
* @access private
*/
static function _mkdtemp($dir)
{
foreach (range(0, 4) as $i) {
$name = $dir . strval(DIRECTORY_SEPARATOR) . strval(getmypid()) .
"-" . strval(rand(1, time()));
if (!mkdir($name, 0700)) {
return false;
} else {
return $name;
}
}
return false;
}
/**
* @access private
*/
function _listdir($dir)
{
$handle = opendir($dir);
$files = array();
while (false !== ($filename = readdir($handle))) {
if (!in_array($filename, array('.', '..'))) {
$files[] = $dir . DIRECTORY_SEPARATOR . $filename;
}
}
return $files;
}
/**
* @access private
*/
function _isFilenameSafe($char)
{
$_Auth_OpenID_filename_allowed = Auth_OpenID_letters .
Auth_OpenID_digits . ".";
return (strpos($_Auth_OpenID_filename_allowed, $char) !== false);
}
/**
* @access private
*/
function _safe64($str)
{
$h64 = base64_encode(Auth_OpenID_SHA1($str));
$h64 = str_replace('+', '_', $h64);
$h64 = str_replace('/', '.', $h64);
$h64 = str_replace('=', '', $h64);
return $h64;
}
/**
* @access private
*/
function _filenameEscape($str)
{
$filename = "";
$b = Auth_OpenID::toBytes($str);
for ($i = 0; $i < count($b); $i++) {
$c = $b[$i];
if (Auth_OpenID_FileStore::_isFilenameSafe($c)) {
$filename .= $c;
} else {
$filename .= sprintf("_%02X", ord($c));
}
}
return $filename;
}
/**
* Attempt to remove a file, returning whether the file existed at
* the time of the call.
*
* @access private
* @return bool $result True if the file was present, false if not.
*/
function _removeIfPresent($filename)
{
return @unlink($filename);
}
function cleanupAssociations()
{
$removed = 0;
foreach ($this->_allAssocs() as $pair) {
list($assoc_filename, $assoc) = $pair;
if ($assoc->getExpiresIn() == 0) {
$this->_removeIfPresent($assoc_filename);
$removed += 1;
}
}
return $removed;
}
}

View File

@ -1,105 +0,0 @@
<?php
/**
* This is the HMACSHA1 implementation for the OpenID library.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @access private
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
require_once 'Auth/OpenID.php';
/**
* SHA1_BLOCKSIZE is this module's SHA1 blocksize used by the fallback
* implementation.
*/
define('Auth_OpenID_SHA1_BLOCKSIZE', 64);
function Auth_OpenID_SHA1($text)
{
if (function_exists('hash') &&
function_exists('hash_algos') &&
(in_array('sha1', hash_algos()))) {
// PHP 5 case (sometimes): 'hash' available and 'sha1' algo
// supported.
return hash('sha1', $text, true);
} else if (function_exists('sha1')) {
// PHP 4 case: 'sha1' available.
$hex = sha1($text);
$raw = '';
for ($i = 0; $i < 40; $i += 2) {
$hexcode = substr($hex, $i, 2);
$charcode = (int)base_convert($hexcode, 16, 10);
$raw .= chr($charcode);
}
return $raw;
} else {
// Explode.
trigger_error('No SHA1 function found', E_USER_ERROR);
}
}
/**
* Compute an HMAC/SHA1 hash.
*
* @access private
* @param string $key The HMAC key
* @param string $text The message text to hash
* @return string $mac The MAC
*/
function Auth_OpenID_HMACSHA1($key, $text)
{
if (Auth_OpenID::bytes($key) > Auth_OpenID_SHA1_BLOCKSIZE) {
$key = Auth_OpenID_SHA1($key, true);
}
if (function_exists('hash_hmac') &&
function_exists('hash_algos') &&
(in_array('sha1', hash_algos()))) {
return hash_hmac('sha1', $text, $key, true);
}
// Home-made solution
$key = str_pad($key, Auth_OpenID_SHA1_BLOCKSIZE, chr(0x00));
$ipad = str_repeat(chr(0x36), Auth_OpenID_SHA1_BLOCKSIZE);
$opad = str_repeat(chr(0x5c), Auth_OpenID_SHA1_BLOCKSIZE);
$hash1 = Auth_OpenID_SHA1(($key ^ $ipad) . $text, true);
$hmac = Auth_OpenID_SHA1(($key ^ $opad) . $hash1, true);
return $hmac;
}
if (function_exists('hash') &&
function_exists('hash_algos') &&
(in_array('sha256', hash_algos()))) {
function Auth_OpenID_SHA256($text)
{
// PHP 5 case: 'hash' available and 'sha256' algo supported.
return hash('sha256', $text, true);
}
define('Auth_OpenID_SHA256_SUPPORTED', true);
} else {
define('Auth_OpenID_SHA256_SUPPORTED', false);
}
if (function_exists('hash_hmac') &&
function_exists('hash_algos') &&
(in_array('sha256', hash_algos()))) {
function Auth_OpenID_HMACSHA256($key, $text)
{
// Return raw MAC (not hex string).
return hash_hmac('sha256', $text, $key, true);
}
define('Auth_OpenID_HMACSHA256_SUPPORTED', true);
} else {
define('Auth_OpenID_HMACSHA256_SUPPORTED', false);
}

View File

@ -1,196 +0,0 @@
<?php
/**
* This file specifies the interface for PHP OpenID store implementations.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* This is the interface for the store objects the OpenID library
* uses. It is a single class that provides all of the persistence
* mechanisms that the OpenID library needs, for both servers and
* consumers. If you want to create an SQL-driven store, please see
* then {@link Auth_OpenID_SQLStore} class.
*
* Change: Version 2.0 removed the storeNonce, getAuthKey, and isDumb
* methods, and changed the behavior of the useNonce method to support
* one-way nonces.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
*/
class Auth_OpenID_OpenIDStore {
/**
* This method puts an Association object into storage,
* retrievable by server URL and handle.
*
* @param string $server_url The URL of the identity server that
* this association is with. Because of the way the server portion
* of the library uses this interface, don't assume there are any
* limitations on the character set of the input string. In
* particular, expect to see unescaped non-url-safe characters in
* the server_url field.
*
* @param Association $association The Association to store.
*/
function storeAssociation($server_url, $association)
{
trigger_error("Auth_OpenID_OpenIDStore::storeAssociation ".
"not implemented", E_USER_ERROR);
}
/*
* Remove expired nonces from the store.
*
* Discards any nonce from storage that is old enough that its
* timestamp would not pass useNonce().
*
* This method is not called in the normal operation of the
* library. It provides a way for store admins to keep their
* storage from filling up with expired data.
*
* @return the number of nonces expired
*/
function cleanupNonces()
{
trigger_error("Auth_OpenID_OpenIDStore::cleanupNonces ".
"not implemented", E_USER_ERROR);
}
/*
* Remove expired associations from the store.
*
* This method is not called in the normal operation of the
* library. It provides a way for store admins to keep their
* storage from filling up with expired data.
*
* @return the number of associations expired.
*/
function cleanupAssociations()
{
trigger_error("Auth_OpenID_OpenIDStore::cleanupAssociations ".
"not implemented", E_USER_ERROR);
}
/*
* Shortcut for cleanupNonces(), cleanupAssociations().
*
* This method is not called in the normal operation of the
* library. It provides a way for store admins to keep their
* storage from filling up with expired data.
*/
function cleanup()
{
return array($this->cleanupNonces(),
$this->cleanupAssociations());
}
/**
* Report whether this storage supports cleanup
*/
function supportsCleanup()
{
return true;
}
/**
* This method returns an Association object from storage that
* matches the server URL and, if specified, handle. It returns
* null if no such association is found or if the matching
* association is expired.
*
* If no handle is specified, the store may return any association
* which matches the server URL. If multiple associations are
* valid, the recommended return value for this method is the one
* most recently issued.
*
* This method is allowed (and encouraged) to garbage collect
* expired associations when found. This method must not return
* expired associations.
*
* @param string $server_url The URL of the identity server to get
* the association for. Because of the way the server portion of
* the library uses this interface, don't assume there are any
* limitations on the character set of the input string. In
* particular, expect to see unescaped non-url-safe characters in
* the server_url field.
*
* @param mixed $handle This optional parameter is the handle of
* the specific association to get. If no specific handle is
* provided, any valid association matching the server URL is
* returned.
*
* @return Association The Association for the given identity
* server.
*/
function getAssociation($server_url, $handle = null)
{
trigger_error("Auth_OpenID_OpenIDStore::getAssociation ".
"not implemented", E_USER_ERROR);
}
/**
* This method removes the matching association if it's found, and
* returns whether the association was removed or not.
*
* @param string $server_url The URL of the identity server the
* association to remove belongs to. Because of the way the server
* portion of the library uses this interface, don't assume there
* are any limitations on the character set of the input
* string. In particular, expect to see unescaped non-url-safe
* characters in the server_url field.
*
* @param string $handle This is the handle of the association to
* remove. If there isn't an association found that matches both
* the given URL and handle, then there was no matching handle
* found.
*
* @return mixed Returns whether or not the given association existed.
*/
function removeAssociation($server_url, $handle)
{
trigger_error("Auth_OpenID_OpenIDStore::removeAssociation ".
"not implemented", E_USER_ERROR);
}
/**
* Called when using a nonce.
*
* This method should return C{True} if the nonce has not been
* used before, and store it for a while to make sure nobody
* tries to use the same value again. If the nonce has already
* been used, return C{False}.
*
* Change: In earlier versions, round-trip nonces were used and a
* nonce was only valid if it had been previously stored with
* storeNonce. Version 2.0 uses one-way nonces, requiring a
* different implementation here that does not depend on a
* storeNonce call. (storeNonce is no longer part of the
* interface.
*
* @param string $nonce The nonce to use.
*
* @return bool Whether or not the nonce was valid.
*/
function useNonce($server_url, $timestamp, $salt)
{
trigger_error("Auth_OpenID_OpenIDStore::useNonce ".
"not implemented", E_USER_ERROR);
}
/**
* Removes all entries from the store; implementation is optional.
*/
function reset()
{
}
}

View File

@ -1,111 +0,0 @@
<?php
/**
* OpenID protocol key-value/comma-newline format parsing and
* serialization
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @access private
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* Container for key-value/comma-newline OpenID format and parsing
*/
class Auth_OpenID_KVForm {
/**
* Convert an OpenID colon/newline separated string into an
* associative array
*
* @static
* @access private
*/
static function toArray($kvs, $strict=false)
{
$lines = explode("\n", $kvs);
$last = array_pop($lines);
if ($last !== '') {
array_push($lines, $last);
if ($strict) {
return false;
}
}
$values = array();
for ($lineno = 0; $lineno < count($lines); $lineno++) {
$line = $lines[$lineno];
$kv = explode(':', $line, 2);
if (count($kv) != 2) {
if ($strict) {
return false;
}
continue;
}
$key = $kv[0];
$tkey = trim($key);
if ($tkey != $key) {
if ($strict) {
return false;
}
}
$value = $kv[1];
$tval = trim($value);
if ($tval != $value) {
if ($strict) {
return false;
}
}
$values[$tkey] = $tval;
}
return $values;
}
/**
* Convert an array into an OpenID colon/newline separated string
*
* @static
* @access private
*/
static function fromArray($values)
{
if ($values === null) {
return null;
}
ksort($values);
$serialized = '';
foreach ($values as $key => $value) {
if (is_array($value)) {
list($key, $value) = array($value[0], $value[1]);
}
if (strpos($key, ':') !== false) {
return null;
}
if (strpos($key, "\n") !== false) {
return null;
}
if (strpos($value, "\n") !== false) {
return null;
}
$serialized .= "$key:$value\n";
}
return $serialized;
}
}

View File

@ -1,413 +0,0 @@
<?php
/**
* SQL-backed OpenID stores for use with PEAR::MDB2.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005 Janrain, Inc.
* @license http://www.gnu.org/copyleft/lesser.html LGPL
*/
require_once 'MDB2.php';
/**
* @access private
*/
require_once 'Auth/OpenID/Interface.php';
/**
* @access private
*/
require_once 'Auth/OpenID.php';
/**
* @access private
*/
require_once 'Auth/OpenID/Nonce.php';
/**
* This store uses a PEAR::MDB2 connection to store persistence
* information.
*
* The table names used are determined by the class variables
* associations_table_name and nonces_table_name. To change the name
* of the tables used, pass new table names into the constructor.
*
* To create the tables with the proper schema, see the createTables
* method.
*
* @package OpenID
*/
class Auth_OpenID_MDB2Store extends Auth_OpenID_OpenIDStore {
/**
* This creates a new MDB2Store instance. It requires an
* established database connection be given to it, and it allows
* overriding the default table names.
*
* @param connection $connection This must be an established
* connection to a database of the correct type for the SQLStore
* subclass you're using. This must be a PEAR::MDB2 connection
* handle.
*
* @param associations_table: This is an optional parameter to
* specify the name of the table used for storing associations.
* The default value is 'oid_associations'.
*
* @param nonces_table: This is an optional parameter to specify
* the name of the table used for storing nonces. The default
* value is 'oid_nonces'.
*/
function Auth_OpenID_MDB2Store($connection,
$associations_table = null,
$nonces_table = null)
{
$this->associations_table_name = "oid_associations";
$this->nonces_table_name = "oid_nonces";
// Check the connection object type to be sure it's a PEAR
// database connection.
if (!is_object($connection) ||
!is_subclass_of($connection, 'mdb2_driver_common')) {
trigger_error("Auth_OpenID_MDB2Store expected PEAR connection " .
"object (got ".get_class($connection).")",
E_USER_ERROR);
return;
}
$this->connection = $connection;
// Be sure to set the fetch mode so the results are keyed on
// column name instead of column index.
$this->connection->setFetchMode(MDB2_FETCHMODE_ASSOC);
if (PEAR::isError($this->connection->loadModule('Extended'))) {
trigger_error("Unable to load MDB2_Extended module", E_USER_ERROR);
return;
}
if ($associations_table) {
$this->associations_table_name = $associations_table;
}
if ($nonces_table) {
$this->nonces_table_name = $nonces_table;
}
$this->max_nonce_age = 6 * 60 * 60;
}
function tableExists($table_name)
{
return !PEAR::isError($this->connection->query(
sprintf("SELECT * FROM %s LIMIT 0",
$table_name)));
}
function createTables()
{
$n = $this->create_nonce_table();
$a = $this->create_assoc_table();
if (!$n || !$a) {
return false;
}
return true;
}
function create_nonce_table()
{
if (!$this->tableExists($this->nonces_table_name)) {
switch ($this->connection->phptype) {
case "mysql":
case "mysqli":
// Custom SQL for MySQL to use InnoDB and variable-
// length keys
$r = $this->connection->exec(
sprintf("CREATE TABLE %s (\n".
" server_url VARCHAR(2047) NOT NULL DEFAULT '',\n".
" timestamp INTEGER NOT NULL,\n".
" salt CHAR(40) NOT NULL,\n".
" UNIQUE (server_url(255), timestamp, salt)\n".
") TYPE=InnoDB",
$this->nonces_table_name));
if (PEAR::isError($r)) {
return false;
}
break;
default:
if (PEAR::isError(
$this->connection->loadModule('Manager'))) {
return false;
}
$fields = array(
"server_url" => array(
"type" => "text",
"length" => 2047,
"notnull" => true
),
"timestamp" => array(
"type" => "integer",
"notnull" => true
),
"salt" => array(
"type" => "text",
"length" => 40,
"fixed" => true,
"notnull" => true
)
);
$constraint = array(
"unique" => 1,
"fields" => array(
"server_url" => true,
"timestamp" => true,
"salt" => true
)
);
$r = $this->connection->createTable($this->nonces_table_name,
$fields);
if (PEAR::isError($r)) {
return false;
}
$r = $this->connection->createConstraint(
$this->nonces_table_name,
$this->nonces_table_name . "_constraint",
$constraint);
if (PEAR::isError($r)) {
return false;
}
break;
}
}
return true;
}
function create_assoc_table()
{
if (!$this->tableExists($this->associations_table_name)) {
switch ($this->connection->phptype) {
case "mysql":
case "mysqli":
// Custom SQL for MySQL to use InnoDB and variable-
// length keys
$r = $this->connection->exec(
sprintf("CREATE TABLE %s(\n".
" server_url VARCHAR(2047) NOT NULL DEFAULT '',\n".
" handle VARCHAR(255) NOT NULL,\n".
" secret BLOB NOT NULL,\n".
" issued INTEGER NOT NULL,\n".
" lifetime INTEGER NOT NULL,\n".
" assoc_type VARCHAR(64) NOT NULL,\n".
" PRIMARY KEY (server_url(255), handle)\n".
") TYPE=InnoDB",
$this->associations_table_name));
if (PEAR::isError($r)) {
return false;
}
break;
default:
if (PEAR::isError(
$this->connection->loadModule('Manager'))) {
return false;
}
$fields = array(
"server_url" => array(
"type" => "text",
"length" => 2047,
"notnull" => true
),
"handle" => array(
"type" => "text",
"length" => 255,
"notnull" => true
),
"secret" => array(
"type" => "blob",
"length" => "255",
"notnull" => true
),
"issued" => array(
"type" => "integer",
"notnull" => true
),
"lifetime" => array(
"type" => "integer",
"notnull" => true
),
"assoc_type" => array(
"type" => "text",
"length" => 64,
"notnull" => true
)
);
$options = array(
"primary" => array(
"server_url" => true,
"handle" => true
)
);
$r = $this->connection->createTable(
$this->associations_table_name,
$fields,
$options);
if (PEAR::isError($r)) {
return false;
}
break;
}
}
return true;
}
function storeAssociation($server_url, $association)
{
$fields = array(
"server_url" => array(
"value" => $server_url,
"key" => true
),
"handle" => array(
"value" => $association->handle,
"key" => true
),
"secret" => array(
"value" => $association->secret,
"type" => "blob"
),
"issued" => array(
"value" => $association->issued
),
"lifetime" => array(
"value" => $association->lifetime
),
"assoc_type" => array(
"value" => $association->assoc_type
)
);
return !PEAR::isError($this->connection->replace(
$this->associations_table_name,
$fields));
}
function cleanupNonces()
{
global $Auth_OpenID_SKEW;
$v = time() - $Auth_OpenID_SKEW;
return $this->connection->exec(
sprintf("DELETE FROM %s WHERE timestamp < %d",
$this->nonces_table_name, $v));
}
function cleanupAssociations()
{
return $this->connection->exec(
sprintf("DELETE FROM %s WHERE issued + lifetime < %d",
$this->associations_table_name, time()));
}
function getAssociation($server_url, $handle = null)
{
$sql = "";
$params = null;
$types = array(
"text",
"blob",
"integer",
"integer",
"text"
);
if ($handle !== null) {
$sql = sprintf("SELECT handle, secret, issued, lifetime, assoc_type " .
"FROM %s WHERE server_url = ? AND handle = ?",
$this->associations_table_name);
$params = array($server_url, $handle);
} else {
$sql = sprintf("SELECT handle, secret, issued, lifetime, assoc_type " .
"FROM %s WHERE server_url = ? ORDER BY issued DESC",
$this->associations_table_name);
$params = array($server_url);
}
$assoc = $this->connection->getRow($sql, $types, $params);
if (!$assoc || PEAR::isError($assoc)) {
return null;
} else {
$association = new Auth_OpenID_Association($assoc['handle'],
stream_get_contents(
$assoc['secret']),
$assoc['issued'],
$assoc['lifetime'],
$assoc['assoc_type']);
fclose($assoc['secret']);
return $association;
}
}
function removeAssociation($server_url, $handle)
{
$r = $this->connection->execParam(
sprintf("DELETE FROM %s WHERE server_url = ? AND handle = ?",
$this->associations_table_name),
array($server_url, $handle));
if (PEAR::isError($r) || $r == 0) {
return false;
}
return true;
}
function useNonce($server_url, $timestamp, $salt)
{
global $Auth_OpenID_SKEW;
if (abs($timestamp - time()) > $Auth_OpenID_SKEW ) {
return false;
}
$fields = array(
"timestamp" => $timestamp,
"salt" => $salt
);
if (!empty($server_url)) {
$fields["server_url"] = $server_url;
}
$r = $this->connection->autoExecute(
$this->nonces_table_name,
$fields,
MDB2_AUTOQUERY_INSERT);
if (PEAR::isError($r)) {
return false;
}
return true;
}
/**
* Resets the store by removing all records from the store's
* tables.
*/
function reset()
{
$this->connection->query(sprintf("DELETE FROM %s",
$this->associations_table_name));
$this->connection->query(sprintf("DELETE FROM %s",
$this->nonces_table_name));
}
}
?>

View File

@ -1,207 +0,0 @@
<?php
/**
* This file supplies a memcached store backend for OpenID servers and
* consumers.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package OpenID
* @author Artemy Tregubenko <me@arty.name>
* @copyright 2008 JanRain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
* Contributed by Open Web Technologies <http://openwebtech.ru/>
*/
/**
* Import the interface for creating a new store class.
*/
require_once 'Auth/OpenID/Interface.php';
/**
* This is a memcached-based store for OpenID associations and
* nonces.
*
* As memcache has limit of 250 chars for key length,
* server_url, handle and salt are hashed with sha1().
*
* Most of the methods of this class are implementation details.
* People wishing to just use this store need only pay attention to
* the constructor.
*
* @package OpenID
*/
class Auth_OpenID_MemcachedStore extends Auth_OpenID_OpenIDStore {
/**
* Initializes a new {@link Auth_OpenID_MemcachedStore} instance.
* Just saves memcached object as property.
*
* @param resource connection Memcache connection resourse
*/
function Auth_OpenID_MemcachedStore($connection, $compress = false)
{
$this->connection = $connection;
$this->compress = $compress ? MEMCACHE_COMPRESSED : 0;
}
/**
* Store association until its expiration time in memcached.
* Overwrites any existing association with same server_url and
* handle. Handles list of associations for every server.
*/
function storeAssociation($server_url, $association)
{
// create memcached keys for association itself
// and list of associations for this server
$associationKey = $this->associationKey($server_url,
$association->handle);
$serverKey = $this->associationServerKey($server_url);
// get list of associations
$serverAssociations = $this->connection->get($serverKey);
// if no such list, initialize it with empty array
if (!$serverAssociations) {
$serverAssociations = array();
}
// and store given association key in it
$serverAssociations[$association->issued] = $associationKey;
// save associations' keys list
$this->connection->set(
$serverKey,
$serverAssociations,
$this->compress
);
// save association itself
$this->connection->set(
$associationKey,
$association,
$this->compress,
$association->issued + $association->lifetime);
}
/**
* Read association from memcached. If no handle given
* and multiple associations found, returns latest issued
*/
function getAssociation($server_url, $handle = null)
{
// simple case: handle given
if ($handle !== null) {
// get association, return null if failed
$association = $this->connection->get(
$this->associationKey($server_url, $handle));
return $association ? $association : null;
}
// no handle given, working with list
// create key for list of associations
$serverKey = $this->associationServerKey($server_url);
// get list of associations
$serverAssociations = $this->connection->get($serverKey);
// return null if failed or got empty list
if (!$serverAssociations) {
return null;
}
// get key of most recently issued association
$keys = array_keys($serverAssociations);
sort($keys);
$lastKey = $serverAssociations[array_pop($keys)];
// get association, return null if failed
$association = $this->connection->get($lastKey);
return $association ? $association : null;
}
/**
* Immediately delete association from memcache.
*/
function removeAssociation($server_url, $handle)
{
// create memcached keys for association itself
// and list of associations for this server
$serverKey = $this->associationServerKey($server_url);
$associationKey = $this->associationKey($server_url,
$handle);
// get list of associations
$serverAssociations = $this->connection->get($serverKey);
// return null if failed or got empty list
if (!$serverAssociations) {
return false;
}
// ensure that given association key exists in list
$serverAssociations = array_flip($serverAssociations);
if (!array_key_exists($associationKey, $serverAssociations)) {
return false;
}
// remove given association key from list
unset($serverAssociations[$associationKey]);
$serverAssociations = array_flip($serverAssociations);
// save updated list
$this->connection->set(
$serverKey,
$serverAssociations,
$this->compress
);
// delete association
return $this->connection->delete($associationKey);
}
/**
* Create nonce for server and salt, expiring after
* $Auth_OpenID_SKEW seconds.
*/
function useNonce($server_url, $timestamp, $salt)
{
global $Auth_OpenID_SKEW;
// save one request to memcache when nonce obviously expired
if (abs($timestamp - time()) > $Auth_OpenID_SKEW) {
return false;
}
// returns false when nonce already exists
// otherwise adds nonce
return $this->connection->add(
'openid_nonce_' . sha1($server_url) . '_' . sha1($salt),
1, // any value here
$this->compress,
$Auth_OpenID_SKEW);
}
/**
* Memcache key is prefixed with 'openid_association_' string.
*/
function associationKey($server_url, $handle = null)
{
return 'openid_association_' . sha1($server_url) . '_' . sha1($handle);
}
/**
* Memcache key is prefixed with 'openid_association_' string.
*/
function associationServerKey($server_url)
{
return 'openid_association_server_' . sha1($server_url);
}
/**
* Report that this storage doesn't support cleanup
*/
function supportsCleanup()
{
return false;
}
}

View File

@ -1,920 +0,0 @@
<?php
/**
* Extension argument processing code
*
* @package OpenID
*/
/**
* Import tools needed to deal with messages.
*/
require_once 'Auth/OpenID.php';
require_once 'Auth/OpenID/KVForm.php';
require_once 'Auth/Yadis/XML.php';
require_once 'Auth/OpenID/Consumer.php'; // For Auth_OpenID_FailureResponse
// This doesn't REALLY belong here, but where is better?
define('Auth_OpenID_IDENTIFIER_SELECT',
"http://specs.openid.net/auth/2.0/identifier_select");
// URI for Simple Registration extension, the only commonly deployed
// OpenID 1.x extension, and so a special case
define('Auth_OpenID_SREG_URI', 'http://openid.net/sreg/1.0');
// The OpenID 1.X namespace URI
define('Auth_OpenID_OPENID1_NS', 'http://openid.net/signon/1.0');
define('Auth_OpenID_THE_OTHER_OPENID1_NS', 'http://openid.net/signon/1.1');
function Auth_OpenID_isOpenID1($ns)
{
return ($ns == Auth_OpenID_THE_OTHER_OPENID1_NS) ||
($ns == Auth_OpenID_OPENID1_NS);
}
// The OpenID 2.0 namespace URI
define('Auth_OpenID_OPENID2_NS', 'http://specs.openid.net/auth/2.0');
// The namespace consisting of pairs with keys that are prefixed with
// "openid." but not in another namespace.
define('Auth_OpenID_NULL_NAMESPACE', 'Null namespace');
// The null namespace, when it is an allowed OpenID namespace
define('Auth_OpenID_OPENID_NS', 'OpenID namespace');
// The top-level namespace, excluding all pairs with keys that start
// with "openid."
define('Auth_OpenID_BARE_NS', 'Bare namespace');
// Sentinel for Message implementation to indicate that getArg should
// return null instead of returning a default.
define('Auth_OpenID_NO_DEFAULT', 'NO DEFAULT ALLOWED');
// Limit, in bytes, of identity provider and return_to URLs, including
// response payload. See OpenID 1.1 specification, Appendix D.
define('Auth_OpenID_OPENID1_URL_LIMIT', 2047);
// All OpenID protocol fields. Used to check namespace aliases.
global $Auth_OpenID_OPENID_PROTOCOL_FIELDS;
$Auth_OpenID_OPENID_PROTOCOL_FIELDS = array(
'ns', 'mode', 'error', 'return_to', 'contact', 'reference',
'signed', 'assoc_type', 'session_type', 'dh_modulus', 'dh_gen',
'dh_consumer_public', 'claimed_id', 'identity', 'realm',
'invalidate_handle', 'op_endpoint', 'response_nonce', 'sig',
'assoc_handle', 'trust_root', 'openid');
// Global namespace / alias registration map. See
// Auth_OpenID_registerNamespaceAlias.
global $Auth_OpenID_registered_aliases;
$Auth_OpenID_registered_aliases = array();
/**
* Registers a (namespace URI, alias) mapping in a global namespace
* alias map. Raises NamespaceAliasRegistrationError if either the
* namespace URI or alias has already been registered with a different
* value. This function is required if you want to use a namespace
* with an OpenID 1 message.
*/
function Auth_OpenID_registerNamespaceAlias($namespace_uri, $alias)
{
global $Auth_OpenID_registered_aliases;
if (Auth_OpenID::arrayGet($Auth_OpenID_registered_aliases,
$alias) == $namespace_uri) {
return true;
}
if (in_array($namespace_uri,
array_values($Auth_OpenID_registered_aliases))) {
return false;
}
if (in_array($alias, array_keys($Auth_OpenID_registered_aliases))) {
return false;
}
$Auth_OpenID_registered_aliases[$alias] = $namespace_uri;
return true;
}
/**
* Removes a (namespace_uri, alias) registration from the global
* namespace alias map. Returns true if the removal succeeded; false
* if not (if the mapping did not exist).
*/
function Auth_OpenID_removeNamespaceAlias($namespace_uri, $alias)
{
global $Auth_OpenID_registered_aliases;
if (Auth_OpenID::arrayGet($Auth_OpenID_registered_aliases,
$alias) === $namespace_uri) {
unset($Auth_OpenID_registered_aliases[$alias]);
return true;
}
return false;
}
/**
* An Auth_OpenID_Mapping maintains a mapping from arbitrary keys to
* arbitrary values. (This is unlike an ordinary PHP array, whose
* keys may be only simple scalars.)
*
* @package OpenID
*/
class Auth_OpenID_Mapping {
/**
* Initialize a mapping. If $classic_array is specified, its keys
* and values are used to populate the mapping.
*/
function Auth_OpenID_Mapping($classic_array = null)
{
$this->keys = array();
$this->values = array();
if (is_array($classic_array)) {
foreach ($classic_array as $key => $value) {
$this->set($key, $value);
}
}
}
/**
* Returns true if $thing is an Auth_OpenID_Mapping object; false
* if not.
*/
static function isA($thing)
{
return (is_object($thing) &&
strtolower(get_class($thing)) == 'auth_openid_mapping');
}
/**
* Returns an array of the keys in the mapping.
*/
function keys()
{
return $this->keys;
}
/**
* Returns an array of values in the mapping.
*/
function values()
{
return $this->values;
}
/**
* Returns an array of (key, value) pairs in the mapping.
*/
function items()
{
$temp = array();
for ($i = 0; $i < count($this->keys); $i++) {
$temp[] = array($this->keys[$i],
$this->values[$i]);
}
return $temp;
}
/**
* Returns the "length" of the mapping, or the number of keys.
*/
function len()
{
return count($this->keys);
}
/**
* Sets a key-value pair in the mapping. If the key already
* exists, its value is replaced with the new value.
*/
function set($key, $value)
{
$index = array_search($key, $this->keys);
if ($index !== false) {
$this->values[$index] = $value;
} else {
$this->keys[] = $key;
$this->values[] = $value;
}
}
/**
* Gets a specified value from the mapping, associated with the
* specified key. If the key does not exist in the mapping,
* $default is returned instead.
*/
function get($key, $default = null)
{
$index = array_search($key, $this->keys);
if ($index !== false) {
return $this->values[$index];
} else {
return $default;
}
}
/**
* @access private
*/
function _reflow()
{
// PHP is broken yet again. Sort the arrays to remove the
// hole in the numeric indexes that make up the array.
$old_keys = $this->keys;
$old_values = $this->values;
$this->keys = array();
$this->values = array();
foreach ($old_keys as $k) {
$this->keys[] = $k;
}
foreach ($old_values as $v) {
$this->values[] = $v;
}
}
/**
* Deletes a key-value pair from the mapping with the specified
* key.
*/
function del($key)
{
$index = array_search($key, $this->keys);
if ($index !== false) {
unset($this->keys[$index]);
unset($this->values[$index]);
$this->_reflow();
return true;
}
return false;
}
/**
* Returns true if the specified value has a key in the mapping;
* false if not.
*/
function contains($value)
{
return (array_search($value, $this->keys) !== false);
}
}
/**
* Maintains a bijective map between namespace uris and aliases.
*
* @package OpenID
*/
class Auth_OpenID_NamespaceMap {
function Auth_OpenID_NamespaceMap()
{
$this->alias_to_namespace = new Auth_OpenID_Mapping();
$this->namespace_to_alias = new Auth_OpenID_Mapping();
$this->implicit_namespaces = array();
}
function getAlias($namespace_uri)
{
return $this->namespace_to_alias->get($namespace_uri);
}
function getNamespaceURI($alias)
{
return $this->alias_to_namespace->get($alias);
}
function iterNamespaceURIs()
{
// Return an iterator over the namespace URIs
return $this->namespace_to_alias->keys();
}
function iterAliases()
{
// Return an iterator over the aliases"""
return $this->alias_to_namespace->keys();
}
function iteritems()
{
return $this->namespace_to_alias->items();
}
function isImplicit($namespace_uri)
{
return in_array($namespace_uri, $this->implicit_namespaces);
}
function addAlias($namespace_uri, $desired_alias, $implicit=false)
{
// Add an alias from this namespace URI to the desired alias
global $Auth_OpenID_OPENID_PROTOCOL_FIELDS;
// Check that desired_alias is not an openid protocol field as
// per the spec.
if (in_array($desired_alias, $Auth_OpenID_OPENID_PROTOCOL_FIELDS)) {
Auth_OpenID::log("\"%s\" is not an allowed namespace alias",
$desired_alias);
return null;
}
// Check that desired_alias does not contain a period as per
// the spec.
if (strpos($desired_alias, '.') !== false) {
Auth_OpenID::log('"%s" must not contain a dot', $desired_alias);
return null;
}
// Check that there is not a namespace already defined for the
// desired alias
$current_namespace_uri =
$this->alias_to_namespace->get($desired_alias);
if (($current_namespace_uri !== null) &&
($current_namespace_uri != $namespace_uri)) {
Auth_OpenID::log('Cannot map "%s" because previous mapping exists',
$namespace_uri);
return null;
}
// Check that there is not already a (different) alias for
// this namespace URI
$alias = $this->namespace_to_alias->get($namespace_uri);
if (($alias !== null) && ($alias != $desired_alias)) {
Auth_OpenID::log('Cannot map %s to alias %s. ' .
'It is already mapped to alias %s',
$namespace_uri, $desired_alias, $alias);
return null;
}
assert((Auth_OpenID_NULL_NAMESPACE === $desired_alias) ||
is_string($desired_alias));
$this->alias_to_namespace->set($desired_alias, $namespace_uri);
$this->namespace_to_alias->set($namespace_uri, $desired_alias);
if ($implicit) {
array_push($this->implicit_namespaces, $namespace_uri);
}
return $desired_alias;
}
function add($namespace_uri)
{
// Add this namespace URI to the mapping, without caring what
// alias it ends up with
// See if this namespace is already mapped to an alias
$alias = $this->namespace_to_alias->get($namespace_uri);
if ($alias !== null) {
return $alias;
}
// Fall back to generating a numerical alias
$i = 0;
while (1) {
$alias = 'ext' . strval($i);
if ($this->addAlias($namespace_uri, $alias) === null) {
$i += 1;
} else {
return $alias;
}
}
// Should NEVER be reached!
return null;
}
function contains($namespace_uri)
{
return $this->isDefined($namespace_uri);
}
function isDefined($namespace_uri)
{
return $this->namespace_to_alias->contains($namespace_uri);
}
}
/**
* In the implementation of this object, null represents the global
* namespace as well as a namespace with no key.
*
* @package OpenID
*/
class Auth_OpenID_Message {
function Auth_OpenID_Message($openid_namespace = null)
{
// Create an empty Message
$this->allowed_openid_namespaces = array(
Auth_OpenID_OPENID1_NS,
Auth_OpenID_THE_OTHER_OPENID1_NS,
Auth_OpenID_OPENID2_NS);
$this->args = new Auth_OpenID_Mapping();
$this->namespaces = new Auth_OpenID_NamespaceMap();
if ($openid_namespace === null) {
$this->_openid_ns_uri = null;
} else {
$implicit = Auth_OpenID_isOpenID1($openid_namespace);
$this->setOpenIDNamespace($openid_namespace, $implicit);
}
}
function isOpenID1()
{
return Auth_OpenID_isOpenID1($this->getOpenIDNamespace());
}
function isOpenID2()
{
return $this->getOpenIDNamespace() == Auth_OpenID_OPENID2_NS;
}
static function fromPostArgs($args)
{
// Construct a Message containing a set of POST arguments
$obj = new Auth_OpenID_Message();
// Partition into "openid." args and bare args
$openid_args = array();
foreach ($args as $key => $value) {
if (is_array($value)) {
return null;
}
$parts = explode('.', $key, 2);
if (count($parts) == 2) {
list($prefix, $rest) = $parts;
} else {
$prefix = null;
}
if ($prefix != 'openid') {
$obj->args->set(array(Auth_OpenID_BARE_NS, $key), $value);
} else {
$openid_args[$rest] = $value;
}
}
if ($obj->_fromOpenIDArgs($openid_args)) {
return $obj;
} else {
return null;
}
}
static function fromOpenIDArgs($openid_args)
{
// Takes an array.
// Construct a Message from a parsed KVForm message
$obj = new Auth_OpenID_Message();
if ($obj->_fromOpenIDArgs($openid_args)) {
return $obj;
} else {
return null;
}
}
/**
* @access private
*/
function _fromOpenIDArgs($openid_args)
{
global $Auth_OpenID_registered_aliases;
// Takes an Auth_OpenID_Mapping instance OR an array.
if (!Auth_OpenID_Mapping::isA($openid_args)) {
$openid_args = new Auth_OpenID_Mapping($openid_args);
}
$ns_args = array();
// Resolve namespaces
foreach ($openid_args->items() as $pair) {
list($rest, $value) = $pair;
$parts = explode('.', $rest, 2);
if (count($parts) == 2) {
list($ns_alias, $ns_key) = $parts;
} else {
$ns_alias = Auth_OpenID_NULL_NAMESPACE;
$ns_key = $rest;
}
if ($ns_alias == 'ns') {
if ($this->namespaces->addAlias($value, $ns_key) === null) {
return false;
}
} else if (($ns_alias == Auth_OpenID_NULL_NAMESPACE) &&
($ns_key == 'ns')) {
// null namespace
if ($this->setOpenIDNamespace($value, false) === false) {
return false;
}
} else {
$ns_args[] = array($ns_alias, $ns_key, $value);
}
}
if (!$this->getOpenIDNamespace()) {
if ($this->setOpenIDNamespace(Auth_OpenID_OPENID1_NS, true) ===
false) {
return false;
}
}
// Actually put the pairs into the appropriate namespaces
foreach ($ns_args as $triple) {
list($ns_alias, $ns_key, $value) = $triple;
$ns_uri = $this->namespaces->getNamespaceURI($ns_alias);
if ($ns_uri === null) {
$ns_uri = $this->_getDefaultNamespace($ns_alias);
if ($ns_uri === null) {
$ns_uri = Auth_OpenID_OPENID_NS;
$ns_key = sprintf('%s.%s', $ns_alias, $ns_key);
} else {
$this->namespaces->addAlias($ns_uri, $ns_alias, true);
}
}
$this->setArg($ns_uri, $ns_key, $value);
}
return true;
}
function _getDefaultNamespace($mystery_alias)
{
global $Auth_OpenID_registered_aliases;
if ($this->isOpenID1()) {
return @$Auth_OpenID_registered_aliases[$mystery_alias];
}
return null;
}
function setOpenIDNamespace($openid_ns_uri, $implicit)
{
if (!in_array($openid_ns_uri, $this->allowed_openid_namespaces)) {
Auth_OpenID::log('Invalid null namespace: "%s"', $openid_ns_uri);
return false;
}
$succeeded = $this->namespaces->addAlias($openid_ns_uri,
Auth_OpenID_NULL_NAMESPACE,
$implicit);
if ($succeeded === false) {
return false;
}
$this->_openid_ns_uri = $openid_ns_uri;
return true;
}
function getOpenIDNamespace()
{
return $this->_openid_ns_uri;
}
static function fromKVForm($kvform_string)
{
// Create a Message from a KVForm string
return Auth_OpenID_Message::fromOpenIDArgs(
Auth_OpenID_KVForm::toArray($kvform_string));
}
function copy()
{
return $this;
}
function toPostArgs()
{
// Return all arguments with openid. in front of namespaced
// arguments.
$args = array();
// Add namespace definitions to the output
foreach ($this->namespaces->iteritems() as $pair) {
list($ns_uri, $alias) = $pair;
if ($this->namespaces->isImplicit($ns_uri)) {
continue;
}
if ($alias == Auth_OpenID_NULL_NAMESPACE) {
$ns_key = 'openid.ns';
} else {
$ns_key = 'openid.ns.' . $alias;
}
$args[$ns_key] = $ns_uri;
}
foreach ($this->args->items() as $pair) {
list($ns_parts, $value) = $pair;
list($ns_uri, $ns_key) = $ns_parts;
$key = $this->getKey($ns_uri, $ns_key);
$args[$key] = $value;
}
return $args;
}
function toArgs()
{
// Return all namespaced arguments, failing if any
// non-namespaced arguments exist.
$post_args = $this->toPostArgs();
$kvargs = array();
foreach ($post_args as $k => $v) {
if (strpos($k, 'openid.') !== 0) {
// raise ValueError(
// 'This message can only be encoded as a POST, because it '
// 'contains arguments that are not prefixed with "openid."')
return null;
} else {
$kvargs[substr($k, 7)] = $v;
}
}
return $kvargs;
}
function toFormMarkup($action_url, $form_tag_attrs = null,
$submit_text = "Continue")
{
$form = "<form accept-charset=\"UTF-8\" ".
"enctype=\"application/x-www-form-urlencoded\"";
if (!$form_tag_attrs) {
$form_tag_attrs = array();
}
$form_tag_attrs['action'] = $action_url;
$form_tag_attrs['method'] = 'post';
unset($form_tag_attrs['enctype']);
unset($form_tag_attrs['accept-charset']);
if ($form_tag_attrs) {
foreach ($form_tag_attrs as $name => $attr) {
$form .= sprintf(" %s=\"%s\"", $name, $attr);
}
}
$form .= ">\n";
foreach ($this->toPostArgs() as $name => $value) {
$form .= sprintf(
"<input type=\"hidden\" name=\"%s\" value=\"%s\" />\n",
$name, $value);
}
$form .= sprintf("<input type=\"submit\" value=\"%s\" />\n",
$submit_text);
$form .= "</form>\n";
return $form;
}
function toURL($base_url)
{
// Generate a GET URL with the parameters in this message
// attached as query parameters.
return Auth_OpenID::appendArgs($base_url, $this->toPostArgs());
}
function toKVForm()
{
// Generate a KVForm string that contains the parameters in
// this message. This will fail if the message contains
// arguments outside of the 'openid.' prefix.
return Auth_OpenID_KVForm::fromArray($this->toArgs());
}
function toURLEncoded()
{
// Generate an x-www-urlencoded string
$args = array();
foreach ($this->toPostArgs() as $k => $v) {
$args[] = array($k, $v);
}
sort($args);
return Auth_OpenID::httpBuildQuery($args);
}
/**
* @access private
*/
function _fixNS($namespace)
{
// Convert an input value into the internally used values of
// this object
if ($namespace == Auth_OpenID_OPENID_NS) {
if ($this->_openid_ns_uri === null) {
return new Auth_OpenID_FailureResponse(null,
'OpenID namespace not set');
} else {
$namespace = $this->_openid_ns_uri;
}
}
if (($namespace != Auth_OpenID_BARE_NS) &&
(!is_string($namespace))) {
//TypeError
$err_msg = sprintf("Namespace must be Auth_OpenID_BARE_NS, ".
"Auth_OpenID_OPENID_NS or a string. got %s",
print_r($namespace, true));
return new Auth_OpenID_FailureResponse(null, $err_msg);
}
if (($namespace != Auth_OpenID_BARE_NS) &&
(strpos($namespace, ':') === false)) {
// fmt = 'OpenID 2.0 namespace identifiers SHOULD be URIs. Got %r'
// warnings.warn(fmt % (namespace,), DeprecationWarning)
if ($namespace == 'sreg') {
// fmt = 'Using %r instead of "sreg" as namespace'
// warnings.warn(fmt % (SREG_URI,), DeprecationWarning,)
return Auth_OpenID_SREG_URI;
}
}
return $namespace;
}
function hasKey($namespace, $ns_key)
{
$namespace = $this->_fixNS($namespace);
if (Auth_OpenID::isFailure($namespace)) {
// XXX log me
return false;
} else {
return $this->args->contains(array($namespace, $ns_key));
}
}
function getKey($namespace, $ns_key)
{
// Get the key for a particular namespaced argument
$namespace = $this->_fixNS($namespace);
if (Auth_OpenID::isFailure($namespace)) {
return $namespace;
}
if ($namespace == Auth_OpenID_BARE_NS) {
return $ns_key;
}
$ns_alias = $this->namespaces->getAlias($namespace);
// No alias is defined, so no key can exist
if ($ns_alias === null) {
return null;
}
if ($ns_alias == Auth_OpenID_NULL_NAMESPACE) {
$tail = $ns_key;
} else {
$tail = sprintf('%s.%s', $ns_alias, $ns_key);
}
return 'openid.' . $tail;
}
function getArg($namespace, $key, $default = null)
{
// Get a value for a namespaced key.
$namespace = $this->_fixNS($namespace);
if (Auth_OpenID::isFailure($namespace)) {
return $namespace;
} else {
if ((!$this->args->contains(array($namespace, $key))) &&
($default == Auth_OpenID_NO_DEFAULT)) {
$err_msg = sprintf("Namespace %s missing required field %s",
$namespace, $key);
return new Auth_OpenID_FailureResponse(null, $err_msg);
} else {
return $this->args->get(array($namespace, $key), $default);
}
}
}
function getArgs($namespace)
{
// Get the arguments that are defined for this namespace URI
$namespace = $this->_fixNS($namespace);
if (Auth_OpenID::isFailure($namespace)) {
return $namespace;
} else {
$stuff = array();
foreach ($this->args->items() as $pair) {
list($key, $value) = $pair;
list($pair_ns, $ns_key) = $key;
if ($pair_ns == $namespace) {
$stuff[$ns_key] = $value;
}
}
return $stuff;
}
}
function updateArgs($namespace, $updates)
{
// Set multiple key/value pairs in one call
$namespace = $this->_fixNS($namespace);
if (Auth_OpenID::isFailure($namespace)) {
return $namespace;
} else {
foreach ($updates as $k => $v) {
$this->setArg($namespace, $k, $v);
}
return true;
}
}
function setArg($namespace, $key, $value)
{
// Set a single argument in this namespace
$namespace = $this->_fixNS($namespace);
if (Auth_OpenID::isFailure($namespace)) {
return $namespace;
} else {
$this->args->set(array($namespace, $key), $value);
if ($namespace !== Auth_OpenID_BARE_NS) {
$this->namespaces->add($namespace);
}
return true;
}
}
function delArg($namespace, $key)
{
$namespace = $this->_fixNS($namespace);
if (Auth_OpenID::isFailure($namespace)) {
return $namespace;
} else {
return $this->args->del(array($namespace, $key));
}
}
function getAliasedArg($aliased_key, $default = null)
{
if ($aliased_key == 'ns') {
// Return the namespace URI for the OpenID namespace
return $this->getOpenIDNamespace();
}
$parts = explode('.', $aliased_key, 2);
if (count($parts) != 2) {
$ns = null;
} else {
list($alias, $key) = $parts;
if ($alias == 'ns') {
// Return the namespace URI for a namespace alias
// parameter.
return $this->namespaces->getNamespaceURI($key);
} else {
$ns = $this->namespaces->getNamespaceURI($alias);
}
}
if ($ns === null) {
$key = $aliased_key;
$ns = $this->getOpenIDNamespace();
}
return $this->getArg($ns, $key, $default);
}
}

View File

@ -1,77 +0,0 @@
<?php
/**
* A MySQL store.
*
* @package OpenID
*/
/**
* Require the base class file.
*/
require_once "Auth/OpenID/SQLStore.php";
/**
* An SQL store that uses MySQL as its backend.
*
* @package OpenID
*/
class Auth_OpenID_MySQLStore extends Auth_OpenID_SQLStore {
/**
* @access private
*/
function setSQL()
{
$this->sql['nonce_table'] =
"CREATE TABLE %s (\n".
" server_url VARCHAR(2047) NOT NULL,\n".
" timestamp INTEGER NOT NULL,\n".
" salt CHAR(40) NOT NULL,\n".
" UNIQUE (server_url(255), timestamp, salt)\n".
") ENGINE=InnoDB";
$this->sql['assoc_table'] =
"CREATE TABLE %s (\n".
" server_url VARCHAR(2047) NOT NULL,\n".
" handle VARCHAR(255) NOT NULL,\n".
" secret BLOB NOT NULL,\n".
" issued INTEGER NOT NULL,\n".
" lifetime INTEGER NOT NULL,\n".
" assoc_type VARCHAR(64) NOT NULL,\n".
" PRIMARY KEY (server_url(255), handle)\n".
") ENGINE=InnoDB";
$this->sql['set_assoc'] =
"REPLACE INTO %s (server_url, handle, secret, issued,\n".
" lifetime, assoc_type) VALUES (?, ?, !, ?, ?, ?)";
$this->sql['get_assocs'] =
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ".
"WHERE server_url = ?";
$this->sql['get_assoc'] =
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ".
"WHERE server_url = ? AND handle = ?";
$this->sql['remove_assoc'] =
"DELETE FROM %s WHERE server_url = ? AND handle = ?";
$this->sql['add_nonce'] =
"INSERT INTO %s (server_url, timestamp, salt) VALUES (?, ?, ?)";
$this->sql['clean_nonce'] =
"DELETE FROM %s WHERE timestamp < ?";
$this->sql['clean_assoc'] =
"DELETE FROM %s WHERE issued + lifetime < ?";
}
/**
* @access private
*/
function blobEncode($blob)
{
return "0x" . bin2hex($blob);
}
}

View File

@ -1,108 +0,0 @@
<?php
/**
* Nonce-related functionality.
*
* @package OpenID
*/
/**
* Need CryptUtil to generate random strings.
*/
require_once 'Auth/OpenID/CryptUtil.php';
/**
* This is the characters that the nonces are made from.
*/
define('Auth_OpenID_Nonce_CHRS',"abcdefghijklmnopqrstuvwxyz" .
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
// Keep nonces for five hours (allow five hours for the combination of
// request time and clock skew). This is probably way more than is
// necessary, but there is not much overhead in storing nonces.
global $Auth_OpenID_SKEW;
$Auth_OpenID_SKEW = 60 * 60 * 5;
define('Auth_OpenID_Nonce_REGEX',
'/(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)Z(.*)/');
define('Auth_OpenID_Nonce_TIME_FMT',
'%Y-%m-%dT%H:%M:%SZ');
function Auth_OpenID_splitNonce($nonce_string)
{
// Extract a timestamp from the given nonce string
$result = preg_match(Auth_OpenID_Nonce_REGEX, $nonce_string, $matches);
if ($result != 1 || count($matches) != 8) {
return null;
}
list($unused,
$tm_year,
$tm_mon,
$tm_mday,
$tm_hour,
$tm_min,
$tm_sec,
$uniquifier) = $matches;
$timestamp =
@gmmktime($tm_hour, $tm_min, $tm_sec, $tm_mon, $tm_mday, $tm_year);
if ($timestamp === false || $timestamp < 0) {
return null;
}
return array($timestamp, $uniquifier);
}
function Auth_OpenID_checkTimestamp($nonce_string,
$allowed_skew = null,
$now = null)
{
// Is the timestamp that is part of the specified nonce string
// within the allowed clock-skew of the current time?
global $Auth_OpenID_SKEW;
if ($allowed_skew === null) {
$allowed_skew = $Auth_OpenID_SKEW;
}
$parts = Auth_OpenID_splitNonce($nonce_string);
if ($parts == null) {
return false;
}
if ($now === null) {
$now = time();
}
$stamp = $parts[0];
// Time after which we should not use the nonce
$past = $now - $allowed_skew;
// Time that is too far in the future for us to allow
$future = $now + $allowed_skew;
// the stamp is not too far in the future and is not too far
// in the past
return (($past <= $stamp) && ($stamp <= $future));
}
function Auth_OpenID_mkNonce($when = null)
{
// Generate a nonce with the current timestamp
$salt = Auth_OpenID_CryptUtil::randomString(
6, Auth_OpenID_Nonce_CHRS);
if ($when === null) {
// It's safe to call time() with no arguments; it returns a
// GMT unix timestamp on PHP 4 and PHP 5. gmmktime() with no
// args returns a local unix timestamp on PHP 4, so don't use
// that.
$when = time();
}
$time_str = gmstrftime(Auth_OpenID_Nonce_TIME_FMT, $when);
return $time_str . $salt;
}

View File

@ -1,300 +0,0 @@
<?php
/**
* An implementation of the OpenID Provider Authentication Policy
* Extension 1.0
*
* See:
* http://openid.net/developers/specs/
*/
require_once "Auth/OpenID/Extension.php";
define('Auth_OpenID_PAPE_NS_URI',
"http://specs.openid.net/extensions/pape/1.0");
define('PAPE_AUTH_MULTI_FACTOR_PHYSICAL',
'http://schemas.openid.net/pape/policies/2007/06/multi-factor-physical');
define('PAPE_AUTH_MULTI_FACTOR',
'http://schemas.openid.net/pape/policies/2007/06/multi-factor');
define('PAPE_AUTH_PHISHING_RESISTANT',
'http://schemas.openid.net/pape/policies/2007/06/phishing-resistant');
define('PAPE_TIME_VALIDATOR',
'/^[0-9]{4,4}-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9]Z$/');
/**
* A Provider Authentication Policy request, sent from a relying party
* to a provider
*
* preferred_auth_policies: The authentication policies that
* the relying party prefers
*
* max_auth_age: The maximum time, in seconds, that the relying party
* wants to allow to have elapsed before the user must re-authenticate
*/
class Auth_OpenID_PAPE_Request extends Auth_OpenID_Extension {
var $ns_alias = 'pape';
var $ns_uri = Auth_OpenID_PAPE_NS_URI;
function Auth_OpenID_PAPE_Request($preferred_auth_policies=null,
$max_auth_age=null)
{
if ($preferred_auth_policies === null) {
$preferred_auth_policies = array();
}
$this->preferred_auth_policies = $preferred_auth_policies;
$this->max_auth_age = $max_auth_age;
}
/**
* Add an acceptable authentication policy URI to this request
*
* This method is intended to be used by the relying party to add
* acceptable authentication types to the request.
*
* policy_uri: The identifier for the preferred type of
* authentication.
*/
function addPolicyURI($policy_uri)
{
if (!in_array($policy_uri, $this->preferred_auth_policies)) {
$this->preferred_auth_policies[] = $policy_uri;
}
}
function getExtensionArgs()
{
$ns_args = array(
'preferred_auth_policies' =>
implode(' ', $this->preferred_auth_policies)
);
if ($this->max_auth_age !== null) {
$ns_args['max_auth_age'] = strval($this->max_auth_age);
}
return $ns_args;
}
/**
* Instantiate a Request object from the arguments in a checkid_*
* OpenID message
*/
static function fromOpenIDRequest($request)
{
$obj = new Auth_OpenID_PAPE_Request();
$args = $request->message->getArgs(Auth_OpenID_PAPE_NS_URI);
if ($args === null || $args === array()) {
return null;
}
$obj->parseExtensionArgs($args);
return $obj;
}
/**
* Set the state of this request to be that expressed in these
* PAPE arguments
*
* @param args: The PAPE arguments without a namespace
*/
function parseExtensionArgs($args)
{
// preferred_auth_policies is a space-separated list of policy
// URIs
$this->preferred_auth_policies = array();
$policies_str = Auth_OpenID::arrayGet($args, 'preferred_auth_policies');
if ($policies_str) {
foreach (explode(' ', $policies_str) as $uri) {
if (!in_array($uri, $this->preferred_auth_policies)) {
$this->preferred_auth_policies[] = $uri;
}
}
}
// max_auth_age is base-10 integer number of seconds
$max_auth_age_str = Auth_OpenID::arrayGet($args, 'max_auth_age');
if ($max_auth_age_str) {
$this->max_auth_age = Auth_OpenID::intval($max_auth_age_str);
} else {
$this->max_auth_age = null;
}
}
/**
* Given a list of authentication policy URIs that a provider
* supports, this method returns the subsequence of those types
* that are preferred by the relying party.
*
* @param supported_types: A sequence of authentication policy
* type URIs that are supported by a provider
*
* @return array The sub-sequence of the supported types that are
* preferred by the relying party. This list will be ordered in
* the order that the types appear in the supported_types
* sequence, and may be empty if the provider does not prefer any
* of the supported authentication types.
*/
function preferredTypes($supported_types)
{
$result = array();
foreach ($supported_types as $st) {
if (in_array($st, $this->preferred_auth_policies)) {
$result[] = $st;
}
}
return $result;
}
}
/**
* A Provider Authentication Policy response, sent from a provider to
* a relying party
*/
class Auth_OpenID_PAPE_Response extends Auth_OpenID_Extension {
var $ns_alias = 'pape';
var $ns_uri = Auth_OpenID_PAPE_NS_URI;
function Auth_OpenID_PAPE_Response($auth_policies=null, $auth_time=null,
$nist_auth_level=null)
{
if ($auth_policies) {
$this->auth_policies = $auth_policies;
} else {
$this->auth_policies = array();
}
$this->auth_time = $auth_time;
$this->nist_auth_level = $nist_auth_level;
}
/**
* Add a authentication policy to this response
*
* This method is intended to be used by the provider to add a
* policy that the provider conformed to when authenticating the
* user.
*
* @param policy_uri: The identifier for the preferred type of
* authentication.
*/
function addPolicyURI($policy_uri)
{
if (!in_array($policy_uri, $this->auth_policies)) {
$this->auth_policies[] = $policy_uri;
}
}
/**
* Create an Auth_OpenID_PAPE_Response object from a successful
* OpenID library response.
*
* @param success_response $success_response A SuccessResponse
* from Auth_OpenID_Consumer::complete()
*
* @returns: A provider authentication policy response from the
* data that was supplied with the id_res response.
*/
static function fromSuccessResponse($success_response)
{
$obj = new Auth_OpenID_PAPE_Response();
// PAPE requires that the args be signed.
$args = $success_response->getSignedNS(Auth_OpenID_PAPE_NS_URI);
if ($args === null || $args === array()) {
return null;
}
$result = $obj->parseExtensionArgs($args);
if ($result === false) {
return null;
} else {
return $obj;
}
}
/**
* Parse the provider authentication policy arguments into the
* internal state of this object
*
* @param args: unqualified provider authentication policy
* arguments
*
* @param strict: Whether to return false when bad data is
* encountered
*
* @return null The data is parsed into the internal fields of
* this object.
*/
function parseExtensionArgs($args, $strict=false)
{
$policies_str = Auth_OpenID::arrayGet($args, 'auth_policies');
if ($policies_str && $policies_str != "none") {
$this->auth_policies = explode(" ", $policies_str);
}
$nist_level_str = Auth_OpenID::arrayGet($args, 'nist_auth_level');
if ($nist_level_str !== null) {
$nist_level = Auth_OpenID::intval($nist_level_str);
if ($nist_level === false) {
if ($strict) {
return false;
} else {
$nist_level = null;
}
}
if (0 <= $nist_level && $nist_level < 5) {
$this->nist_auth_level = $nist_level;
} else if ($strict) {
return false;
}
}
$auth_time = Auth_OpenID::arrayGet($args, 'auth_time');
if ($auth_time !== null) {
if (preg_match(PAPE_TIME_VALIDATOR, $auth_time)) {
$this->auth_time = $auth_time;
} else if ($strict) {
return false;
}
}
}
function getExtensionArgs()
{
$ns_args = array();
if (count($this->auth_policies) > 0) {
$ns_args['auth_policies'] = implode(' ', $this->auth_policies);
} else {
$ns_args['auth_policies'] = 'none';
}
if ($this->nist_auth_level !== null) {
if (!in_array($this->nist_auth_level, range(0, 4), true)) {
return false;
}
$ns_args['nist_auth_level'] = strval($this->nist_auth_level);
}
if ($this->auth_time !== null) {
if (!preg_match(PAPE_TIME_VALIDATOR, $this->auth_time)) {
return false;
}
$ns_args['auth_time'] = $this->auth_time;
}
return $ns_args;
}
}

View File

@ -1,381 +0,0 @@
<?php
/**
* This module implements a VERY limited parser that finds <link> tags
* in the head of HTML or XHTML documents and parses out their
* attributes according to the OpenID spec. It is a liberal parser,
* but it requires these things from the data in order to work:
*
* - There must be an open <html> tag
*
* - There must be an open <head> tag inside of the <html> tag
*
* - Only <link>s that are found inside of the <head> tag are parsed
* (this is by design)
*
* - The parser follows the OpenID specification in resolving the
* attributes of the link tags. This means that the attributes DO
* NOT get resolved as they would by an XML or HTML parser. In
* particular, only certain entities get replaced, and href
* attributes do not get resolved relative to a base URL.
*
* From http://openid.net/specs.bml:
*
* - The openid.server URL MUST be an absolute URL. OpenID consumers
* MUST NOT attempt to resolve relative URLs.
*
* - The openid.server URL MUST NOT include entities other than &amp;,
* &lt;, &gt;, and &quot;.
*
* The parser ignores SGML comments and <![CDATA[blocks]]>. Both kinds
* of quoting are allowed for attributes.
*
* The parser deals with invalid markup in these ways:
*
* - Tag names are not case-sensitive
*
* - The <html> tag is accepted even when it is not at the top level
*
* - The <head> tag is accepted even when it is not a direct child of
* the <html> tag, but a <html> tag must be an ancestor of the
* <head> tag
*
* - <link> tags are accepted even when they are not direct children
* of the <head> tag, but a <head> tag must be an ancestor of the
* <link> tag
*
* - If there is no closing tag for an open <html> or <head> tag, the
* remainder of the document is viewed as being inside of the
* tag. If there is no closing tag for a <link> tag, the link tag is
* treated as a short tag. Exceptions to this rule are that <html>
* closes <html> and <body> or <head> closes <head>
*
* - Attributes of the <link> tag are not required to be quoted.
*
* - In the case of duplicated attribute names, the attribute coming
* last in the tag will be the value returned.
*
* - Any text that does not parse as an attribute within a link tag
* will be ignored. (e.g. <link pumpkin rel='openid.server' /> will
* ignore pumpkin)
*
* - If there are more than one <html> or <head> tag, the parser only
* looks inside of the first one.
*
* - The contents of <script> tags are ignored entirely, except
* unclosed <script> tags. Unclosed <script> tags are ignored.
*
* - Any other invalid markup is ignored, including unclosed SGML
* comments and unclosed <![CDATA[blocks.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @access private
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* Require Auth_OpenID::arrayGet().
*/
require_once "Auth/OpenID.php";
class Auth_OpenID_Parse {
/**
* Specify some flags for use with regex matching.
*/
var $_re_flags = "si";
/**
* Stuff to remove before we start looking for tags
*/
var $_removed_re =
"<!--.*?-->|<!\[CDATA\[.*?\]\]>|<script\b(?!:)[^>]*>.*?<\/script>";
/**
* Starts with the tag name at a word boundary, where the tag name
* is not a namespace
*/
var $_tag_expr = "<%s\b(?!:)([^>]*?)(?:\/>|>(.*)(?:<\/?%s\s*>|\Z))";
var $_attr_find = '\b(\w+)=("[^"]*"|\'[^\']*\'|[^\'"\s\/<>]+)';
var $_open_tag_expr = "<%s\b";
var $_close_tag_expr = "<((\/%s\b)|(%s[^>\/]*\/))>";
function Auth_OpenID_Parse()
{
$this->_link_find = sprintf("/<link\b(?!:)([^>]*)(?!<)>/%s",
$this->_re_flags);
$this->_entity_replacements = array(
'amp' => '&',
'lt' => '<',
'gt' => '>',
'quot' => '"'
);
$this->_attr_find = sprintf("/%s/%s",
$this->_attr_find,
$this->_re_flags);
$this->_removed_re = sprintf("/%s/%s",
$this->_removed_re,
$this->_re_flags);
$this->_ent_replace =
sprintf("&(%s);", implode("|",
$this->_entity_replacements));
}
/**
* Returns a regular expression that will match a given tag in an
* SGML string.
*/
function tagMatcher($tag_name, $close_tags = null)
{
$expr = $this->_tag_expr;
if ($close_tags) {
$options = implode("|", array_merge(array($tag_name), $close_tags));
$closer = sprintf("(?:%s)", $options);
} else {
$closer = $tag_name;
}
$expr = sprintf($expr, $tag_name, $closer);
return sprintf("/%s/%s", $expr, $this->_re_flags);
}
function openTag($tag_name)
{
$expr = sprintf($this->_open_tag_expr, $tag_name);
return sprintf("/%s/%s", $expr, $this->_re_flags);
}
function closeTag($tag_name)
{
$expr = sprintf($this->_close_tag_expr, $tag_name, $tag_name);
return sprintf("/%s/%s", $expr, $this->_re_flags);
}
function htmlBegin($s)
{
$matches = array();
$result = preg_match($this->openTag('html'), $s,
$matches, PREG_OFFSET_CAPTURE);
if ($result === false || !$matches) {
return false;
}
// Return the offset of the first match.
return $matches[0][1];
}
function htmlEnd($s)
{
$matches = array();
$result = preg_match($this->closeTag('html'), $s,
$matches, PREG_OFFSET_CAPTURE);
if ($result === false || !$matches) {
return false;
}
// Return the offset of the first match.
return $matches[count($matches) - 1][1];
}
function headFind()
{
return $this->tagMatcher('head', array('body', 'html'));
}
function replaceEntities($str)
{
foreach ($this->_entity_replacements as $old => $new) {
$str = preg_replace(sprintf("/&%s;/", $old), $new, $str);
}
return $str;
}
function removeQuotes($str)
{
$matches = array();
$double = '/^"(.*)"$/';
$single = "/^\'(.*)\'$/";
if (preg_match($double, $str, $matches)) {
return $matches[1];
} else if (preg_match($single, $str, $matches)) {
return $matches[1];
} else {
return $str;
}
}
function match($regexp, $text, &$match)
{
if (!is_callable('mb_ereg_search_init')) {
if (!preg_match($regexp, $text, $match)) {
return false;
}
$match = $match[0];
return true;
}
$regexp = substr($regexp, 1, strlen($regexp) - 2 - strlen($this->_re_flags));
mb_ereg_search_init($text);
if (!mb_ereg_search($regexp)) {
return false;
}
$match = mb_ereg_search_getregs();
return true;
}
/**
* Find all link tags in a string representing a HTML document and
* return a list of their attributes.
*
* @todo This is quite ineffective and may fail with the default
* pcre.backtrack_limit of 100000 in PHP 5.2, if $html is big.
* It should rather use stripos (in PHP5) or strpos()+strtoupper()
* in PHP4 to manage this.
*
* @param string $html The text to parse
* @return array $list An array of arrays of attributes, one for each
* link tag
*/
function parseLinkAttrs($html)
{
$stripped = preg_replace($this->_removed_re,
"",
$html);
$html_begin = $this->htmlBegin($stripped);
$html_end = $this->htmlEnd($stripped);
if ($html_begin === false) {
return array();
}
if ($html_end === false) {
$html_end = strlen($stripped);
}
$stripped = substr($stripped, $html_begin,
$html_end - $html_begin);
// Workaround to prevent PREG_BACKTRACK_LIMIT_ERROR:
$old_btlimit = ini_set( 'pcre.backtrack_limit', -1 );
// Try to find the <HEAD> tag.
$head_re = $this->headFind();
$head_match = array();
if (!$this->match($head_re, $stripped, $head_match)) {
ini_set( 'pcre.backtrack_limit', $old_btlimit );
return array();
}
$link_data = array();
$link_matches = array();
if (!preg_match_all($this->_link_find, $head_match[0],
$link_matches)) {
ini_set( 'pcre.backtrack_limit', $old_btlimit );
return array();
}
foreach ($link_matches[0] as $link) {
$attr_matches = array();
preg_match_all($this->_attr_find, $link, $attr_matches);
$link_attrs = array();
foreach ($attr_matches[0] as $index => $full_match) {
$name = $attr_matches[1][$index];
$value = $this->replaceEntities(
$this->removeQuotes($attr_matches[2][$index]));
$link_attrs[strtolower($name)] = $value;
}
$link_data[] = $link_attrs;
}
ini_set( 'pcre.backtrack_limit', $old_btlimit );
return $link_data;
}
function relMatches($rel_attr, $target_rel)
{
// Does this target_rel appear in the rel_str?
// XXX: TESTME
$rels = preg_split("/\s+/", trim($rel_attr));
foreach ($rels as $rel) {
$rel = strtolower($rel);
if ($rel == $target_rel) {
return 1;
}
}
return 0;
}
function linkHasRel($link_attrs, $target_rel)
{
// Does this link have target_rel as a relationship?
// XXX: TESTME
$rel_attr = Auth_OpeniD::arrayGet($link_attrs, 'rel', null);
return ($rel_attr && $this->relMatches($rel_attr,
$target_rel));
}
function findLinksRel($link_attrs_list, $target_rel)
{
// Filter the list of link attributes on whether it has
// target_rel as a relationship.
// XXX: TESTME
$result = array();
foreach ($link_attrs_list as $attr) {
if ($this->linkHasRel($attr, $target_rel)) {
$result[] = $attr;
}
}
return $result;
}
function findFirstHref($link_attrs_list, $target_rel)
{
// Return the value of the href attribute for the first link
// tag in the list that has target_rel as a relationship.
// XXX: TESTME
$matches = $this->findLinksRel($link_attrs_list,
$target_rel);
if (!$matches) {
return null;
}
$first = $matches[0];
return Auth_OpenID::arrayGet($first, 'href', null);
}
}
function Auth_OpenID_legacy_discover($html_text, $server_rel,
$delegate_rel)
{
$p = new Auth_OpenID_Parse();
$link_attrs = $p->parseLinkAttrs($html_text);
$server_url = $p->findFirstHref($link_attrs,
$server_rel);
if ($server_url === null) {
return false;
} else {
$delegate_url = $p->findFirstHref($link_attrs,
$delegate_rel);
return array($delegate_url, $server_url);
}
}

View File

@ -1,112 +0,0 @@
<?php
/**
* A PostgreSQL store.
*
* @package OpenID
*/
/**
* Require the base class file.
*/
require_once "Auth/OpenID/SQLStore.php";
/**
* An SQL store that uses PostgreSQL as its backend.
*
* @package OpenID
*/
class Auth_OpenID_PostgreSQLStore extends Auth_OpenID_SQLStore {
/**
* @access private
*/
function setSQL()
{
$this->sql['nonce_table'] =
"CREATE TABLE %s (server_url VARCHAR(2047) NOT NULL, ".
"timestamp INTEGER NOT NULL, ".
"salt CHAR(40) NOT NULL, ".
"UNIQUE (server_url, timestamp, salt))";
$this->sql['assoc_table'] =
"CREATE TABLE %s (server_url VARCHAR(2047) NOT NULL, ".
"handle VARCHAR(255) NOT NULL, ".
"secret BYTEA NOT NULL, ".
"issued INTEGER NOT NULL, ".
"lifetime INTEGER NOT NULL, ".
"assoc_type VARCHAR(64) NOT NULL, ".
"PRIMARY KEY (server_url, handle), ".
"CONSTRAINT secret_length_constraint CHECK ".
"(LENGTH(secret) <= 128))";
$this->sql['set_assoc'] =
array(
'insert_assoc' => "INSERT INTO %s (server_url, handle, ".
"secret, issued, lifetime, assoc_type) VALUES ".
"(?, ?, '!', ?, ?, ?)",
'update_assoc' => "UPDATE %s SET secret = '!', issued = ?, ".
"lifetime = ?, assoc_type = ? WHERE server_url = ? AND ".
"handle = ?"
);
$this->sql['get_assocs'] =
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ".
"WHERE server_url = ?";
$this->sql['get_assoc'] =
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ".
"WHERE server_url = ? AND handle = ?";
$this->sql['remove_assoc'] =
"DELETE FROM %s WHERE server_url = ? AND handle = ?";
$this->sql['add_nonce'] =
"INSERT INTO %s (server_url, timestamp, salt) VALUES ".
"(?, ?, ?)"
;
$this->sql['clean_nonce'] =
"DELETE FROM %s WHERE timestamp < ?";
$this->sql['clean_assoc'] =
"DELETE FROM %s WHERE issued + lifetime < ?";
}
/**
* @access private
*/
function _set_assoc($server_url, $handle, $secret, $issued, $lifetime,
$assoc_type)
{
$result = $this->_get_assoc($server_url, $handle);
if ($result) {
// Update the table since this associations already exists.
$this->connection->query($this->sql['set_assoc']['update_assoc'],
array($secret, $issued, $lifetime,
$assoc_type, $server_url, $handle));
} else {
// Insert a new record because this association wasn't
// found.
$this->connection->query($this->sql['set_assoc']['insert_assoc'],
array($server_url, $handle, $secret,
$issued, $lifetime, $assoc_type));
}
}
/**
* @access private
*/
function blobEncode($blob)
{
return $this->_octify($blob);
}
/**
* @access private
*/
function blobDecode($blob)
{
return $this->_unoctify($blob);
}
}

View File

@ -1,557 +0,0 @@
<?php
/**
* SQL-backed OpenID stores.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* @access private
*/
require_once 'Auth/OpenID/Interface.php';
require_once 'Auth/OpenID/Nonce.php';
/**
* @access private
*/
require_once 'Auth/OpenID.php';
/**
* @access private
*/
require_once 'Auth/OpenID/Nonce.php';
/**
* This is the parent class for the SQL stores, which contains the
* logic common to all of the SQL stores.
*
* The table names used are determined by the class variables
* associations_table_name and nonces_table_name. To change the name
* of the tables used, pass new table names into the constructor.
*
* To create the tables with the proper schema, see the createTables
* method.
*
* This class shouldn't be used directly. Use one of its subclasses
* instead, as those contain the code necessary to use a specific
* database. If you're an OpenID integrator and you'd like to create
* an SQL-driven store that wraps an application's database
* abstraction, be sure to create a subclass of
* {@link Auth_OpenID_DatabaseConnection} that calls the application's
* database abstraction calls. Then, pass an instance of your new
* database connection class to your SQLStore subclass constructor.
*
* All methods other than the constructor and createTables should be
* considered implementation details.
*
* @package OpenID
*/
class Auth_OpenID_SQLStore extends Auth_OpenID_OpenIDStore {
/**
* This creates a new SQLStore instance. It requires an
* established database connection be given to it, and it allows
* overriding the default table names.
*
* @param connection $connection This must be an established
* connection to a database of the correct type for the SQLStore
* subclass you're using. This must either be an PEAR DB
* connection handle or an instance of a subclass of
* Auth_OpenID_DatabaseConnection.
*
* @param associations_table: This is an optional parameter to
* specify the name of the table used for storing associations.
* The default value is 'oid_associations'.
*
* @param nonces_table: This is an optional parameter to specify
* the name of the table used for storing nonces. The default
* value is 'oid_nonces'.
*/
function Auth_OpenID_SQLStore($connection,
$associations_table = null,
$nonces_table = null)
{
$this->associations_table_name = "oid_associations";
$this->nonces_table_name = "oid_nonces";
// Check the connection object type to be sure it's a PEAR
// database connection.
if (!(is_object($connection) &&
(is_subclass_of($connection, 'db_common') ||
is_subclass_of($connection,
'auth_openid_databaseconnection')))) {
trigger_error("Auth_OpenID_SQLStore expected PEAR connection " .
"object (got ".get_class($connection).")",
E_USER_ERROR);
return;
}
$this->connection = $connection;
// Be sure to set the fetch mode so the results are keyed on
// column name instead of column index. This is a PEAR
// constant, so only try to use it if PEAR is present. Note
// that Auth_Openid_Databaseconnection instances need not
// implement ::setFetchMode for this reason.
if (is_subclass_of($this->connection, 'db_common')) {
$this->connection->setFetchMode(DB_FETCHMODE_ASSOC);
}
if ($associations_table) {
$this->associations_table_name = $associations_table;
}
if ($nonces_table) {
$this->nonces_table_name = $nonces_table;
}
$this->max_nonce_age = 6 * 60 * 60;
// Be sure to run the database queries with auto-commit mode
// turned OFF, because we want every function to run in a
// transaction, implicitly. As a rule, methods named with a
// leading underscore will NOT control transaction behavior.
// Callers of these methods will worry about transactions.
$this->connection->autoCommit(false);
// Create an empty SQL strings array.
$this->sql = array();
// Call this method (which should be overridden by subclasses)
// to populate the $this->sql array with SQL strings.
$this->setSQL();
// Verify that all required SQL statements have been set, and
// raise an error if any expected SQL strings were either
// absent or empty.
list($missing, $empty) = $this->_verifySQL();
if ($missing) {
trigger_error("Expected keys in SQL query list: " .
implode(", ", $missing),
E_USER_ERROR);
return;
}
if ($empty) {
trigger_error("SQL list keys have no SQL strings: " .
implode(", ", $empty),
E_USER_ERROR);
return;
}
// Add table names to queries.
$this->_fixSQL();
}
function tableExists($table_name)
{
return !$this->isError(
$this->connection->query(
sprintf("SELECT * FROM %s LIMIT 0",
$table_name)));
}
/**
* Returns true if $value constitutes a database error; returns
* false otherwise.
*/
function isError($value)
{
return PEAR::isError($value);
}
/**
* Converts a query result to a boolean. If the result is a
* database error according to $this->isError(), this returns
* false; otherwise, this returns true.
*/
function resultToBool($obj)
{
if ($this->isError($obj)) {
return false;
} else {
return true;
}
}
/**
* This method should be overridden by subclasses. This method is
* called by the constructor to set values in $this->sql, which is
* an array keyed on sql name.
*/
function setSQL()
{
}
/**
* Resets the store by removing all records from the store's
* tables.
*/
function reset()
{
$this->connection->query(sprintf("DELETE FROM %s",
$this->associations_table_name));
$this->connection->query(sprintf("DELETE FROM %s",
$this->nonces_table_name));
}
/**
* @access private
*/
function _verifySQL()
{
$missing = array();
$empty = array();
$required_sql_keys = array(
'nonce_table',
'assoc_table',
'set_assoc',
'get_assoc',
'get_assocs',
'remove_assoc'
);
foreach ($required_sql_keys as $key) {
if (!array_key_exists($key, $this->sql)) {
$missing[] = $key;
} else if (!$this->sql[$key]) {
$empty[] = $key;
}
}
return array($missing, $empty);
}
/**
* @access private
*/
function _fixSQL()
{
$replacements = array(
array(
'value' => $this->nonces_table_name,
'keys' => array('nonce_table',
'add_nonce',
'clean_nonce')
),
array(
'value' => $this->associations_table_name,
'keys' => array('assoc_table',
'set_assoc',
'get_assoc',
'get_assocs',
'remove_assoc',
'clean_assoc')
)
);
foreach ($replacements as $item) {
$value = $item['value'];
$keys = $item['keys'];
foreach ($keys as $k) {
if (is_array($this->sql[$k])) {
foreach ($this->sql[$k] as $part_key => $part_value) {
$this->sql[$k][$part_key] = sprintf($part_value,
$value);
}
} else {
$this->sql[$k] = sprintf($this->sql[$k], $value);
}
}
}
}
function blobDecode($blob)
{
return $blob;
}
function blobEncode($str)
{
return $str;
}
function createTables()
{
$this->connection->autoCommit(true);
$n = $this->create_nonce_table();
$a = $this->create_assoc_table();
$this->connection->autoCommit(false);
if ($n && $a) {
return true;
} else {
return false;
}
}
function create_nonce_table()
{
if (!$this->tableExists($this->nonces_table_name)) {
$r = $this->connection->query($this->sql['nonce_table']);
return $this->resultToBool($r);
}
return true;
}
function create_assoc_table()
{
if (!$this->tableExists($this->associations_table_name)) {
$r = $this->connection->query($this->sql['assoc_table']);
return $this->resultToBool($r);
}
return true;
}
/**
* @access private
*/
function _set_assoc($server_url, $handle, $secret, $issued,
$lifetime, $assoc_type)
{
return $this->connection->query($this->sql['set_assoc'],
array(
$server_url,
$handle,
$secret,
$issued,
$lifetime,
$assoc_type));
}
function storeAssociation($server_url, $association)
{
if ($this->resultToBool($this->_set_assoc(
$server_url,
$association->handle,
$this->blobEncode(
$association->secret),
$association->issued,
$association->lifetime,
$association->assoc_type
))) {
$this->connection->commit();
} else {
$this->connection->rollback();
}
}
/**
* @access private
*/
function _get_assoc($server_url, $handle)
{
$result = $this->connection->getRow($this->sql['get_assoc'],
array($server_url, $handle));
if ($this->isError($result)) {
return null;
} else {
return $result;
}
}
/**
* @access private
*/
function _get_assocs($server_url)
{
$result = $this->connection->getAll($this->sql['get_assocs'],
array($server_url));
if ($this->isError($result)) {
return array();
} else {
return $result;
}
}
function removeAssociation($server_url, $handle)
{
if ($this->_get_assoc($server_url, $handle) == null) {
return false;
}
if ($this->resultToBool($this->connection->query(
$this->sql['remove_assoc'],
array($server_url, $handle)))) {
$this->connection->commit();
} else {
$this->connection->rollback();
}
return true;
}
function getAssociation($server_url, $handle = null)
{
if ($handle !== null) {
$assoc = $this->_get_assoc($server_url, $handle);
$assocs = array();
if ($assoc) {
$assocs[] = $assoc;
}
} else {
$assocs = $this->_get_assocs($server_url);
}
if (!$assocs || (count($assocs) == 0)) {
return null;
} else {
$associations = array();
foreach ($assocs as $assoc_row) {
$assoc = new Auth_OpenID_Association($assoc_row['handle'],
$assoc_row['secret'],
$assoc_row['issued'],
$assoc_row['lifetime'],
$assoc_row['assoc_type']);
$assoc->secret = $this->blobDecode($assoc->secret);
if ($assoc->getExpiresIn() == 0) {
$this->removeAssociation($server_url, $assoc->handle);
} else {
$associations[] = array($assoc->issued, $assoc);
}
}
if ($associations) {
$issued = array();
$assocs = array();
foreach ($associations as $key => $assoc) {
$issued[$key] = $assoc[0];
$assocs[$key] = $assoc[1];
}
array_multisort($issued, SORT_DESC, $assocs, SORT_DESC,
$associations);
// return the most recently issued one.
list($issued, $assoc) = $associations[0];
return $assoc;
} else {
return null;
}
}
}
/**
* @access private
*/
function _add_nonce($server_url, $timestamp, $salt)
{
$sql = $this->sql['add_nonce'];
$result = $this->connection->query($sql, array($server_url,
$timestamp,
$salt));
if ($this->isError($result)) {
$this->connection->rollback();
} else {
$this->connection->commit();
}
return $this->resultToBool($result);
}
function useNonce($server_url, $timestamp, $salt)
{
global $Auth_OpenID_SKEW;
if ( abs($timestamp - time()) > $Auth_OpenID_SKEW ) {
return false;
}
return $this->_add_nonce($server_url, $timestamp, $salt);
}
/**
* "Octifies" a binary string by returning a string with escaped
* octal bytes. This is used for preparing binary data for
* PostgreSQL BYTEA fields.
*
* @access private
*/
function _octify($str)
{
$result = "";
for ($i = 0; $i < Auth_OpenID::bytes($str); $i++) {
$ch = substr($str, $i, 1);
if ($ch == "\\") {
$result .= "\\\\\\\\";
} else if (ord($ch) == 0) {
$result .= "\\\\000";
} else {
$result .= "\\" . strval(decoct(ord($ch)));
}
}
return $result;
}
/**
* "Unoctifies" octal-escaped data from PostgreSQL and returns the
* resulting ASCII (possibly binary) string.
*
* @access private
*/
function _unoctify($str)
{
$result = "";
$i = 0;
while ($i < strlen($str)) {
$char = $str[$i];
if ($char == "\\") {
// Look to see if the next char is a backslash and
// append it.
if ($str[$i + 1] != "\\") {
$octal_digits = substr($str, $i + 1, 3);
$dec = octdec($octal_digits);
$char = chr($dec);
$i += 4;
} else {
$char = "\\";
$i += 2;
}
} else {
$i += 1;
}
$result .= $char;
}
return $result;
}
function cleanupNonces()
{
global $Auth_OpenID_SKEW;
$v = time() - $Auth_OpenID_SKEW;
$this->connection->query($this->sql['clean_nonce'], array($v));
$num = $this->connection->affectedRows();
$this->connection->commit();
return $num;
}
function cleanupAssociations()
{
$this->connection->query($this->sql['clean_assoc'],
array(time()));
$num = $this->connection->affectedRows();
$this->connection->commit();
return $num;
}
}

View File

@ -1,70 +0,0 @@
<?php
/**
* An SQLite store.
*
* @package OpenID
*/
/**
* Require the base class file.
*/
require_once "Auth/OpenID/SQLStore.php";
/**
* An SQL store that uses SQLite as its backend.
*
* @package OpenID
*/
class Auth_OpenID_SQLiteStore extends Auth_OpenID_SQLStore {
function setSQL()
{
$this->sql['nonce_table'] =
"CREATE TABLE %s (server_url VARCHAR(2047), timestamp INTEGER, ".
"salt CHAR(40), UNIQUE (server_url, timestamp, salt))";
$this->sql['assoc_table'] =
"CREATE TABLE %s (server_url VARCHAR(2047), handle VARCHAR(255), ".
"secret BLOB(128), issued INTEGER, lifetime INTEGER, ".
"assoc_type VARCHAR(64), PRIMARY KEY (server_url, handle))";
$this->sql['set_assoc'] =
"INSERT OR REPLACE INTO %s VALUES (?, ?, ?, ?, ?, ?)";
$this->sql['get_assocs'] =
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ".
"WHERE server_url = ?";
$this->sql['get_assoc'] =
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ".
"WHERE server_url = ? AND handle = ?";
$this->sql['remove_assoc'] =
"DELETE FROM %s WHERE server_url = ? AND handle = ?";
$this->sql['add_nonce'] =
"INSERT INTO %s (server_url, timestamp, salt) VALUES (?, ?, ?)";
$this->sql['clean_nonce'] =
"DELETE FROM %s WHERE timestamp < ?";
$this->sql['clean_assoc'] =
"DELETE FROM %s WHERE issued + lifetime < ?";
}
/**
* @access private
*/
function _add_nonce($server_url, $timestamp, $salt)
{
// PECL SQLite extensions 1.0.3 and older (1.0.3 is the
// current release at the time of this writing) have a broken
// sqlite_escape_string function that breaks when passed the
// empty string. Prefixing all strings with one character
// keeps them unique and avoids this bug. The nonce table is
// write-only, so we don't have to worry about updating other
// functions with this same bad hack.
return parent::_add_nonce('x' . $server_url, $timestamp, $salt);
}
}

View File

@ -1,521 +0,0 @@
<?php
/**
* Simple registration request and response parsing and object
* representation.
*
* This module contains objects representing simple registration
* requests and responses that can be used with both OpenID relying
* parties and OpenID providers.
*
* 1. The relying party creates a request object and adds it to the
* {@link Auth_OpenID_AuthRequest} object before making the
* checkid request to the OpenID provider:
*
* $sreg_req = Auth_OpenID_SRegRequest::build(array('email'));
* $auth_request->addExtension($sreg_req);
*
* 2. The OpenID provider extracts the simple registration request
* from the OpenID request using {@link
* Auth_OpenID_SRegRequest::fromOpenIDRequest}, gets the user's
* approval and data, creates an {@link Auth_OpenID_SRegResponse}
* object and adds it to the id_res response:
*
* $sreg_req = Auth_OpenID_SRegRequest::fromOpenIDRequest(
* $checkid_request);
* // [ get the user's approval and data, informing the user that
* // the fields in sreg_response were requested ]
* $sreg_resp = Auth_OpenID_SRegResponse::extractResponse(
* $sreg_req, $user_data);
* $sreg_resp->toMessage($openid_response->fields);
*
* 3. The relying party uses {@link
* Auth_OpenID_SRegResponse::fromSuccessResponse} to extract the data
* from the OpenID response:
*
* $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse(
* $success_response);
*
* @package OpenID
*/
/**
* Import message and extension internals.
*/
require_once 'Auth/OpenID/Message.php';
require_once 'Auth/OpenID/Extension.php';
// The data fields that are listed in the sreg spec
global $Auth_OpenID_sreg_data_fields;
$Auth_OpenID_sreg_data_fields = array(
'fullname' => 'Full Name',
'nickname' => 'Nickname',
'dob' => 'Date of Birth',
'email' => 'E-mail Address',
'gender' => 'Gender',
'postcode' => 'Postal Code',
'country' => 'Country',
'language' => 'Language',
'timezone' => 'Time Zone');
/**
* Check to see that the given value is a valid simple registration
* data field name. Return true if so, false if not.
*/
function Auth_OpenID_checkFieldName($field_name)
{
global $Auth_OpenID_sreg_data_fields;
if (!in_array($field_name, array_keys($Auth_OpenID_sreg_data_fields))) {
return false;
}
return true;
}
// URI used in the wild for Yadis documents advertising simple
// registration support
define('Auth_OpenID_SREG_NS_URI_1_0', 'http://openid.net/sreg/1.0');
// URI in the draft specification for simple registration 1.1
// <http://openid.net/specs/openid-simple-registration-extension-1_1-01.html>
define('Auth_OpenID_SREG_NS_URI_1_1', 'http://openid.net/extensions/sreg/1.1');
// This attribute will always hold the preferred URI to use when
// adding sreg support to an XRDS file or in an OpenID namespace
// declaration.
define('Auth_OpenID_SREG_NS_URI', Auth_OpenID_SREG_NS_URI_1_1);
Auth_OpenID_registerNamespaceAlias(Auth_OpenID_SREG_NS_URI_1_1, 'sreg');
/**
* Does the given endpoint advertise support for simple
* registration?
*
* $endpoint: The endpoint object as returned by OpenID discovery.
* returns whether an sreg type was advertised by the endpoint
*/
function Auth_OpenID_supportsSReg($endpoint)
{
return ($endpoint->usesExtension(Auth_OpenID_SREG_NS_URI_1_1) ||
$endpoint->usesExtension(Auth_OpenID_SREG_NS_URI_1_0));
}
/**
* A base class for classes dealing with Simple Registration protocol
* messages.
*
* @package OpenID
*/
class Auth_OpenID_SRegBase extends Auth_OpenID_Extension {
/**
* Extract the simple registration namespace URI from the given
* OpenID message. Handles OpenID 1 and 2, as well as both sreg
* namespace URIs found in the wild, as well as missing namespace
* definitions (for OpenID 1)
*
* $message: The OpenID message from which to parse simple
* registration fields. This may be a request or response message.
*
* Returns the sreg namespace URI for the supplied message. The
* message may be modified to define a simple registration
* namespace.
*
* @access private
*/
static function _getSRegNS($message)
{
$alias = null;
$found_ns_uri = null;
// See if there exists an alias for one of the two defined
// simple registration types.
foreach (array(Auth_OpenID_SREG_NS_URI_1_1,
Auth_OpenID_SREG_NS_URI_1_0) as $sreg_ns_uri) {
$alias = $message->namespaces->getAlias($sreg_ns_uri);
if ($alias !== null) {
$found_ns_uri = $sreg_ns_uri;
break;
}
}
if ($alias === null) {
// There is no alias for either of the types, so try to
// add one. We default to using the modern value (1.1)
$found_ns_uri = Auth_OpenID_SREG_NS_URI_1_1;
if ($message->namespaces->addAlias(Auth_OpenID_SREG_NS_URI_1_1,
'sreg') === null) {
// An alias for the string 'sreg' already exists, but
// it's defined for something other than simple
// registration
return null;
}
}
return $found_ns_uri;
}
}
/**
* An object to hold the state of a simple registration request.
*
* required: A list of the required fields in this simple registration
* request
*
* optional: A list of the optional fields in this simple registration
* request
*
* @package OpenID
*/
class Auth_OpenID_SRegRequest extends Auth_OpenID_SRegBase {
var $ns_alias = 'sreg';
/**
* Initialize an empty simple registration request.
*/
static function build($required=null, $optional=null,
$policy_url=null,
$sreg_ns_uri=Auth_OpenID_SREG_NS_URI,
$cls='Auth_OpenID_SRegRequest')
{
$obj = new $cls();
$obj->required = array();
$obj->optional = array();
$obj->policy_url = $policy_url;
$obj->ns_uri = $sreg_ns_uri;
if ($required) {
if (!$obj->requestFields($required, true, true)) {
return null;
}
}
if ($optional) {
if (!$obj->requestFields($optional, false, true)) {
return null;
}
}
return $obj;
}
/**
* Create a simple registration request that contains the fields
* that were requested in the OpenID request with the given
* arguments
*
* $request: The OpenID authentication request from which to
* extract an sreg request.
*
* $cls: name of class to use when creating sreg request object.
* Used for testing.
*
* Returns the newly created simple registration request
*/
static function fromOpenIDRequest($request, $cls='Auth_OpenID_SRegRequest')
{
$obj = call_user_func_array(array($cls, 'build'),
array(null, null, null, Auth_OpenID_SREG_NS_URI, $cls));
// Since we're going to mess with namespace URI mapping, don't
// mutate the object that was passed in.
$m = $request->message;
$obj->ns_uri = $obj->_getSRegNS($m);
$args = $m->getArgs($obj->ns_uri);
if ($args === null || Auth_OpenID::isFailure($args)) {
return null;
}
$obj->parseExtensionArgs($args);
return $obj;
}
/**
* Parse the unqualified simple registration request parameters
* and add them to this object.
*
* This method is essentially the inverse of
* getExtensionArgs. This method restores the serialized simple
* registration request fields.
*
* If you are extracting arguments from a standard OpenID
* checkid_* request, you probably want to use fromOpenIDRequest,
* which will extract the sreg namespace and arguments from the
* OpenID request. This method is intended for cases where the
* OpenID server needs more control over how the arguments are
* parsed than that method provides.
*
* $args == $message->getArgs($ns_uri);
* $request->parseExtensionArgs($args);
*
* $args: The unqualified simple registration arguments
*
* strict: Whether requests with fields that are not defined in
* the simple registration specification should be tolerated (and
* ignored)
*/
function parseExtensionArgs($args, $strict=false)
{
foreach (array('required', 'optional') as $list_name) {
$required = ($list_name == 'required');
$items = Auth_OpenID::arrayGet($args, $list_name);
if ($items) {
foreach (explode(',', $items) as $field_name) {
if (!$this->requestField($field_name, $required, $strict)) {
if ($strict) {
return false;
}
}
}
}
}
$this->policy_url = Auth_OpenID::arrayGet($args, 'policy_url');
return true;
}
/**
* A list of all of the simple registration fields that were
* requested, whether they were required or optional.
*/
function allRequestedFields()
{
return array_merge($this->required, $this->optional);
}
/**
* Have any simple registration fields been requested?
*/
function wereFieldsRequested()
{
return count($this->allRequestedFields());
}
/**
* Was this field in the request?
*/
function contains($field_name)
{
return (in_array($field_name, $this->required) ||
in_array($field_name, $this->optional));
}
/**
* Request the specified field from the OpenID user
*
* $field_name: the unqualified simple registration field name
*
* required: whether the given field should be presented to the
* user as being a required to successfully complete the request
*
* strict: whether to raise an exception when a field is added to
* a request more than once
*/
function requestField($field_name,
$required=false, $strict=false)
{
if (!Auth_OpenID_checkFieldName($field_name)) {
return false;
}
if ($strict) {
if ($this->contains($field_name)) {
return false;
}
} else {
if (in_array($field_name, $this->required)) {
return true;
}
if (in_array($field_name, $this->optional)) {
if ($required) {
unset($this->optional[array_search($field_name,
$this->optional)]);
} else {
return true;
}
}
}
if ($required) {
$this->required[] = $field_name;
} else {
$this->optional[] = $field_name;
}
return true;
}
/**
* Add the given list of fields to the request
*
* field_names: The simple registration data fields to request
*
* required: Whether these values should be presented to the user
* as required
*
* strict: whether to raise an exception when a field is added to
* a request more than once
*/
function requestFields($field_names, $required=false, $strict=false)
{
if (!is_array($field_names)) {
return false;
}
foreach ($field_names as $field_name) {
if (!$this->requestField($field_name, $required, $strict=$strict)) {
return false;
}
}
return true;
}
/**
* Get a dictionary of unqualified simple registration arguments
* representing this request.
*
* This method is essentially the inverse of
* C{L{parseExtensionArgs}}. This method serializes the simple
* registration request fields.
*/
function getExtensionArgs()
{
$args = array();
if ($this->required) {
$args['required'] = implode(',', $this->required);
}
if ($this->optional) {
$args['optional'] = implode(',', $this->optional);
}
if ($this->policy_url) {
$args['policy_url'] = $this->policy_url;
}
return $args;
}
}
/**
* Represents the data returned in a simple registration response
* inside of an OpenID C{id_res} response. This object will be created
* by the OpenID server, added to the C{id_res} response object, and
* then extracted from the C{id_res} message by the Consumer.
*
* @package OpenID
*/
class Auth_OpenID_SRegResponse extends Auth_OpenID_SRegBase {
var $ns_alias = 'sreg';
function Auth_OpenID_SRegResponse($data=null,
$sreg_ns_uri=Auth_OpenID_SREG_NS_URI)
{
if ($data === null) {
$this->data = array();
} else {
$this->data = $data;
}
$this->ns_uri = $sreg_ns_uri;
}
/**
* Take a C{L{SRegRequest}} and a dictionary of simple
* registration values and create a C{L{SRegResponse}} object
* containing that data.
*
* request: The simple registration request object
*
* data: The simple registration data for this response, as a
* dictionary from unqualified simple registration field name to
* string (unicode) value. For instance, the nickname should be
* stored under the key 'nickname'.
*/
static function extractResponse($request, $data)
{
$obj = new Auth_OpenID_SRegResponse();
$obj->ns_uri = $request->ns_uri;
foreach ($request->allRequestedFields() as $field) {
$value = Auth_OpenID::arrayGet($data, $field);
if ($value !== null) {
$obj->data[$field] = $value;
}
}
return $obj;
}
/**
* Create a C{L{SRegResponse}} object from a successful OpenID
* library response
* (C{L{openid.consumer.consumer.SuccessResponse}}) response
* message
*
* success_response: A SuccessResponse from consumer.complete()
*
* signed_only: Whether to process only data that was
* signed in the id_res message from the server.
*
* Returns a simple registration response containing the data that
* was supplied with the C{id_res} response.
*/
static function fromSuccessResponse($success_response, $signed_only=true)
{
global $Auth_OpenID_sreg_data_fields;
$obj = new Auth_OpenID_SRegResponse();
$obj->ns_uri = $obj->_getSRegNS($success_response->message);
if ($signed_only) {
$args = $success_response->getSignedNS($obj->ns_uri);
} else {
$args = $success_response->message->getArgs($obj->ns_uri);
}
if ($args === null || Auth_OpenID::isFailure($args)) {
return null;
}
foreach ($Auth_OpenID_sreg_data_fields as $field_name => $desc) {
if (in_array($field_name, array_keys($args))) {
$obj->data[$field_name] = $args[$field_name];
}
}
return $obj;
}
function getExtensionArgs()
{
return $this->data;
}
// Read-only dictionary interface
function get($field_name, $default=null)
{
if (!Auth_OpenID_checkFieldName($field_name)) {
return null;
}
return Auth_OpenID::arrayGet($this->data, $field_name, $default);
}
function contents()
{
return $this->data;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,36 +0,0 @@
<?php
/**
* OpenID Server Request
*
* @see Auth_OpenID_Server
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* Imports
*/
require_once "Auth/OpenID.php";
/**
* Object that holds the state of a request to the OpenID server
*
* With accessor functions to get at the internal request data.
*
* @see Auth_OpenID_Server
* @package OpenID
*/
class Auth_OpenID_ServerRequest {
function Auth_OpenID_ServerRequest()
{
$this->mode = null;
}
}

View File

@ -1,461 +0,0 @@
<?php
/**
* Functions for dealing with OpenID trust roots
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
require_once 'Auth/OpenID/Discover.php';
/**
* A regular expression that matches a domain ending in a top-level domains.
* Used in checking trust roots for sanity.
*
* @access private
*/
define('Auth_OpenID___TLDs',
'/\.(ac|ad|ae|aero|af|ag|ai|al|am|an|ao|aq|ar|arpa|as|asia' .
'|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|biz|bj|bm|bn|bo|br' .
'|bs|bt|bv|bw|by|bz|ca|cat|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co' .
'|com|coop|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|edu|ee|eg' .
'|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl' .
'|gm|gn|gov|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie' .
'|il|im|in|info|int|io|iq|ir|is|it|je|jm|jo|jobs|jp|ke|kg|kh' .
'|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly' .
'|ma|mc|md|me|mg|mh|mil|mk|ml|mm|mn|mo|mobi|mp|mq|mr|ms|mt' .
'|mu|museum|mv|mw|mx|my|mz|na|name|nc|ne|net|nf|ng|ni|nl|no' .
'|np|nr|nu|nz|om|org|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|pro|ps|pt' .
'|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl' .
'|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tel|tf|tg|th|tj|tk|tl|tm' .
'|tn|to|tp|tr|travel|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve' .
'|vg|vi|vn|vu|wf|ws|xn--0zwm56d|xn--11b5bs3a9aj6g' .
'|xn--80akhbyknj4f|xn--9t4b11yi5a|xn--deba0ad|xn--g6w251d' .
'|xn--hgbk6aj7f53bba|xn--hlcj6aya9esc7a|xn--jxalpdlp' .
'|xn--kgbechtv|xn--zckzah|ye|yt|yu|za|zm|zw)\.?$/');
define('Auth_OpenID___HostSegmentRe',
"/^(?:[-a-zA-Z0-9!$&'\\(\\)\\*+,;=._~]|%[a-zA-Z0-9]{2})*$/");
/**
* A wrapper for trust-root related functions
*/
class Auth_OpenID_TrustRoot {
/*
* Return a discovery URL for this realm.
*
* Return null if the realm could not be parsed or was not valid.
*
* @param return_to The relying party return URL of the OpenID
* authentication request
*
* @return The URL upon which relying party discovery should be
* run in order to verify the return_to URL
*/
static function buildDiscoveryURL($realm)
{
$parsed = Auth_OpenID_TrustRoot::_parse($realm);
if ($parsed === false) {
return false;
}
if ($parsed['wildcard']) {
// Use "www." in place of the star
if ($parsed['host'][0] != '.') {
return false;
}
$www_domain = 'www' . $parsed['host'];
return sprintf('%s://%s%s', $parsed['scheme'],
$www_domain, $parsed['path']);
} else {
return $parsed['unparsed'];
}
}
/**
* Parse a URL into its trust_root parts.
*
* @static
*
* @access private
*
* @param string $trust_root The url to parse
*
* @return mixed $parsed Either an associative array of trust root
* parts or false if parsing failed.
*/
static function _parse($trust_root)
{
$trust_root = Auth_OpenID_urinorm($trust_root);
if ($trust_root === null) {
return false;
}
if (preg_match("/:\/\/[^:]+(:\d+){2,}(\/|$)/", $trust_root)) {
return false;
}
$parts = @parse_url($trust_root);
if ($parts === false) {
return false;
}
$required_parts = array('scheme', 'host');
$forbidden_parts = array('user', 'pass', 'fragment');
$keys = array_keys($parts);
if (array_intersect($keys, $required_parts) != $required_parts) {
return false;
}
if (array_intersect($keys, $forbidden_parts) != array()) {
return false;
}
if (!preg_match(Auth_OpenID___HostSegmentRe, $parts['host'])) {
return false;
}
$scheme = strtolower($parts['scheme']);
$allowed_schemes = array('http', 'https');
if (!in_array($scheme, $allowed_schemes)) {
return false;
}
$parts['scheme'] = $scheme;
$host = strtolower($parts['host']);
$hostparts = explode('*', $host);
switch (count($hostparts)) {
case 1:
$parts['wildcard'] = false;
break;
case 2:
if ($hostparts[0] ||
($hostparts[1] && substr($hostparts[1], 0, 1) != '.')) {
return false;
}
$host = $hostparts[1];
$parts['wildcard'] = true;
break;
default:
return false;
}
if (strpos($host, ':') !== false) {
return false;
}
$parts['host'] = $host;
if (isset($parts['path'])) {
$path = strtolower($parts['path']);
if (substr($path, 0, 1) != '/') {
return false;
}
} else {
$path = '/';
}
$parts['path'] = $path;
if (!isset($parts['port'])) {
$parts['port'] = false;
}
$parts['unparsed'] = $trust_root;
return $parts;
}
/**
* Is this trust root sane?
*
* A trust root is sane if it is syntactically valid and it has a
* reasonable domain name. Specifically, the domain name must be
* more than one level below a standard TLD or more than two
* levels below a two-letter tld.
*
* For example, '*.com' is not a sane trust root, but '*.foo.com'
* is. '*.co.uk' is not sane, but '*.bbc.co.uk' is.
*
* This check is not always correct, but it attempts to err on the
* side of marking sane trust roots insane instead of marking
* insane trust roots sane. For example, 'kink.fm' is marked as
* insane even though it "should" (for some meaning of should) be
* marked sane.
*
* This function should be used when creating OpenID servers to
* alert the users of the server when a consumer attempts to get
* the user to accept a suspicious trust root.
*
* @static
* @param string $trust_root The trust root to check
* @return bool $sanity Whether the trust root looks OK
*/
static function isSane($trust_root)
{
$parts = Auth_OpenID_TrustRoot::_parse($trust_root);
if ($parts === false) {
return false;
}
// Localhost is a special case
if ($parts['host'] == 'localhost') {
return true;
}
$host_parts = explode('.', $parts['host']);
if ($parts['wildcard']) {
// Remove the empty string from the beginning of the array
array_shift($host_parts);
}
if ($host_parts && !$host_parts[count($host_parts) - 1]) {
array_pop($host_parts);
}
if (!$host_parts) {
return false;
}
// Don't allow adjacent dots
if (in_array('', $host_parts, true)) {
return false;
}
// Get the top-level domain of the host. If it is not a valid TLD,
// it's not sane.
preg_match(Auth_OpenID___TLDs, $parts['host'], $matches);
if (!$matches) {
return false;
}
$tld = $matches[1];
if (count($host_parts) == 1) {
return false;
}
if ($parts['wildcard']) {
// It's a 2-letter tld with a short second to last segment
// so there needs to be more than two segments specified
// (e.g. *.co.uk is insane)
$second_level = $host_parts[count($host_parts) - 2];
if (strlen($tld) == 2 && strlen($second_level) <= 3) {
return count($host_parts) > 2;
}
}
return true;
}
/**
* Does this URL match the given trust root?
*
* Return whether the URL falls under the given trust root. This
* does not check whether the trust root is sane. If the URL or
* trust root do not parse, this function will return false.
*
* @param string $trust_root The trust root to match against
*
* @param string $url The URL to check
*
* @return bool $matches Whether the URL matches against the
* trust root
*/
static function match($trust_root, $url)
{
$trust_root_parsed = Auth_OpenID_TrustRoot::_parse($trust_root);
$url_parsed = Auth_OpenID_TrustRoot::_parse($url);
if (!$trust_root_parsed || !$url_parsed) {
return false;
}
// Check hosts matching
if ($url_parsed['wildcard']) {
return false;
}
if ($trust_root_parsed['wildcard']) {
$host_tail = $trust_root_parsed['host'];
$host = $url_parsed['host'];
if ($host_tail &&
substr($host, -(strlen($host_tail))) != $host_tail &&
substr($host_tail, 1) != $host) {
return false;
}
} else {
if ($trust_root_parsed['host'] != $url_parsed['host']) {
return false;
}
}
// Check path and query matching
$base_path = $trust_root_parsed['path'];
$path = $url_parsed['path'];
if (!isset($trust_root_parsed['query'])) {
if ($base_path != $path) {
if (substr($path, 0, strlen($base_path)) != $base_path) {
return false;
}
if (substr($base_path, strlen($base_path) - 1, 1) != '/' &&
substr($path, strlen($base_path), 1) != '/') {
return false;
}
}
} else {
$base_query = $trust_root_parsed['query'];
$query = @$url_parsed['query'];
$qplus = substr($query, 0, strlen($base_query) + 1);
$bqplus = $base_query . '&';
if ($base_path != $path ||
($base_query != $query && $qplus != $bqplus)) {
return false;
}
}
// The port and scheme need to match exactly
return ($trust_root_parsed['scheme'] == $url_parsed['scheme'] &&
$url_parsed['port'] === $trust_root_parsed['port']);
}
}
/*
* If the endpoint is a relying party OpenID return_to endpoint,
* return the endpoint URL. Otherwise, return None.
*
* This function is intended to be used as a filter for the Yadis
* filtering interface.
*
* @see: C{L{openid.yadis.services}}
* @see: C{L{openid.yadis.filters}}
*
* @param endpoint: An XRDS BasicServiceEndpoint, as returned by
* performing Yadis dicovery.
*
* @returns: The endpoint URL or None if the endpoint is not a
* relying party endpoint.
*/
function filter_extractReturnURL($endpoint)
{
if ($endpoint->matchTypes(array(Auth_OpenID_RP_RETURN_TO_URL_TYPE))) {
return $endpoint;
} else {
return null;
}
}
function &Auth_OpenID_extractReturnURL(&$endpoint_list)
{
$result = array();
foreach ($endpoint_list as $endpoint) {
if (filter_extractReturnURL($endpoint)) {
$result[] = $endpoint;
}
}
return $result;
}
/*
* Is the return_to URL under one of the supplied allowed return_to
* URLs?
*/
function Auth_OpenID_returnToMatches($allowed_return_to_urls, $return_to)
{
foreach ($allowed_return_to_urls as $allowed_return_to) {
// A return_to pattern works the same as a realm, except that
// it's not allowed to use a wildcard. We'll model this by
// parsing it as a realm, and not trying to match it if it has
// a wildcard.
$return_realm = Auth_OpenID_TrustRoot::_parse($allowed_return_to);
if (// Parses as a trust root
($return_realm !== false) &&
// Does not have a wildcard
(!$return_realm['wildcard']) &&
// Matches the return_to that we passed in with it
(Auth_OpenID_TrustRoot::match($allowed_return_to, $return_to))) {
return true;
}
}
// No URL in the list matched
return false;
}
/*
* Given a relying party discovery URL return a list of return_to
* URLs.
*/
function Auth_OpenID_getAllowedReturnURLs($relying_party_url, $fetcher,
$discover_function=null)
{
if ($discover_function === null) {
$discover_function = array('Auth_Yadis_Yadis', 'discover');
}
$xrds_parse_cb = array('Auth_OpenID_ServiceEndpoint', 'consumerFromXRDS');
list($rp_url_after_redirects, $endpoints) =
Auth_Yadis_getServiceEndpoints($relying_party_url, $xrds_parse_cb,
$discover_function, $fetcher);
if ($rp_url_after_redirects != $relying_party_url) {
// Verification caused a redirect
return false;
}
call_user_func_array($discover_function,
array($relying_party_url, &$fetcher));
$return_to_urls = array();
$matching_endpoints = Auth_OpenID_extractReturnURL($endpoints);
foreach ($matching_endpoints as $e) {
$return_to_urls[] = $e->server_url;
}
return $return_to_urls;
}
/*
* Verify that a return_to URL is valid for the given realm.
*
* This function builds a discovery URL, performs Yadis discovery on
* it, makes sure that the URL does not redirect, parses out the
* return_to URLs, and finally checks to see if the current return_to
* URL matches the return_to.
*
* @return true if the return_to URL is valid for the realm
*/
function Auth_OpenID_verifyReturnTo($realm_str, $return_to, $fetcher,
$_vrfy='Auth_OpenID_getAllowedReturnURLs')
{
$disco_url = Auth_OpenID_TrustRoot::buildDiscoveryURL($realm_str);
if ($disco_url === false) {
return false;
}
$allowable_urls = call_user_func_array($_vrfy,
array($disco_url, $fetcher));
// The realm_str could not be parsed.
if ($allowable_urls === false) {
return false;
}
if (Auth_OpenID_returnToMatches($allowable_urls, $return_to)) {
return true;
} else {
return false;
}
}

View File

@ -1,249 +0,0 @@
<?php
/**
* URI normalization routines.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
require_once 'Auth/Yadis/Misc.php';
// from appendix B of rfc 3986 (http://www.ietf.org/rfc/rfc3986.txt)
function Auth_OpenID_getURIPattern()
{
return '&^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?&';
}
function Auth_OpenID_getAuthorityPattern()
{
return '/^([^@]*@)?([^:]*)(:.*)?/';
}
function Auth_OpenID_getEncodedPattern()
{
return '/%([0-9A-Fa-f]{2})/';
}
# gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
#
# sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
# / "*" / "+" / "," / ";" / "="
#
# unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
function Auth_OpenID_getURLIllegalCharRE()
{
return "/([^-A-Za-z0-9:\/\?#\[\]@\!\$&'\(\)\*\+,;=\._~\%])/";
}
function Auth_OpenID_getUnreserved()
{
$_unreserved = array();
for ($i = 0; $i < 256; $i++) {
$_unreserved[$i] = false;
}
for ($i = ord('A'); $i <= ord('Z'); $i++) {
$_unreserved[$i] = true;
}
for ($i = ord('0'); $i <= ord('9'); $i++) {
$_unreserved[$i] = true;
}
for ($i = ord('a'); $i <= ord('z'); $i++) {
$_unreserved[$i] = true;
}
$_unreserved[ord('-')] = true;
$_unreserved[ord('.')] = true;
$_unreserved[ord('_')] = true;
$_unreserved[ord('~')] = true;
return $_unreserved;
}
function Auth_OpenID_getEscapeRE()
{
$parts = array();
foreach (array_merge(Auth_Yadis_getUCSChars(),
Auth_Yadis_getIPrivateChars()) as $pair) {
list($m, $n) = $pair;
$parts[] = sprintf("%s-%s", chr($m), chr($n));
}
return sprintf('[%s]', implode('', $parts));
}
function Auth_OpenID_pct_encoded_replace_unreserved($mo)
{
$_unreserved = Auth_OpenID_getUnreserved();
$i = intval($mo[1], 16);
if ($_unreserved[$i]) {
return chr($i);
} else {
return strtoupper($mo[0]);
}
return $mo[0];
}
function Auth_OpenID_pct_encoded_replace($mo)
{
return chr(intval($mo[1], 16));
}
function Auth_OpenID_remove_dot_segments($path)
{
$result_segments = array();
while ($path) {
if (Auth_Yadis_startswith($path, '../')) {
$path = substr($path, 3);
} else if (Auth_Yadis_startswith($path, './')) {
$path = substr($path, 2);
} else if (Auth_Yadis_startswith($path, '/./')) {
$path = substr($path, 2);
} else if ($path == '/.') {
$path = '/';
} else if (Auth_Yadis_startswith($path, '/../')) {
$path = substr($path, 3);
if ($result_segments) {
array_pop($result_segments);
}
} else if ($path == '/..') {
$path = '/';
if ($result_segments) {
array_pop($result_segments);
}
} else if (($path == '..') ||
($path == '.')) {
$path = '';
} else {
$i = 0;
if ($path[0] == '/') {
$i = 1;
}
$i = strpos($path, '/', $i);
if ($i === false) {
$i = strlen($path);
}
$result_segments[] = substr($path, 0, $i);
$path = substr($path, $i);
}
}
return implode('', $result_segments);
}
function Auth_OpenID_urinorm($uri)
{
$uri_matches = array();
preg_match(Auth_OpenID_getURIPattern(), $uri, $uri_matches);
if (count($uri_matches) < 9) {
for ($i = count($uri_matches); $i <= 9; $i++) {
$uri_matches[] = '';
}
}
$illegal_matches = array();
preg_match(Auth_OpenID_getURLIllegalCharRE(),
$uri, $illegal_matches);
if ($illegal_matches) {
return null;
}
$scheme = $uri_matches[2];
if ($scheme) {
$scheme = strtolower($scheme);
}
$scheme = $uri_matches[2];
if ($scheme === '') {
// No scheme specified
return null;
}
$scheme = strtolower($scheme);
if (!in_array($scheme, array('http', 'https'))) {
// Not an absolute HTTP or HTTPS URI
return null;
}
$authority = $uri_matches[4];
if ($authority === '') {
// Not an absolute URI
return null;
}
$authority_matches = array();
preg_match(Auth_OpenID_getAuthorityPattern(),
$authority, $authority_matches);
if (count($authority_matches) === 0) {
// URI does not have a valid authority
return null;
}
if (count($authority_matches) < 4) {
for ($i = count($authority_matches); $i <= 4; $i++) {
$authority_matches[] = '';
}
}
list($_whole, $userinfo, $host, $port) = $authority_matches;
if ($userinfo === null) {
$userinfo = '';
}
if (strpos($host, '%') !== -1) {
$host = strtolower($host);
$host = preg_replace_callback(
Auth_OpenID_getEncodedPattern(),
'Auth_OpenID_pct_encoded_replace', $host);
// NO IDNA.
// $host = unicode($host, 'utf-8').encode('idna');
} else {
$host = strtolower($host);
}
if ($port) {
if (($port == ':') ||
($scheme == 'http' && $port == ':80') ||
($scheme == 'https' && $port == ':443')) {
$port = '';
}
} else {
$port = '';
}
$authority = $userinfo . $host . $port;
$path = $uri_matches[5];
$path = preg_replace_callback(
Auth_OpenID_getEncodedPattern(),
'Auth_OpenID_pct_encoded_replace_unreserved', $path);
$path = Auth_OpenID_remove_dot_segments($path);
if (!$path) {
$path = '/';
}
$query = $uri_matches[6];
if ($query === null) {
$query = '';
}
$fragment = $uri_matches[8];
if ($fragment === null) {
$fragment = '';
}
return $scheme . '://' . $authority . $path . $query . $fragment;
}

View File

@ -1,174 +0,0 @@
<?php
/**
* This module contains the HTTP fetcher interface
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* Require logging functionality
*/
require_once "Auth/OpenID.php";
define('Auth_OpenID_FETCHER_MAX_RESPONSE_KB', 1024);
define('Auth_OpenID_USER_AGENT',
'php-openid/'.Auth_OpenID_VERSION.' (php/'.phpversion().')');
class Auth_Yadis_HTTPResponse {
function Auth_Yadis_HTTPResponse($final_url = null, $status = null,
$headers = null, $body = null)
{
$this->final_url = $final_url;
$this->status = $status;
$this->headers = $headers;
$this->body = $body;
}
}
/**
* This class is the interface for HTTP fetchers the Yadis library
* uses. This interface is only important if you need to write a new
* fetcher for some reason.
*
* @access private
* @package OpenID
*/
class Auth_Yadis_HTTPFetcher {
var $timeout = 20; // timeout in seconds.
/**
* Return whether a URL can be fetched. Returns false if the URL
* scheme is not allowed or is not supported by this fetcher
* implementation; returns true otherwise.
*
* @return bool
*/
function canFetchURL($url)
{
if ($this->isHTTPS($url) && !$this->supportsSSL()) {
Auth_OpenID::log("HTTPS URL unsupported fetching %s",
$url);
return false;
}
if (!$this->allowedURL($url)) {
Auth_OpenID::log("URL fetching not allowed for '%s'",
$url);
return false;
}
return true;
}
/**
* Return whether a URL should be allowed. Override this method to
* conform to your local policy.
*
* By default, will attempt to fetch any http or https URL.
*/
function allowedURL($url)
{
return $this->URLHasAllowedScheme($url);
}
/**
* Does this fetcher implementation (and runtime) support fetching
* HTTPS URLs? May inspect the runtime environment.
*
* @return bool $support True if this fetcher supports HTTPS
* fetching; false if not.
*/
function supportsSSL()
{
trigger_error("not implemented", E_USER_ERROR);
}
/**
* Is this an https URL?
*
* @access private
*/
function isHTTPS($url)
{
return (bool)preg_match('/^https:\/\//i', $url);
}
/**
* Is this an http or https URL?
*
* @access private
*/
function URLHasAllowedScheme($url)
{
return (bool)preg_match('/^https?:\/\//i', $url);
}
/**
* @access private
*/
function _findRedirect($headers, $url)
{
foreach ($headers as $line) {
if (strpos(strtolower($line), "location: ") === 0) {
$parts = explode(" ", $line, 2);
$loc = $parts[1];
$ppos = strpos($loc, "://");
if ($ppos === false || $ppos > strpos($loc, "/")) {
/* no host; add it */
$hpos = strpos($url, "://");
$prt = substr($url, 0, $hpos+3);
$url = substr($url, $hpos+3);
if (substr($loc, 0, 1) == "/") {
/* absolute path */
$fspos = strpos($url, "/");
if ($fspos) $loc = $prt.substr($url, 0, $fspos).$loc;
else $loc = $prt.$url.$loc;
} else {
/* relative path */
$pp = $prt;
while (1) {
$xpos = strpos($url, "/");
if ($xpos === false) break;
$apos = strpos($url, "?");
if ($apos !== false && $apos < $xpos) break;
$apos = strpos($url, "&");
if ($apos !== false && $apos < $xpos) break;
$pp .= substr($url, 0, $xpos+1);
$url = substr($url, $xpos+1);
}
$loc = $pp.$loc;
}
}
return $loc;
}
}
return null;
}
/**
* Fetches the specified URL using optional extra headers and
* returns the server's response.
*
* @param string $url The URL to be fetched.
* @param array $extra_headers An array of header strings
* (e.g. "Accept: text/html").
* @return mixed $result An array of ($code, $url, $headers,
* $body) if the URL could be fetched; null if the URL does not
* pass the URLHasAllowedScheme check or if the server's response
* is malformed.
*/
function get($url, $headers = null)
{
trigger_error("not implemented", E_USER_ERROR);
}
}

View File

@ -1,523 +0,0 @@
<?php
/**
* Yadis service manager to be used during yadis-driven authentication
* attempts.
*
* @package OpenID
*/
/**
* The base session class used by the Auth_Yadis_Manager. This
* class wraps the default PHP session machinery and should be
* subclassed if your application doesn't use PHP sessioning.
*
* @package OpenID
*/
class Auth_Yadis_PHPSession {
/**
* Set a session key/value pair.
*
* @param string $name The name of the session key to add.
* @param string $value The value to add to the session.
*/
function set($name, $value)
{
$_SESSION[$name] = $value;
}
/**
* Get a key's value from the session.
*
* @param string $name The name of the key to retrieve.
* @param string $default The optional value to return if the key
* is not found in the session.
* @return string $result The key's value in the session or
* $default if it isn't found.
*/
function get($name, $default=null)
{
if (array_key_exists($name, $_SESSION)) {
return $_SESSION[$name];
} else {
return $default;
}
}
/**
* Remove a key/value pair from the session.
*
* @param string $name The name of the key to remove.
*/
function del($name)
{
unset($_SESSION[$name]);
}
/**
* Return the contents of the session in array form.
*/
function contents()
{
return $_SESSION;
}
}
/**
* A session helper class designed to translate between arrays and
* objects. Note that the class used must have a constructor that
* takes no parameters. This is not a general solution, but it works
* for dumb objects that just need to have attributes set. The idea
* is that you'll subclass this and override $this->check($data) ->
* bool to implement your own session data validation.
*
* @package OpenID
*/
class Auth_Yadis_SessionLoader {
/**
* Override this.
*
* @access private
*/
function check($data)
{
return true;
}
/**
* Given a session data value (an array), this creates an object
* (returned by $this->newObject()) whose attributes and values
* are those in $data. Returns null if $data lacks keys found in
* $this->requiredKeys(). Returns null if $this->check($data)
* evaluates to false. Returns null if $this->newObject()
* evaluates to false.
*
* @access private
*/
function fromSession($data)
{
if (!$data) {
return null;
}
$required = $this->requiredKeys();
foreach ($required as $k) {
if (!array_key_exists($k, $data)) {
return null;
}
}
if (!$this->check($data)) {
return null;
}
$data = array_merge($data, $this->prepareForLoad($data));
$obj = $this->newObject($data);
if (!$obj) {
return null;
}
foreach ($required as $k) {
$obj->$k = $data[$k];
}
return $obj;
}
/**
* Prepares the data array by making any necessary changes.
* Returns an array whose keys and values will be used to update
* the original data array before calling $this->newObject($data).
*
* @access private
*/
function prepareForLoad($data)
{
return array();
}
/**
* Returns a new instance of this loader's class, using the
* session data to construct it if necessary. The object need
* only be created; $this->fromSession() will take care of setting
* the object's attributes.
*
* @access private
*/
function newObject($data)
{
return null;
}
/**
* Returns an array of keys and values built from the attributes
* of $obj. If $this->prepareForSave($obj) returns an array, its keys
* and values are used to update the $data array of attributes
* from $obj.
*
* @access private
*/
function toSession($obj)
{
$data = array();
foreach ($obj as $k => $v) {
$data[$k] = $v;
}
$extra = $this->prepareForSave($obj);
if ($extra && is_array($extra)) {
foreach ($extra as $k => $v) {
$data[$k] = $v;
}
}
return $data;
}
/**
* Override this.
*
* @access private
*/
function prepareForSave($obj)
{
return array();
}
}
/**
* A concrete loader implementation for Auth_OpenID_ServiceEndpoints.
*
* @package OpenID
*/
class Auth_OpenID_ServiceEndpointLoader extends Auth_Yadis_SessionLoader {
function newObject($data)
{
return new Auth_OpenID_ServiceEndpoint();
}
function requiredKeys()
{
$obj = new Auth_OpenID_ServiceEndpoint();
$data = array();
foreach ($obj as $k => $v) {
$data[] = $k;
}
return $data;
}
function check($data)
{
return is_array($data['type_uris']);
}
}
/**
* A concrete loader implementation for Auth_Yadis_Managers.
*
* @package OpenID
*/
class Auth_Yadis_ManagerLoader extends Auth_Yadis_SessionLoader {
function requiredKeys()
{
return array('starting_url',
'yadis_url',
'services',
'session_key',
'_current',
'stale');
}
function newObject($data)
{
return new Auth_Yadis_Manager($data['starting_url'],
$data['yadis_url'],
$data['services'],
$data['session_key']);
}
function check($data)
{
return is_array($data['services']);
}
function prepareForLoad($data)
{
$loader = new Auth_OpenID_ServiceEndpointLoader();
$services = array();
foreach ($data['services'] as $s) {
$services[] = $loader->fromSession($s);
}
return array('services' => $services);
}
function prepareForSave($obj)
{
$loader = new Auth_OpenID_ServiceEndpointLoader();
$services = array();
foreach ($obj->services as $s) {
$services[] = $loader->toSession($s);
}
return array('services' => $services);
}
}
/**
* The Yadis service manager which stores state in a session and
* iterates over <Service> elements in a Yadis XRDS document and lets
* a caller attempt to use each one. This is used by the Yadis
* library internally.
*
* @package OpenID
*/
class Auth_Yadis_Manager {
/**
* Intialize a new yadis service manager.
*
* @access private
*/
function Auth_Yadis_Manager($starting_url, $yadis_url,
$services, $session_key)
{
// The URL that was used to initiate the Yadis protocol
$this->starting_url = $starting_url;
// The URL after following redirects (the identifier)
$this->yadis_url = $yadis_url;
// List of service elements
$this->services = $services;
$this->session_key = $session_key;
// Reference to the current service object
$this->_current = null;
// Stale flag for cleanup if PHP lib has trouble.
$this->stale = false;
}
/**
* @access private
*/
function length()
{
// How many untried services remain?
return count($this->services);
}
/**
* Return the next service
*
* $this->current() will continue to return that service until the
* next call to this method.
*/
function nextService()
{
if ($this->services) {
$this->_current = array_shift($this->services);
} else {
$this->_current = null;
}
return $this->_current;
}
/**
* @access private
*/
function current()
{
// Return the current service.
// Returns None if there are no services left.
return $this->_current;
}
/**
* @access private
*/
function forURL($url)
{
return in_array($url, array($this->starting_url, $this->yadis_url));
}
/**
* @access private
*/
function started()
{
// Has the first service been returned?
return $this->_current !== null;
}
}
/**
* State management for discovery.
*
* High-level usage pattern is to call .getNextService(discover) in
* order to find the next available service for this user for this
* session. Once a request completes, call .cleanup() to clean up the
* session state.
*
* @package OpenID
*/
class Auth_Yadis_Discovery {
/**
* @access private
*/
var $DEFAULT_SUFFIX = 'auth';
/**
* @access private
*/
var $PREFIX = '_yadis_services_';
/**
* Initialize a discovery object.
*
* @param Auth_Yadis_PHPSession $session An object which
* implements the Auth_Yadis_PHPSession API.
* @param string $url The URL on which to attempt discovery.
* @param string $session_key_suffix The optional session key
* suffix override.
*/
function Auth_Yadis_Discovery($session, $url,
$session_key_suffix = null)
{
/// Initialize a discovery object
$this->session = $session;
$this->url = $url;
if ($session_key_suffix === null) {
$session_key_suffix = $this->DEFAULT_SUFFIX;
}
$this->session_key_suffix = $session_key_suffix;
$this->session_key = $this->PREFIX . $this->session_key_suffix;
}
/**
* Return the next authentication service for the pair of
* user_input and session. This function handles fallback.
*/
function getNextService($discover_cb, $fetcher)
{
$manager = $this->getManager();
if (!$manager || (!$manager->services)) {
$this->destroyManager();
list($yadis_url, $services) = call_user_func_array($discover_cb,
array(
$this->url,
&$fetcher,
));
$manager = $this->createManager($services, $yadis_url);
}
if ($manager) {
$loader = new Auth_Yadis_ManagerLoader();
$service = $manager->nextService();
$this->session->set($this->session_key,
serialize($loader->toSession($manager)));
} else {
$service = null;
}
return $service;
}
/**
* Clean up Yadis-related services in the session and return the
* most-recently-attempted service from the manager, if one
* exists.
*
* @param $force True if the manager should be deleted regardless
* of whether it's a manager for $this->url.
*/
function cleanup($force=false)
{
$manager = $this->getManager($force);
if ($manager) {
$service = $manager->current();
$this->destroyManager($force);
} else {
$service = null;
}
return $service;
}
/**
* @access private
*/
function getSessionKey()
{
// Get the session key for this starting URL and suffix
return $this->PREFIX . $this->session_key_suffix;
}
/**
* @access private
*
* @param $force True if the manager should be returned regardless
* of whether it's a manager for $this->url.
*/
function getManager($force=false)
{
// Extract the YadisServiceManager for this object's URL and
// suffix from the session.
$manager_str = $this->session->get($this->getSessionKey());
$manager = null;
if ($manager_str !== null) {
$loader = new Auth_Yadis_ManagerLoader();
$manager = $loader->fromSession(unserialize($manager_str));
}
if ($manager && ($manager->forURL($this->url) || $force)) {
return $manager;
}
}
/**
* @access private
*/
function createManager($services, $yadis_url = null)
{
$key = $this->getSessionKey();
if ($this->getManager()) {
return $this->getManager();
}
if ($services) {
$loader = new Auth_Yadis_ManagerLoader();
$manager = new Auth_Yadis_Manager($this->url, $yadis_url,
$services, $key);
$this->session->set($this->session_key,
serialize($loader->toSession($manager)));
return $manager;
}
}
/**
* @access private
*
* @param $force True if the manager should be deleted regardless
* of whether it's a manager for $this->url.
*/
function destroyManager($force=false)
{
if ($this->getManager($force) !== null) {
$key = $this->getSessionKey();
$this->session->del($key);
}
}
}

View File

@ -1,58 +0,0 @@
<?php
/**
* Miscellaneous utility values and functions for OpenID and Yadis.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
function Auth_Yadis_getUCSChars()
{
return array(
array(0xA0, 0xD7FF),
array(0xF900, 0xFDCF),
array(0xFDF0, 0xFFEF),
array(0x10000, 0x1FFFD),
array(0x20000, 0x2FFFD),
array(0x30000, 0x3FFFD),
array(0x40000, 0x4FFFD),
array(0x50000, 0x5FFFD),
array(0x60000, 0x6FFFD),
array(0x70000, 0x7FFFD),
array(0x80000, 0x8FFFD),
array(0x90000, 0x9FFFD),
array(0xA0000, 0xAFFFD),
array(0xB0000, 0xBFFFD),
array(0xC0000, 0xCFFFD),
array(0xD0000, 0xDFFFD),
array(0xE1000, 0xEFFFD)
);
}
function Auth_Yadis_getIPrivateChars()
{
return array(
array(0xE000, 0xF8FF),
array(0xF0000, 0xFFFFD),
array(0x100000, 0x10FFFD)
);
}
function Auth_Yadis_pct_escape_unicode($char_match)
{
$c = $char_match[0];
$result = "";
for ($i = 0; $i < strlen($c); $i++) {
$result .= "%".sprintf("%X", ord($c[$i]));
}
return $result;
}
function Auth_Yadis_startswith($s, $stuff)
{
return strpos($s, $stuff) === 0;
}

View File

@ -1,267 +0,0 @@
<?php
/**
* This module contains the CURL-based HTTP fetcher implementation.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* Interface import
*/
require_once "Auth/Yadis/HTTPFetcher.php";
require_once "Auth/OpenID.php";
/**
* A paranoid {@link Auth_Yadis_HTTPFetcher} class which uses CURL
* for fetching.
*
* @package OpenID
*/
class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher {
function Auth_Yadis_ParanoidHTTPFetcher()
{
$this->reset();
}
function reset()
{
$this->headers = array();
$this->data = "";
}
/**
* @access private
*/
function _writeHeader($ch, $header)
{
array_push($this->headers, rtrim($header));
return strlen($header);
}
/**
* @access private
*/
function _writeData($ch, $data)
{
if (strlen($this->data) > 1024*Auth_OpenID_FETCHER_MAX_RESPONSE_KB) {
return 0;
} else {
$this->data .= $data;
return strlen($data);
}
}
/**
* Does this fetcher support SSL URLs?
*/
function supportsSSL()
{
$v = curl_version();
if(is_array($v)) {
return in_array('https', $v['protocols']);
} elseif (is_string($v)) {
return preg_match('/OpenSSL/i', $v);
} else {
return 0;
}
}
function get($url, $extra_headers = null)
{
if (!$this->canFetchURL($url)) {
return null;
}
$stop = time() + $this->timeout;
$off = $this->timeout;
$redir = true;
while ($redir && ($off > 0)) {
$this->reset();
$c = curl_init();
if ($c === false) {
Auth_OpenID::log(
"curl_init returned false; could not " .
"initialize for URL '%s'", $url);
return null;
}
if (defined('CURLOPT_NOSIGNAL')) {
curl_setopt($c, CURLOPT_NOSIGNAL, true);
}
if (!$this->allowedURL($url)) {
Auth_OpenID::log("Fetching URL not allowed: %s",
$url);
return null;
}
curl_setopt($c, CURLOPT_WRITEFUNCTION,
array($this, "_writeData"));
curl_setopt($c, CURLOPT_HEADERFUNCTION,
array($this, "_writeHeader"));
if ($extra_headers) {
curl_setopt($c, CURLOPT_HTTPHEADER, $extra_headers);
}
$cv = curl_version();
if(is_array($cv)) {
$curl_user_agent = 'curl/'.$cv['version'];
} else {
$curl_user_agent = $cv;
}
curl_setopt($c, CURLOPT_USERAGENT,
Auth_OpenID_USER_AGENT.' '.$curl_user_agent);
curl_setopt($c, CURLOPT_TIMEOUT, $off);
curl_setopt($c, CURLOPT_URL, $url);
if (defined('Auth_OpenID_VERIFY_HOST')) {
// set SSL verification options only if Auth_OpenID_VERIFY_HOST
// is explicitly set, otherwise use system default.
if (Auth_OpenID_VERIFY_HOST) {
curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2);
if (defined('Auth_OpenID_CAINFO')) {
curl_setopt($c, CURLOPT_CAINFO, Auth_OpenID_CAINFO);
}
} else {
curl_setopt($c, CURLOPT_SSL_VERIFYPEER, false);
}
}
curl_exec($c);
$code = curl_getinfo($c, CURLINFO_HTTP_CODE);
$body = $this->data;
$headers = $this->headers;
if (!$code) {
Auth_OpenID::log("Got no response code when fetching %s", $url);
Auth_OpenID::log("CURL error (%s): %s",
curl_errno($c), curl_error($c));
return null;
}
if (in_array($code, array(301, 302, 303, 307))) {
$url = $this->_findRedirect($headers, $url);
$redir = true;
} else {
$redir = false;
curl_close($c);
if (defined('Auth_OpenID_VERIFY_HOST') &&
Auth_OpenID_VERIFY_HOST == true &&
$this->isHTTPS($url)) {
Auth_OpenID::log('OpenID: Verified SSL host %s using '.
'curl/get', $url);
}
$new_headers = array();
foreach ($headers as $header) {
if (strpos($header, ': ')) {
list($name, $value) = explode(': ', $header, 2);
$new_headers[$name] = $value;
}
}
Auth_OpenID::log(
"Successfully fetched '%s': GET response code %s",
$url, $code);
return new Auth_Yadis_HTTPResponse($url, $code,
$new_headers, $body);
}
$off = $stop - time();
}
return null;
}
function post($url, $body, $extra_headers = null)
{
if (!$this->canFetchURL($url)) {
return null;
}
$this->reset();
$c = curl_init();
if (defined('CURLOPT_NOSIGNAL')) {
curl_setopt($c, CURLOPT_NOSIGNAL, true);
}
curl_setopt($c, CURLOPT_POST, true);
curl_setopt($c, CURLOPT_POSTFIELDS, $body);
curl_setopt($c, CURLOPT_TIMEOUT, $this->timeout);
curl_setopt($c, CURLOPT_URL, $url);
curl_setopt($c, CURLOPT_WRITEFUNCTION,
array($this, "_writeData"));
if (defined('Auth_OpenID_VERIFY_HOST')) {
// set SSL verification options only if Auth_OpenID_VERIFY_HOST
// is explicitly set, otherwise use system default.
if (Auth_OpenID_VERIFY_HOST) {
curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2);
if (defined('Auth_OpenID_CAINFO')) {
curl_setopt($c, CURLOPT_CAINFO, Auth_OpenID_CAINFO);
}
} else {
curl_setopt($c, CURLOPT_SSL_VERIFYPEER, false);
}
}
curl_exec($c);
$code = curl_getinfo($c, CURLINFO_HTTP_CODE);
if (!$code) {
Auth_OpenID::log("Got no response code when fetching %s", $url);
Auth_OpenID::log("CURL error (%s): %s",
curl_errno($c), curl_error($c));
return null;
}
if (defined('Auth_OpenID_VERIFY_HOST') &&
Auth_OpenID_VERIFY_HOST == true &&
$this->isHTTPS($url)) {
Auth_OpenID::log('OpenID: Verified SSL host %s using '.
'curl/post', $url);
}
$body = $this->data;
curl_close($c);
$new_headers = $extra_headers;
foreach ($this->headers as $header) {
if (strpos($header, ': ')) {
list($name, $value) = explode(': ', $header, 2);
$new_headers[$name] = $value;
}
}
Auth_OpenID::log("Successfully fetched '%s': POST response code %s",
$url, $code);
return new Auth_Yadis_HTTPResponse($url, $code,
$new_headers, $body);
}
}

View File

@ -1,258 +0,0 @@
<?php
/**
* This is the HTML pseudo-parser for the Yadis library.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* This class is responsible for scanning an HTML string to find META
* tags and their attributes. This is used by the Yadis discovery
* process. This class must be instantiated to be used.
*
* @package OpenID
*/
class Auth_Yadis_ParseHTML {
/**
* @access private
*/
var $_re_flags = "si";
/**
* @access private
*/
var $_removed_re =
"<!--.*?-->|<!\[CDATA\[.*?\]\]>|<script\b(?!:)[^>]*>.*?<\/script>";
/**
* @access private
*/
var $_tag_expr = "<%s%s(?:\s.*?)?%s>";
/**
* @access private
*/
var $_attr_find = '\b([-\w]+)=(".*?"|\'.*?\'|.+?)[\/\s>]';
function Auth_Yadis_ParseHTML()
{
$this->_attr_find = sprintf("/%s/%s",
$this->_attr_find,
$this->_re_flags);
$this->_removed_re = sprintf("/%s/%s",
$this->_removed_re,
$this->_re_flags);
$this->_entity_replacements = array(
'amp' => '&',
'lt' => '<',
'gt' => '>',
'quot' => '"'
);
$this->_ent_replace =
sprintf("&(%s);", implode("|",
$this->_entity_replacements));
}
/**
* Replace HTML entities (amp, lt, gt, and quot) as well as
* numeric entities (e.g. #x9f;) with their actual values and
* return the new string.
*
* @access private
* @param string $str The string in which to look for entities
* @return string $new_str The new string entities decoded
*/
function replaceEntities($str)
{
foreach ($this->_entity_replacements as $old => $new) {
$str = preg_replace(sprintf("/&%s;/", $old), $new, $str);
}
// Replace numeric entities because html_entity_decode doesn't
// do it for us.
$str = preg_replace('~&#x([0-9a-f]+);~ei', 'chr(hexdec("\\1"))', $str);
$str = preg_replace('~&#([0-9]+);~e', 'chr(\\1)', $str);
return $str;
}
/**
* Strip single and double quotes off of a string, if they are
* present.
*
* @access private
* @param string $str The original string
* @return string $new_str The new string with leading and
* trailing quotes removed
*/
function removeQuotes($str)
{
$matches = array();
$double = '/^"(.*)"$/';
$single = "/^\'(.*)\'$/";
if (preg_match($double, $str, $matches)) {
return $matches[1];
} else if (preg_match($single, $str, $matches)) {
return $matches[1];
} else {
return $str;
}
}
/**
* Create a regular expression that will match an opening
* or closing tag from a set of names.
*
* @access private
* @param mixed $tag_names Tag names to match
* @param mixed $close false/0 = no, true/1 = yes, other = maybe
* @param mixed $self_close false/0 = no, true/1 = yes, other = maybe
* @return string $regex A regular expression string to be used
* in, say, preg_match.
*/
function tagPattern($tag_names, $close, $self_close)
{
if (is_array($tag_names)) {
$tag_names = '(?:'.implode('|',$tag_names).')';
}
if ($close) {
$close = '\/' . (($close == 1)? '' : '?');
} else {
$close = '';
}
if ($self_close) {
$self_close = '(?:\/\s*)' . (($self_close == 1)? '' : '?');
} else {
$self_close = '';
}
$expr = sprintf($this->_tag_expr, $close, $tag_names, $self_close);
return sprintf("/%s/%s", $expr, $this->_re_flags);
}
/**
* Given an HTML document string, this finds all the META tags in
* the document, provided they are found in the
* <HTML><HEAD>...</HEAD> section of the document. The <HTML> tag
* may be missing.
*
* @access private
* @param string $html_string An HTMl document string
* @return array $tag_list Array of tags; each tag is an array of
* attribute -> value.
*/
function getMetaTags($html_string)
{
$html_string = preg_replace($this->_removed_re,
"",
$html_string);
$key_tags = array($this->tagPattern('html', false, false),
$this->tagPattern('head', false, false),
$this->tagPattern('head', true, false),
$this->tagPattern('html', true, false),
$this->tagPattern(array(
'body', 'frameset', 'frame', 'p', 'div',
'table','span','a'), 'maybe', 'maybe'));
$key_tags_pos = array();
foreach ($key_tags as $pat) {
$matches = array();
preg_match($pat, $html_string, $matches, PREG_OFFSET_CAPTURE);
if($matches) {
$key_tags_pos[] = $matches[0][1];
} else {
$key_tags_pos[] = null;
}
}
// no opening head tag
if (is_null($key_tags_pos[1])) {
return array();
}
// the effective </head> is the min of the following
if (is_null($key_tags_pos[2])) {
$key_tags_pos[2] = strlen($html_string);
}
foreach (array($key_tags_pos[3], $key_tags_pos[4]) as $pos) {
if (!is_null($pos) && $pos < $key_tags_pos[2]) {
$key_tags_pos[2] = $pos;
}
}
// closing head tag comes before opening head tag
if ($key_tags_pos[1] > $key_tags_pos[2]) {
return array();
}
// if there is an opening html tag, make sure the opening head tag
// comes after it
if (!is_null($key_tags_pos[0]) && $key_tags_pos[1] < $key_tags_pos[0]) {
return array();
}
$html_string = substr($html_string, $key_tags_pos[1],
($key_tags_pos[2]-$key_tags_pos[1]));
$link_data = array();
$link_matches = array();
if (!preg_match_all($this->tagPattern('meta', false, 'maybe'),
$html_string, $link_matches)) {
return array();
}
foreach ($link_matches[0] as $link) {
$attr_matches = array();
preg_match_all($this->_attr_find, $link, $attr_matches);
$link_attrs = array();
foreach ($attr_matches[0] as $index => $full_match) {
$name = $attr_matches[1][$index];
$value = $this->replaceEntities(
$this->removeQuotes($attr_matches[2][$index]));
$link_attrs[strtolower($name)] = $value;
}
$link_data[] = $link_attrs;
}
return $link_data;
}
/**
* Looks for a META tag with an "http-equiv" attribute whose value
* is one of ("x-xrds-location", "x-yadis-location"), ignoring
* case. If such a META tag is found, its "content" attribute
* value is returned.
*
* @param string $html_string An HTML document in string format
* @return mixed $content The "content" attribute value of the
* META tag, if found, or null if no such tag was found.
*/
function getHTTPEquiv($html_string)
{
$meta_tags = $this->getMetaTags($html_string);
if ($meta_tags) {
foreach ($meta_tags as $tag) {
if (array_key_exists('http-equiv', $tag) &&
(in_array(strtolower($tag['http-equiv']),
array('x-xrds-location', 'x-yadis-location'))) &&
array_key_exists('content', $tag)) {
return $tag['content'];
}
}
}
return null;
}
}

View File

@ -1,248 +0,0 @@
<?php
/**
* This module contains the plain non-curl HTTP fetcher
* implementation.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* Interface import
*/
require_once "Auth/Yadis/HTTPFetcher.php";
/**
* This class implements a plain, hand-built socket-based fetcher
* which will be used in the event that CURL is unavailable.
*
* @package OpenID
*/
class Auth_Yadis_PlainHTTPFetcher extends Auth_Yadis_HTTPFetcher {
/**
* Does this fetcher support SSL URLs?
*/
function supportsSSL()
{
return function_exists('openssl_open');
}
function get($url, $extra_headers = null)
{
if (!$this->canFetchURL($url)) {
return null;
}
$redir = true;
$stop = time() + $this->timeout;
$off = $this->timeout;
while ($redir && ($off > 0)) {
$parts = parse_url($url);
$specify_port = true;
// Set a default port.
if (!array_key_exists('port', $parts)) {
$specify_port = false;
if ($parts['scheme'] == 'http') {
$parts['port'] = 80;
} elseif ($parts['scheme'] == 'https') {
$parts['port'] = 443;
} else {
return null;
}
}
if (!array_key_exists('path', $parts)) {
$parts['path'] = '/';
}
$host = $parts['host'];
if ($parts['scheme'] == 'https') {
$host = 'ssl://' . $host;
}
$user_agent = Auth_OpenID_USER_AGENT;
$headers = array(
"GET ".$parts['path'].
(array_key_exists('query', $parts) ?
"?".$parts['query'] : "").
" HTTP/1.0",
"User-Agent: $user_agent",
"Host: ".$parts['host'].
($specify_port ? ":".$parts['port'] : ""),
"Port: ".$parts['port']);
$errno = 0;
$errstr = '';
if ($extra_headers) {
foreach ($extra_headers as $h) {
$headers[] = $h;
}
}
@$sock = fsockopen($host, $parts['port'], $errno, $errstr,
$this->timeout);
if ($sock === false) {
return false;
}
stream_set_timeout($sock, $this->timeout);
fputs($sock, implode("\r\n", $headers) . "\r\n\r\n");
$data = "";
$kilobytes = 0;
while (!feof($sock) &&
$kilobytes < Auth_OpenID_FETCHER_MAX_RESPONSE_KB ) {
$data .= fgets($sock, 1024);
$kilobytes += 1;
}
fclose($sock);
// Split response into header and body sections
list($headers, $body) = explode("\r\n\r\n", $data, 2);
$headers = explode("\r\n", $headers);
$http_code = explode(" ", $headers[0]);
$code = $http_code[1];
if (in_array($code, array('301', '302'))) {
$url = $this->_findRedirect($headers, $url);
$redir = true;
} else {
$redir = false;
}
$off = $stop - time();
}
$new_headers = array();
foreach ($headers as $header) {
if (preg_match("/:/", $header)) {
$parts = explode(": ", $header, 2);
if (count($parts) == 2) {
list($name, $value) = $parts;
$new_headers[$name] = $value;
}
}
}
return new Auth_Yadis_HTTPResponse($url, $code, $new_headers, $body);
}
function post($url, $body, $extra_headers = null)
{
if (!$this->canFetchURL($url)) {
return null;
}
$parts = parse_url($url);
$headers = array();
$post_path = $parts['path'];
if (isset($parts['query'])) {
$post_path .= '?' . $parts['query'];
}
$headers[] = "POST ".$post_path." HTTP/1.0";
$headers[] = "Host: " . $parts['host'];
$headers[] = "Content-type: application/x-www-form-urlencoded";
$headers[] = "Content-length: " . strval(strlen($body));
if ($extra_headers &&
is_array($extra_headers)) {
$headers = array_merge($headers, $extra_headers);
}
// Join all headers together.
$all_headers = implode("\r\n", $headers);
// Add headers, two newlines, and request body.
$request = $all_headers . "\r\n\r\n" . $body;
// Set a default port.
if (!array_key_exists('port', $parts)) {
if ($parts['scheme'] == 'http') {
$parts['port'] = 80;
} elseif ($parts['scheme'] == 'https') {
$parts['port'] = 443;
} else {
return null;
}
}
if ($parts['scheme'] == 'https') {
$parts['host'] = sprintf("ssl://%s", $parts['host']);
}
// Connect to the remote server.
$errno = 0;
$errstr = '';
$sock = fsockopen($parts['host'], $parts['port'], $errno, $errstr,
$this->timeout);
if ($sock === false) {
return null;
}
stream_set_timeout($sock, $this->timeout);
// Write the POST request.
fputs($sock, $request);
// Get the response from the server.
$response = "";
while (!feof($sock)) {
if ($data = fgets($sock, 128)) {
$response .= $data;
} else {
break;
}
}
// Split the request into headers and body.
list($headers, $response_body) = explode("\r\n\r\n", $response, 2);
$headers = explode("\r\n", $headers);
// Expect the first line of the headers data to be something
// like HTTP/1.1 200 OK. Split the line on spaces and take
// the second token, which should be the return code.
$http_code = explode(" ", $headers[0]);
$code = $http_code[1];
$new_headers = array();
foreach ($headers as $header) {
if (preg_match("/:/", $header)) {
list($name, $value) = explode(": ", $header, 2);
$new_headers[$name] = $value;
}
}
return new Auth_Yadis_HTTPResponse($url, $code,
$new_headers, $response_body);
}
}

View File

@ -1,352 +0,0 @@
<?php
/**
* XML-parsing classes to wrap the domxml and DOM extensions for PHP 4
* and 5, respectively.
*
* @package OpenID
*/
/**
* The base class for wrappers for available PHP XML-parsing
* extensions. To work with this Yadis library, subclasses of this
* class MUST implement the API as defined in the remarks for this
* class. Subclasses of Auth_Yadis_XMLParser are used to wrap
* particular PHP XML extensions such as 'domxml'. These are used
* internally by the library depending on the availability of
* supported PHP XML extensions.
*
* @package OpenID
*/
class Auth_Yadis_XMLParser {
/**
* Initialize an instance of Auth_Yadis_XMLParser with some
* XML and namespaces. This SHOULD NOT be overridden by
* subclasses.
*
* @param string $xml_string A string of XML to be parsed.
* @param array $namespace_map An array of ($ns_name => $ns_uri)
* to be registered with the XML parser. May be empty.
* @return boolean $result True if the initialization and
* namespace registration(s) succeeded; false otherwise.
*/
function init($xml_string, $namespace_map)
{
if (!$this->setXML($xml_string)) {
return false;
}
foreach ($namespace_map as $prefix => $uri) {
if (!$this->registerNamespace($prefix, $uri)) {
return false;
}
}
return true;
}
/**
* Register a namespace with the XML parser. This should be
* overridden by subclasses.
*
* @param string $prefix The namespace prefix to appear in XML tag
* names.
*
* @param string $uri The namespace URI to be used to identify the
* namespace in the XML.
*
* @return boolean $result True if the registration succeeded;
* false otherwise.
*/
function registerNamespace($prefix, $uri)
{
// Not implemented.
}
/**
* Set this parser object's XML payload. This should be
* overridden by subclasses.
*
* @param string $xml_string The XML string to pass to this
* object's XML parser.
*
* @return boolean $result True if the initialization succeeded;
* false otherwise.
*/
function setXML($xml_string)
{
// Not implemented.
}
/**
* Evaluate an XPath expression and return the resulting node
* list. This should be overridden by subclasses.
*
* @param string $xpath The XPath expression to be evaluated.
*
* @param mixed $node A node object resulting from a previous
* evalXPath call. This node, if specified, provides the context
* for the evaluation of this xpath expression.
*
* @return array $node_list An array of matching opaque node
* objects to be used with other methods of this parser class.
*/
function &evalXPath($xpath, $node = null)
{
// Not implemented.
}
/**
* Return the textual content of a specified node.
*
* @param mixed $node A node object from a previous call to
* $this->evalXPath().
*
* @return string $content The content of this node.
*/
function content($node)
{
// Not implemented.
}
/**
* Return the attributes of a specified node.
*
* @param mixed $node A node object from a previous call to
* $this->evalXPath().
*
* @return array $attrs An array mapping attribute names to
* values.
*/
function attributes($node)
{
// Not implemented.
}
}
/**
* This concrete implementation of Auth_Yadis_XMLParser implements
* the appropriate API for the 'domxml' extension which is typically
* packaged with PHP 4. This class will be used whenever the 'domxml'
* extension is detected. See the Auth_Yadis_XMLParser class for
* details on this class's methods.
*
* @package OpenID
*/
class Auth_Yadis_domxml extends Auth_Yadis_XMLParser {
function Auth_Yadis_domxml()
{
$this->xml = null;
$this->doc = null;
$this->xpath = null;
$this->errors = array();
}
function setXML($xml_string)
{
$this->xml = $xml_string;
$this->doc = @domxml_open_mem($xml_string, DOMXML_LOAD_PARSING,
$this->errors);
if (!$this->doc) {
return false;
}
$this->xpath = $this->doc->xpath_new_context();
return true;
}
function registerNamespace($prefix, $uri)
{
return xpath_register_ns($this->xpath, $prefix, $uri);
}
function &evalXPath($xpath, $node = null)
{
if ($node) {
$result = @$this->xpath->xpath_eval($xpath, $node);
} else {
$result = @$this->xpath->xpath_eval($xpath);
}
if (!$result) {
$n = array();
return $n;
}
if (!$result->nodeset) {
$n = array();
return $n;
}
return $result->nodeset;
}
function content($node)
{
if ($node) {
return $node->get_content();
}
}
function attributes($node)
{
if ($node) {
$arr = $node->attributes();
$result = array();
if ($arr) {
foreach ($arr as $attrnode) {
$result[$attrnode->name] = $attrnode->value;
}
}
return $result;
}
}
}
/**
* This concrete implementation of Auth_Yadis_XMLParser implements
* the appropriate API for the 'dom' extension which is typically
* packaged with PHP 5. This class will be used whenever the 'dom'
* extension is detected. See the Auth_Yadis_XMLParser class for
* details on this class's methods.
*
* @package OpenID
*/
class Auth_Yadis_dom extends Auth_Yadis_XMLParser {
function Auth_Yadis_dom()
{
$this->xml = null;
$this->doc = null;
$this->xpath = null;
$this->errors = array();
}
function setXML($xml_string)
{
$this->xml = $xml_string;
$this->doc = new DOMDocument;
if (!$this->doc) {
return false;
}
if (!@$this->doc->loadXML($xml_string)) {
return false;
}
$this->xpath = new DOMXPath($this->doc);
if ($this->xpath) {
return true;
} else {
return false;
}
}
function registerNamespace($prefix, $uri)
{
return $this->xpath->registerNamespace($prefix, $uri);
}
function &evalXPath($xpath, $node = null)
{
if ($node) {
$result = @$this->xpath->query($xpath, $node);
} else {
$result = @$this->xpath->query($xpath);
}
$n = array();
if (!$result) {
return $n;
}
for ($i = 0; $i < $result->length; $i++) {
$n[] = $result->item($i);
}
return $n;
}
function content($node)
{
if ($node) {
return $node->textContent;
}
}
function attributes($node)
{
if ($node) {
$arr = $node->attributes;
$result = array();
if ($arr) {
for ($i = 0; $i < $arr->length; $i++) {
$node = $arr->item($i);
$result[$node->nodeName] = $node->nodeValue;
}
}
return $result;
}
}
}
global $__Auth_Yadis_defaultParser;
$__Auth_Yadis_defaultParser = null;
/**
* Set a default parser to override the extension-driven selection of
* available parser classes. This is helpful in a test environment or
* one in which multiple parsers can be used but one is more
* desirable.
*
* @param Auth_Yadis_XMLParser $parser An instance of a
* Auth_Yadis_XMLParser subclass.
*/
function Auth_Yadis_setDefaultParser($parser)
{
global $__Auth_Yadis_defaultParser;
$__Auth_Yadis_defaultParser = $parser;
}
function Auth_Yadis_getSupportedExtensions()
{
return array('dom' => 'Auth_Yadis_dom',
'domxml' => 'Auth_Yadis_domxml');
}
/**
* Returns an instance of a Auth_Yadis_XMLParser subclass based on
* the availability of PHP extensions for XML parsing. If
* Auth_Yadis_setDefaultParser has been called, the parser used in
* that call will be returned instead.
*/
function Auth_Yadis_getXMLParser()
{
global $__Auth_Yadis_defaultParser;
if (isset($__Auth_Yadis_defaultParser)) {
return $__Auth_Yadis_defaultParser;
}
foreach(Auth_Yadis_getSupportedExtensions() as $extension => $classname)
{
if (extension_loaded($extension))
{
$p = new $classname();
Auth_Yadis_setDefaultParser($p);
return $p;
}
}
return false;
}

View File

@ -1,478 +0,0 @@
<?php
/**
* This module contains the XRDS parsing code.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* Require the XPath implementation.
*/
require_once 'Auth/Yadis/XML.php';
/**
* This match mode means a given service must match ALL filters passed
* to the Auth_Yadis_XRDS::services() call.
*/
define('SERVICES_YADIS_MATCH_ALL', 101);
/**
* This match mode means a given service must match ANY filters (at
* least one) passed to the Auth_Yadis_XRDS::services() call.
*/
define('SERVICES_YADIS_MATCH_ANY', 102);
/**
* The priority value used for service elements with no priority
* specified.
*/
define('SERVICES_YADIS_MAX_PRIORITY', pow(2, 30));
/**
* XRD XML namespace
*/
define('Auth_Yadis_XMLNS_XRD_2_0', 'xri://$xrd*($v*2.0)');
/**
* XRDS XML namespace
*/
define('Auth_Yadis_XMLNS_XRDS', 'xri://$xrds');
function Auth_Yadis_getNSMap()
{
return array('xrds' => Auth_Yadis_XMLNS_XRDS,
'xrd' => Auth_Yadis_XMLNS_XRD_2_0);
}
/**
* @access private
*/
function Auth_Yadis_array_scramble($arr)
{
$result = array();
while (count($arr)) {
$index = array_rand($arr, 1);
$result[] = $arr[$index];
unset($arr[$index]);
}
return $result;
}
/**
* This class represents a <Service> element in an XRDS document.
* Objects of this type are returned by
* Auth_Yadis_XRDS::services() and
* Auth_Yadis_Yadis::services(). Each object corresponds directly
* to a <Service> element in the XRDS and supplies a
* getElements($name) method which you should use to inspect the
* element's contents. See {@link Auth_Yadis_Yadis} for more
* information on the role this class plays in Yadis discovery.
*
* @package OpenID
*/
class Auth_Yadis_Service {
/**
* Creates an empty service object.
*/
function Auth_Yadis_Service()
{
$this->element = null;
$this->parser = null;
}
/**
* Return the URIs in the "Type" elements, if any, of this Service
* element.
*
* @return array $type_uris An array of Type URI strings.
*/
function getTypes()
{
$t = array();
foreach ($this->getElements('xrd:Type') as $elem) {
$c = $this->parser->content($elem);
if ($c) {
$t[] = $c;
}
}
return $t;
}
function matchTypes($type_uris)
{
$result = array();
foreach ($this->getTypes() as $typ) {
if (in_array($typ, $type_uris)) {
$result[] = $typ;
}
}
return $result;
}
/**
* Return the URIs in the "URI" elements, if any, of this Service
* element. The URIs are returned sorted in priority order.
*
* @return array $uris An array of URI strings.
*/
function getURIs()
{
$uris = array();
$last = array();
foreach ($this->getElements('xrd:URI') as $elem) {
$uri_string = $this->parser->content($elem);
$attrs = $this->parser->attributes($elem);
if ($attrs &&
array_key_exists('priority', $attrs)) {
$priority = intval($attrs['priority']);
if (!array_key_exists($priority, $uris)) {
$uris[$priority] = array();
}
$uris[$priority][] = $uri_string;
} else {
$last[] = $uri_string;
}
}
$keys = array_keys($uris);
sort($keys);
// Rebuild array of URIs.
$result = array();
foreach ($keys as $k) {
$new_uris = Auth_Yadis_array_scramble($uris[$k]);
$result = array_merge($result, $new_uris);
}
$result = array_merge($result,
Auth_Yadis_array_scramble($last));
return $result;
}
/**
* Returns the "priority" attribute value of this <Service>
* element, if the attribute is present. Returns null if not.
*
* @return mixed $result Null or integer, depending on whether
* this Service element has a 'priority' attribute.
*/
function getPriority()
{
$attributes = $this->parser->attributes($this->element);
if (array_key_exists('priority', $attributes)) {
return intval($attributes['priority']);
}
return null;
}
/**
* Used to get XML elements from this object's <Service> element.
*
* This is what you should use to get all custom information out
* of this element. This is used by service filter functions to
* determine whether a service element contains specific tags,
* etc. NOTE: this only considers elements which are direct
* children of the <Service> element for this object.
*
* @param string $name The name of the element to look for
* @return array $list An array of elements with the specified
* name which are direct children of the <Service> element. The
* nodes returned by this function can be passed to $this->parser
* methods (see {@link Auth_Yadis_XMLParser}).
*/
function getElements($name)
{
return $this->parser->evalXPath($name, $this->element);
}
}
/*
* Return the expiration date of this XRD element, or None if no
* expiration was specified.
*
* @param $default The value to use as the expiration if no expiration
* was specified in the XRD.
*/
function Auth_Yadis_getXRDExpiration($xrd_element, $default=null)
{
$expires_element = $xrd_element->$parser->evalXPath('/xrd:Expires');
if ($expires_element === null) {
return $default;
} else {
$expires_string = $expires_element->text;
// Will raise ValueError if the string is not the expected
// format
$t = strptime($expires_string, "%Y-%m-%dT%H:%M:%SZ");
if ($t === false) {
return false;
}
// [int $hour [, int $minute [, int $second [,
// int $month [, int $day [, int $year ]]]]]]
return mktime($t['tm_hour'], $t['tm_min'], $t['tm_sec'],
$t['tm_mon'], $t['tm_day'], $t['tm_year']);
}
}
/**
* This class performs parsing of XRDS documents.
*
* You should not instantiate this class directly; rather, call
* parseXRDS statically:
*
* <pre> $xrds = Auth_Yadis_XRDS::parseXRDS($xml_string);</pre>
*
* If the XRDS can be parsed and is valid, an instance of
* Auth_Yadis_XRDS will be returned. Otherwise, null will be
* returned. This class is used by the Auth_Yadis_Yadis::discover
* method.
*
* @package OpenID
*/
class Auth_Yadis_XRDS {
/**
* Instantiate a Auth_Yadis_XRDS object. Requires an XPath
* instance which has been used to parse a valid XRDS document.
*/
function Auth_Yadis_XRDS($xmlParser, $xrdNodes)
{
$this->parser = $xmlParser;
$this->xrdNode = $xrdNodes[count($xrdNodes) - 1];
$this->allXrdNodes = $xrdNodes;
$this->serviceList = array();
$this->_parse();
}
/**
* Parse an XML string (XRDS document) and return either a
* Auth_Yadis_XRDS object or null, depending on whether the
* XRDS XML is valid.
*
* @param string $xml_string An XRDS XML string.
* @return mixed $xrds An instance of Auth_Yadis_XRDS or null,
* depending on the validity of $xml_string
*/
static function parseXRDS($xml_string, $extra_ns_map = null)
{
$_null = null;
if (!$xml_string) {
return $_null;
}
$parser = Auth_Yadis_getXMLParser();
$ns_map = Auth_Yadis_getNSMap();
if ($extra_ns_map && is_array($extra_ns_map)) {
$ns_map = array_merge($ns_map, $extra_ns_map);
}
if (!($parser && $parser->init($xml_string, $ns_map))) {
return $_null;
}
// Try to get root element.
$root = $parser->evalXPath('/xrds:XRDS[1]');
if (!$root) {
return $_null;
}
if (is_array($root)) {
$root = $root[0];
}
$attrs = $parser->attributes($root);
if (array_key_exists('xmlns:xrd', $attrs) &&
$attrs['xmlns:xrd'] != Auth_Yadis_XMLNS_XRDS) {
return $_null;
} else if (array_key_exists('xmlns', $attrs) &&
preg_match('/xri/', $attrs['xmlns']) &&
$attrs['xmlns'] != Auth_Yadis_XMLNS_XRD_2_0) {
return $_null;
}
// Get the last XRD node.
$xrd_nodes = $parser->evalXPath('/xrds:XRDS[1]/xrd:XRD');
if (!$xrd_nodes) {
return $_null;
}
$xrds = new Auth_Yadis_XRDS($parser, $xrd_nodes);
return $xrds;
}
/**
* @access private
*/
function _addService($priority, $service)
{
$priority = intval($priority);
if (!array_key_exists($priority, $this->serviceList)) {
$this->serviceList[$priority] = array();
}
$this->serviceList[$priority][] = $service;
}
/**
* Creates the service list using nodes from the XRDS XML
* document.
*
* @access private
*/
function _parse()
{
$this->serviceList = array();
$services = $this->parser->evalXPath('xrd:Service', $this->xrdNode);
foreach ($services as $node) {
$s = new Auth_Yadis_Service();
$s->element = $node;
$s->parser = $this->parser;
$priority = $s->getPriority();
if ($priority === null) {
$priority = SERVICES_YADIS_MAX_PRIORITY;
}
$this->_addService($priority, $s);
}
}
/**
* Returns a list of service objects which correspond to <Service>
* elements in the XRDS XML document for this object.
*
* Optionally, an array of filter callbacks may be given to limit
* the list of returned service objects. Furthermore, the default
* mode is to return all service objects which match ANY of the
* specified filters, but $filter_mode may be
* SERVICES_YADIS_MATCH_ALL if you want to be sure that the
* returned services match all the given filters. See {@link
* Auth_Yadis_Yadis} for detailed usage information on filter
* functions.
*
* @param mixed $filters An array of callbacks to filter the
* returned services, or null if all services are to be returned.
* @param integer $filter_mode SERVICES_YADIS_MATCH_ALL or
* SERVICES_YADIS_MATCH_ANY, depending on whether the returned
* services should match ALL or ANY of the specified filters,
* respectively.
* @return mixed $services An array of {@link
* Auth_Yadis_Service} objects if $filter_mode is a valid
* mode; null if $filter_mode is an invalid mode (i.e., not
* SERVICES_YADIS_MATCH_ANY or SERVICES_YADIS_MATCH_ALL).
*/
function services($filters = null,
$filter_mode = SERVICES_YADIS_MATCH_ANY)
{
$pri_keys = array_keys($this->serviceList);
sort($pri_keys, SORT_NUMERIC);
// If no filters are specified, return the entire service
// list, ordered by priority.
if (!$filters ||
(!is_array($filters))) {
$result = array();
foreach ($pri_keys as $pri) {
$result = array_merge($result, $this->serviceList[$pri]);
}
return $result;
}
// If a bad filter mode is specified, return null.
if (!in_array($filter_mode, array(SERVICES_YADIS_MATCH_ANY,
SERVICES_YADIS_MATCH_ALL))) {
return null;
}
// Otherwise, use the callbacks in the filter list to
// determine which services are returned.
$filtered = array();
foreach ($pri_keys as $priority_value) {
$service_obj_list = $this->serviceList[$priority_value];
foreach ($service_obj_list as $service) {
$matches = 0;
foreach ($filters as $filter) {
if (call_user_func_array($filter, array(&$service))) {
$matches++;
if ($filter_mode == SERVICES_YADIS_MATCH_ANY) {
$pri = $service->getPriority();
if ($pri === null) {
$pri = SERVICES_YADIS_MAX_PRIORITY;
}
if (!array_key_exists($pri, $filtered)) {
$filtered[$pri] = array();
}
$filtered[$pri][] = $service;
break;
}
}
}
if (($filter_mode == SERVICES_YADIS_MATCH_ALL) &&
($matches == count($filters))) {
$pri = $service->getPriority();
if ($pri === null) {
$pri = SERVICES_YADIS_MAX_PRIORITY;
}
if (!array_key_exists($pri, $filtered)) {
$filtered[$pri] = array();
}
$filtered[$pri][] = $service;
}
}
}
$pri_keys = array_keys($filtered);
sort($pri_keys, SORT_NUMERIC);
$result = array();
foreach ($pri_keys as $pri) {
$result = array_merge($result, $filtered[$pri]);
}
return $result;
}
}

View File

@ -1,234 +0,0 @@
<?php
/**
* Routines for XRI resolution.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
require_once 'Auth/Yadis/Misc.php';
require_once 'Auth/Yadis/Yadis.php';
require_once 'Auth/OpenID.php';
function Auth_Yadis_getDefaultProxy()
{
return 'http://xri.net/';
}
function Auth_Yadis_getXRIAuthorities()
{
return array('!', '=', '@', '+', '$', '(');
}
function Auth_Yadis_getEscapeRE()
{
$parts = array();
foreach (array_merge(Auth_Yadis_getUCSChars(),
Auth_Yadis_getIPrivateChars()) as $pair) {
list($m, $n) = $pair;
$parts[] = sprintf("%s-%s", chr($m), chr($n));
}
return sprintf('/[%s]/', implode('', $parts));
}
function Auth_Yadis_getXrefRE()
{
return '/\((.*?)\)/';
}
function Auth_Yadis_identifierScheme($identifier)
{
if (Auth_Yadis_startswith($identifier, 'xri://') ||
($identifier &&
in_array($identifier[0], Auth_Yadis_getXRIAuthorities()))) {
return "XRI";
} else {
return "URI";
}
}
function Auth_Yadis_toIRINormal($xri)
{
if (!Auth_Yadis_startswith($xri, 'xri://')) {
$xri = 'xri://' . $xri;
}
return Auth_Yadis_escapeForIRI($xri);
}
function _escape_xref($xref_match)
{
$xref = $xref_match[0];
$xref = str_replace('/', '%2F', $xref);
$xref = str_replace('?', '%3F', $xref);
$xref = str_replace('#', '%23', $xref);
return $xref;
}
function Auth_Yadis_escapeForIRI($xri)
{
$xri = str_replace('%', '%25', $xri);
$xri = preg_replace_callback(Auth_Yadis_getXrefRE(),
'_escape_xref', $xri);
return $xri;
}
function Auth_Yadis_toURINormal($xri)
{
return Auth_Yadis_iriToURI(Auth_Yadis_toIRINormal($xri));
}
function Auth_Yadis_iriToURI($iri)
{
if (1) {
return $iri;
} else {
// According to RFC 3987, section 3.1, "Mapping of IRIs to URIs"
return preg_replace_callback(Auth_Yadis_getEscapeRE(),
'Auth_Yadis_pct_escape_unicode', $iri);
}
}
function Auth_Yadis_XRIAppendArgs($url, $args)
{
// Append some arguments to an HTTP query. Yes, this is just like
// OpenID's appendArgs, but with special seasoning for XRI
// queries.
if (count($args) == 0) {
return $url;
}
// Non-empty array; if it is an array of arrays, use multisort;
// otherwise use sort.
if (array_key_exists(0, $args) &&
is_array($args[0])) {
// Do nothing here.
} else {
$keys = array_keys($args);
sort($keys);
$new_args = array();
foreach ($keys as $key) {
$new_args[] = array($key, $args[$key]);
}
$args = $new_args;
}
// According to XRI Resolution section "QXRI query parameters":
//
// "If the original QXRI had a null query component (only a
// leading question mark), or a query component consisting of
// only question marks, one additional leading question mark MUST
// be added when adding any XRI resolution parameters."
if (strpos(rtrim($url, '?'), '?') !== false) {
$sep = '&';
} else {
$sep = '?';
}
return $url . $sep . Auth_OpenID::httpBuildQuery($args);
}
function Auth_Yadis_providerIsAuthoritative($providerID, $canonicalID)
{
$lastbang = strrpos($canonicalID, '!');
$p = substr($canonicalID, 0, $lastbang);
return $p == $providerID;
}
function Auth_Yadis_rootAuthority($xri)
{
// Return the root authority for an XRI.
$root = null;
if (Auth_Yadis_startswith($xri, 'xri://')) {
$xri = substr($xri, 6);
}
$authority = explode('/', $xri, 2);
$authority = $authority[0];
if ($authority[0] == '(') {
// Cross-reference.
// XXX: This is incorrect if someone nests cross-references so
// there is another close-paren in there. Hopefully nobody
// does that before we have a real xriparse function.
// Hopefully nobody does that *ever*.
$root = substr($authority, 0, strpos($authority, ')') + 1);
} else if (in_array($authority[0], Auth_Yadis_getXRIAuthorities())) {
// Other XRI reference.
$root = $authority[0];
} else {
// IRI reference.
$_segments = explode("!", $authority);
$segments = array();
foreach ($_segments as $s) {
$segments = array_merge($segments, explode("*", $s));
}
$root = $segments[0];
}
return Auth_Yadis_XRI($root);
}
function Auth_Yadis_XRI($xri)
{
if (!Auth_Yadis_startswith($xri, 'xri://')) {
$xri = 'xri://' . $xri;
}
return $xri;
}
function Auth_Yadis_getCanonicalID($iname, $xrds)
{
// Returns false or a canonical ID value.
// Now nodes are in reverse order.
$xrd_list = array_reverse($xrds->allXrdNodes);
$parser = $xrds->parser;
$node = $xrd_list[0];
$canonicalID_nodes = $parser->evalXPath('xrd:CanonicalID', $node);
if (!$canonicalID_nodes) {
return false;
}
$canonicalID = $canonicalID_nodes[0];
$canonicalID = Auth_Yadis_XRI($parser->content($canonicalID));
$childID = $canonicalID;
for ($i = 1; $i < count($xrd_list); $i++) {
$xrd = $xrd_list[$i];
$parent_sought = substr($childID, 0, strrpos($childID, '!'));
$parentCID = $parser->evalXPath('xrd:CanonicalID', $xrd);
if (!$parentCID) {
return false;
}
$parentCID = Auth_Yadis_XRI($parser->content($parentCID[0]));
if (strcasecmp($parent_sought, $parentCID)) {
// raise XRDSFraud.
return false;
}
$childID = $parent_sought;
}
$root = Auth_Yadis_rootAuthority($iname);
if (!Auth_Yadis_providerIsAuthoritative($root, $childID)) {
// raise XRDSFraud.
return false;
}
return $canonicalID;
}

View File

@ -1,72 +0,0 @@
<?php
/**
* Code for using a proxy XRI resolver.
*/
require_once 'Auth/Yadis/XRDS.php';
require_once 'Auth/Yadis/XRI.php';
class Auth_Yadis_ProxyResolver {
function Auth_Yadis_ProxyResolver($fetcher, $proxy_url = null)
{
$this->fetcher = $fetcher;
$this->proxy_url = $proxy_url;
if (!$this->proxy_url) {
$this->proxy_url = Auth_Yadis_getDefaultProxy();
}
}
function queryURL($xri, $service_type = null)
{
// trim off the xri:// prefix
$qxri = substr(Auth_Yadis_toURINormal($xri), 6);
$hxri = $this->proxy_url . $qxri;
$args = array(
'_xrd_r' => 'application/xrds+xml'
);
if ($service_type) {
$args['_xrd_t'] = $service_type;
} else {
// Don't perform service endpoint selection.
$args['_xrd_r'] .= ';sep=false';
}
$query = Auth_Yadis_XRIAppendArgs($hxri, $args);
return $query;
}
function query($xri, $service_types, $filters = array())
{
$services = array();
$canonicalID = null;
foreach ($service_types as $service_type) {
$url = $this->queryURL($xri, $service_type);
$response = $this->fetcher->get($url);
if ($response->status != 200 and $response->status != 206) {
continue;
}
$xrds = Auth_Yadis_XRDS::parseXRDS($response->body);
if (!$xrds) {
continue;
}
$canonicalID = Auth_Yadis_getCanonicalID($xri,
$xrds);
if ($canonicalID === false) {
return null;
}
$some_services = $xrds->services($filters);
$services = array_merge($services, $some_services);
// TODO:
// * If we do get hits for multiple service_types, we're
// almost certainly going to have duplicated service
// entries and broken priority ordering.
}
return array($canonicalID, $services);
}
}

View File

@ -1,382 +0,0 @@
<?php
/**
* The core PHP Yadis implementation.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* Need both fetcher types so we can use the right one based on the
* presence or absence of CURL.
*/
require_once "Auth/Yadis/PlainHTTPFetcher.php";
require_once "Auth/Yadis/ParanoidHTTPFetcher.php";
/**
* Need this for parsing HTML (looking for META tags).
*/
require_once "Auth/Yadis/ParseHTML.php";
/**
* Need this to parse the XRDS document during Yadis discovery.
*/
require_once "Auth/Yadis/XRDS.php";
/**
* XRDS (yadis) content type
*/
define('Auth_Yadis_CONTENT_TYPE', 'application/xrds+xml');
/**
* Yadis header
*/
define('Auth_Yadis_HEADER_NAME', 'X-XRDS-Location');
/**
* Contains the result of performing Yadis discovery on a URI.
*
* @package OpenID
*/
class Auth_Yadis_DiscoveryResult {
// The URI that was passed to the fetcher
var $request_uri = null;
// The result of following redirects from the request_uri
var $normalized_uri = null;
// The URI from which the response text was returned (set to
// None if there was no XRDS document found)
var $xrds_uri = null;
var $xrds = null;
// The content-type returned with the response_text
var $content_type = null;
// The document returned from the xrds_uri
var $response_text = null;
// Did the discovery fail miserably?
var $failed = false;
function Auth_Yadis_DiscoveryResult($request_uri)
{
// Initialize the state of the object
// sets all attributes to None except the request_uri
$this->request_uri = $request_uri;
}
function fail()
{
$this->failed = true;
}
function isFailure()
{
return $this->failed;
}
/**
* Returns the list of service objects as described by the XRDS
* document, if this yadis object represents a successful Yadis
* discovery.
*
* @return array $services An array of {@link Auth_Yadis_Service}
* objects
*/
function services()
{
if ($this->xrds) {
return $this->xrds->services();
}
return null;
}
function usedYadisLocation()
{
// Was the Yadis protocol's indirection used?
return ($this->xrds_uri && $this->normalized_uri != $this->xrds_uri);
}
function isXRDS()
{
// Is the response text supposed to be an XRDS document?
return ($this->usedYadisLocation() ||
$this->content_type == Auth_Yadis_CONTENT_TYPE);
}
}
/**
*
* Perform the Yadis protocol on the input URL and return an iterable
* of resulting endpoint objects.
*
* input_url: The URL on which to perform the Yadis protocol
*
* @return: The normalized identity URL and an iterable of endpoint
* objects generated by the filter function.
*
* xrds_parse_func: a callback which will take (uri, xrds_text) and
* return an array of service endpoint objects or null. Usually
* array('Auth_OpenID_ServiceEndpoint', 'fromXRDS').
*
* discover_func: if not null, a callback which should take (uri) and
* return an Auth_Yadis_Yadis object or null.
*/
function Auth_Yadis_getServiceEndpoints($input_url, $xrds_parse_func,
$discover_func=null, $fetcher=null)
{
if ($discover_func === null) {
$discover_function = array('Auth_Yadis_Yadis', 'discover');
}
$yadis_result = call_user_func_array($discover_func,
array($input_url, &$fetcher));
if ($yadis_result === null) {
return array($input_url, array());
}
$endpoints = call_user_func_array($xrds_parse_func,
array($yadis_result->normalized_uri,
$yadis_result->response_text));
if ($endpoints === null) {
$endpoints = array();
}
return array($yadis_result->normalized_uri, $endpoints);
}
/**
* This is the core of the PHP Yadis library. This is the only class
* a user needs to use to perform Yadis discovery. This class
* performs the discovery AND stores the result of the discovery.
*
* First, require this library into your program source:
*
* <pre> require_once "Auth/Yadis/Yadis.php";</pre>
*
* To perform Yadis discovery, first call the "discover" method
* statically with a URI parameter:
*
* <pre> $http_response = array();
* $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
* $yadis_object = Auth_Yadis_Yadis::discover($uri,
* $http_response, $fetcher);</pre>
*
* If the discovery succeeds, $yadis_object will be an instance of
* {@link Auth_Yadis_Yadis}. If not, it will be null. The XRDS
* document found during discovery should have service descriptions,
* which can be accessed by calling
*
* <pre> $service_list = $yadis_object->services();</pre>
*
* which returns an array of objects which describe each service.
* These objects are instances of Auth_Yadis_Service. Each object
* describes exactly one whole Service element, complete with all of
* its Types and URIs (no expansion is performed). The common use
* case for using the service objects returned by services() is to
* write one or more filter functions and pass those to services():
*
* <pre> $service_list = $yadis_object->services(
* array("filterByURI",
* "filterByExtension"));</pre>
*
* The filter functions (whose names appear in the array passed to
* services()) take the following form:
*
* <pre> function myFilter($service) {
* // Query $service object here. Return true if the service
* // matches your query; false if not.
* }</pre>
*
* This is an example of a filter which uses a regular expression to
* match the content of URI tags (note that the Auth_Yadis_Service
* class provides a getURIs() method which you should use instead of
* this contrived example):
*
* <pre>
* function URIMatcher($service) {
* foreach ($service->getElements('xrd:URI') as $uri) {
* if (preg_match("/some_pattern/",
* $service->parser->content($uri))) {
* return true;
* }
* }
* return false;
* }</pre>
*
* The filter functions you pass will be called for each service
* object to determine which ones match the criteria your filters
* specify. The default behavior is that if a given service object
* matches ANY of the filters specified in the services() call, it
* will be returned. You can specify that a given service object will
* be returned ONLY if it matches ALL specified filters by changing
* the match mode of services():
*
* <pre> $yadis_object->services(array("filter1", "filter2"),
* SERVICES_YADIS_MATCH_ALL);</pre>
*
* See {@link SERVICES_YADIS_MATCH_ALL} and {@link
* SERVICES_YADIS_MATCH_ANY}.
*
* Services described in an XRDS should have a library which you'll
* probably be using. Those libraries are responsible for defining
* filters that can be used with the "services()" call. If you need
* to write your own filter, see the documentation for {@link
* Auth_Yadis_Service}.
*
* @package OpenID
*/
class Auth_Yadis_Yadis {
/**
* Returns an HTTP fetcher object. If the CURL extension is
* present, an instance of {@link Auth_Yadis_ParanoidHTTPFetcher}
* is returned. If not, an instance of
* {@link Auth_Yadis_PlainHTTPFetcher} is returned.
*
* If Auth_Yadis_CURL_OVERRIDE is defined, this method will always
* return a {@link Auth_Yadis_PlainHTTPFetcher}.
*/
static function getHTTPFetcher($timeout = 20)
{
if (Auth_Yadis_Yadis::curlPresent() &&
(!defined('Auth_Yadis_CURL_OVERRIDE'))) {
$fetcher = new Auth_Yadis_ParanoidHTTPFetcher($timeout);
} else {
$fetcher = new Auth_Yadis_PlainHTTPFetcher($timeout);
}
return $fetcher;
}
static function curlPresent()
{
return function_exists('curl_init');
}
/**
* @access private
*/
static function _getHeader($header_list, $names)
{
foreach ($header_list as $name => $value) {
foreach ($names as $n) {
if (strtolower($name) == strtolower($n)) {
return $value;
}
}
}
return null;
}
/**
* @access private
*/
static function _getContentType($content_type_header)
{
if ($content_type_header) {
$parts = explode(";", $content_type_header);
return strtolower($parts[0]);
}
}
/**
* This should be called statically and will build a Yadis
* instance if the discovery process succeeds. This implements
* Yadis discovery as specified in the Yadis specification.
*
* @param string $uri The URI on which to perform Yadis discovery.
*
* @param array $http_response An array reference where the HTTP
* response object will be stored (see {@link
* Auth_Yadis_HTTPResponse}.
*
* @param Auth_Yadis_HTTPFetcher $fetcher An instance of a
* Auth_Yadis_HTTPFetcher subclass.
*
* @param array $extra_ns_map An array which maps namespace names
* to namespace URIs to be used when parsing the Yadis XRDS
* document.
*
* @param integer $timeout An optional fetcher timeout, in seconds.
*
* @return mixed $obj Either null or an instance of
* Auth_Yadis_Yadis, depending on whether the discovery
* succeeded.
*/
static function discover($uri, $fetcher,
$extra_ns_map = null, $timeout = 20)
{
$result = new Auth_Yadis_DiscoveryResult($uri);
$request_uri = $uri;
$headers = array("Accept: " . Auth_Yadis_CONTENT_TYPE .
', text/html; q=0.3, application/xhtml+xml; q=0.5');
if ($fetcher === null) {
$fetcher = Auth_Yadis_Yadis::getHTTPFetcher($timeout);
}
$response = $fetcher->get($uri, $headers);
if (!$response || ($response->status != 200 and
$response->status != 206)) {
$result->fail();
return $result;
}
$result->normalized_uri = $response->final_url;
$result->content_type = Auth_Yadis_Yadis::_getHeader(
$response->headers,
array('content-type'));
if ($result->content_type &&
(Auth_Yadis_Yadis::_getContentType($result->content_type) ==
Auth_Yadis_CONTENT_TYPE)) {
$result->xrds_uri = $result->normalized_uri;
} else {
$yadis_location = Auth_Yadis_Yadis::_getHeader(
$response->headers,
array(Auth_Yadis_HEADER_NAME));
if (!$yadis_location) {
$parser = new Auth_Yadis_ParseHTML();
$yadis_location = $parser->getHTTPEquiv($response->body);
}
if ($yadis_location) {
$result->xrds_uri = $yadis_location;
$response = $fetcher->get($yadis_location);
if ((!$response) || ($response->status != 200 and
$response->status != 206)) {
$result->fail();
return $result;
}
$result->content_type = Auth_Yadis_Yadis::_getHeader(
$response->headers,
array('content-type'));
}
}
$result->response_text = $response->body;
return $result;
}
}

View File

@ -1,65 +0,0 @@
<?php
/**
* The Artifact is part of the SAML 2.0 IdP code, and it builds an artifact object.
* I am using strings, because I find them easier to work with.
* I want to use this, to be consistent with the other saml2_requests
*
* @author Danny Bollaert, UGent AS. <danny.bollaert@ugent.be>
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_ArtifactResolve extends SAML2_Request {
private $artifact;
public function __construct(DOMElement $xml = NULL) {
parent::__construct('ArtifactResolve', $xml);
if(!is_null($xml)){
$results = SAML2_Utils::xpQuery($xml, './saml_protocol:Artifact');
$this->artifact = $results[0]->textContent;
}
}
/**
* Retrieve the Artifact in this response.
*
* @return string artifact.
*/
public function getArtifact() {
return $this->artifact;
}
/**
* Set the artifact that should be included in this response.
*
* @param String The $artifact.
*/
public function setArtifact($artifact) {
assert('is_string($artifact)');
$this->artifact = $artifact;
}
/**
* Convert the response message to an XML element.
*
* @return DOMElement This response.
*/
public function toUnsignedXML() {
$root = parent::toUnsignedXML();
$artifactelement = $this->document->createElementNS(SAML2_Const::NS_SAMLP, 'Artifact', $this->artifact);
$root->appendChild($artifactelement);
return $root;
}
}

View File

@ -1,71 +0,0 @@
<?php
/**
* The SAML2_ArtifactResponse, is the response to the SAML2_ArtifactResolve.
*
* @author Danny Bollaert, UGent AS. <danny.bollaert@ugent.be>
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_ArtifactResponse extends SAML2_StatusResponse {
/**
* The DOMElement with the message the artifact refers
* to, or NULL if we don't refer to any artifact.
*
* @var DOMElement|NULL
*/
private $any;
public function __construct(DOMElement $xml = NULL) {
parent::__construct('ArtifactResponse', $xml);
if(!is_null($xml)){
$status = SAML2_Utils::xpQuery($xml, './saml_protocol:Status');
assert('!empty($status)'); /* Will have failed during StatusResponse parsing. */
$status = $status[0];
for ($any = $status->nextSibling; $any !== NULL; $any = $any->nextSibling) {
if ($any instanceof DOMElement) {
$this->any = $any;
break;
}
/* Ignore comments and text nodes. */
}
}
}
public function setAny(DOMElement $any = NULL) {
$this->any = $any;
}
public function getAny() {
return $this->any;
}
/**
* Convert the response message to an XML element.
*
* @return DOMElement This response.
*/
public function toUnsignedXML() {
$root = parent::toUnsignedXML();
if (isset($this->any)) {
$node = $root->ownerDocument->importNode($this->any, TRUE);
$root->appendChild($node);
}
return $root;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,176 +0,0 @@
<?php
/**
* Class for SAML 2 attribute query messages.
*
* An attribute query asks for a set of attributes. The following
* rules apply:
*
* - If no attributes are present in the query, all attributes should be
* returned.
* - If any attributes are present, only those attributes which are present
* in the query should be returned.
* - If an attribute contains any attribute values, only the attribute values
* which match those in the query should be returned.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_AttributeQuery extends SAML2_SubjectQuery {
/**
* The attributes, as an associative array.
*
* @var array
*/
private $attributes;
/**
* The NameFormat used on all attributes.
*
* If more than one NameFormat is used, this will contain
* the unspecified nameformat.
*
* @var string
*/
private $nameFormat;
/**
* Constructor for SAML 2 attribute query messages.
*
* @param DOMElement|NULL $xml The input message.
*/
public function __construct(DOMElement $xml = NULL) {
parent::__construct('AttributeQuery', $xml);
$this->attributes = array();
$this->nameFormat = SAML2_Const::NAMEFORMAT_UNSPECIFIED;
if ($xml === NULL) {
return;
}
$firstAttribute = TRUE;
$attributes = SAML2_Utils::xpQuery($xml, './saml_assertion:Attribute');
foreach ($attributes as $attribute) {
if (!$attribute->hasAttribute('Name')) {
throw new Exception('Missing name on <saml:Attribute> element.');
}
$name = $attribute->getAttribute('Name');
if ($attribute->hasAttribute('NameFormat')) {
$nameFormat = $attribute->getAttribute('NameFormat');
} else {
$nameFormat = SAML2_Const::NAMEFORMAT_UNSPECIFIED;
}
if ($firstAttribute) {
$this->nameFormat = $nameFormat;
$firstAttribute = FALSE;
} else {
if ($this->nameFormat !== $nameFormat) {
$this->nameFormat = SAML2_Const::NAMEFORMAT_UNSPECIFIED;
}
}
if (!array_key_exists($name, $this->attributes)) {
$this->attributes[$name] = array();
}
$values = SAML2_Utils::xpQuery($attribute, './saml_assertion:AttributeValue');
foreach ($values as $value) {
$this->attributes[$name][] = trim($value->textContent);
}
}
}
/**
* Retrieve all requested attributes.
*
* @return array All requested attributes, as an associative array.
*/
public function getAttributes() {
return $this->attributes;
}
/**
* Set all requested attributes.
*
* @param array $attributes All requested attributes, as an associative array.
*/
public function setAttributes(array $attributes) {
$this->attributes = $attributes;
}
/**
* Retrieve the NameFormat used on all attributes.
*
* If more than one NameFormat is used in the received attributes, this
* returns the unspecified NameFormat.
*
* @return string The NameFormat used on all attributes.
*/
public function getAttributeNameFormat() {
return $this->nameFormat;
}
/**
* Set the NameFormat used on all attributes.
*
* @param string $nameFormat The NameFormat used on all attributes.
*/
public function setAttributeNameFormat($nameFormat) {
assert('is_string($nameFormat)');
$this->nameFormat = $nameFormat;
}
/**
* Convert the attribute query message to an XML element.
*
* @return DOMElement This attribute query.
*/
public function toUnsignedXML() {
$root = parent::toUnsignedXML();
foreach ($this->attributes as $name => $values) {
$attribute = $root->ownerDocument->createElementNS(SAML2_Const::NS_SAML, 'saml:Attribute');
$root->appendChild($attribute);
$attribute->setAttribute('Name', $name);
if ($this->nameFormat !== SAML2_Const::NAMEFORMAT_UNSPECIFIED) {
$attribute->setAttribute('NameFormat', $this->nameFormat);
}
foreach ($values as $value) {
if (is_string($value)) {
$type = 'xs:string';
} elseif (is_int($value)) {
$type = 'xs:integer';
} else {
$type = NULL;
}
$attributeValue = SAML2_Utils::addString($attribute, SAML2_Const::NS_SAML, 'saml:AttributeValue', $value);
if ($type !== NULL) {
$attributeValue->setAttributeNS(SAML2_Const::NS_XSI, 'xsi:type', $type);
}
}
}
return $root;
}
}

View File

@ -1,533 +0,0 @@
<?php
/**
* Class for SAML 2 authentication request messages.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_AuthnRequest extends SAML2_Request {
/**
* The options for what type of name identifier should be returned.
*
* @var array
*/
private $nameIdPolicy;
/**
* Whether the Identity Provider must authenticate the user again.
*
* @var bool
*/
private $forceAuthn;
/**
* Set to TRUE if this request is passive.
*
* @var bool.
*/
private $isPassive;
/**
* The list of providerIDs in this request's scoping element
*
* @var array
*/
private $IDPList = array();
/**
* The ProxyCount in this request's scoping element
*
* @var int
*/
private $ProxyCount = null;
/**
* The RequesterID list in this request's scoping element
*
* @var array
*/
private $RequesterID = array();
/**
* The URL of the asertion consumer service where the response should be delivered.
*
* @var string|NULL
*/
private $assertionConsumerServiceURL;
/**
* What binding should be used when sending the response.
*
* @var string|NULL
*/
private $protocolBinding;
/**
* The index of the AttributeConsumingService.
*
* @var int|NULL
*/
private $attributeConsumingServiceIndex;
/**
* The index of the AssertionConsumerService.
*
* @var int|NULL
*/
private $assertionConsumerServiceIndex;
/**
* What authentication context was requested.
*
* Array with the following elements.
* - AuthnContextClassRef (required)
* - Comparison (optinal)
*
* @var array
*/
private $requestedAuthnContext;
/**
* Request extensions.
*
* @var array
*/
private $extensions;
/**
* Constructor for SAML 2 authentication request messages.
*
* @param DOMElement|NULL $xml The input message.
*/
public function __construct(DOMElement $xml = NULL) {
parent::__construct('AuthnRequest', $xml);
$this->nameIdPolicy = array();
$this->forceAuthn = FALSE;
$this->isPassive = FALSE;
if ($xml === NULL) {
return;
}
$this->forceAuthn = SAML2_Utils::parseBoolean($xml, 'ForceAuthn', FALSE);
$this->isPassive = SAML2_Utils::parseBoolean($xml, 'IsPassive', FALSE);
if ($xml->hasAttribute('AssertionConsumerServiceURL')) {
$this->assertionConsumerServiceURL = $xml->getAttribute('AssertionConsumerServiceURL');
}
if ($xml->hasAttribute('ProtocolBinding')) {
$this->protocolBinding = $xml->getAttribute('ProtocolBinding');
}
if ($xml->hasAttribute('AttributeConsumingServiceIndex')) {
$this->attributeConsumingServiceIndex = (int)$xml->getAttribute('AttributeConsumingServiceIndex');
}
if ($xml->hasAttribute('AssertionConsumerServiceIndex')) {
$this->assertionConsumerServiceIndex = (int)$xml->getAttribute('AssertionConsumerServiceIndex');
}
$nameIdPolicy = SAML2_Utils::xpQuery($xml, './saml_protocol:NameIDPolicy');
if (!empty($nameIdPolicy)) {
$nameIdPolicy = $nameIdPolicy[0];
if ($nameIdPolicy->hasAttribute('Format')) {
$this->nameIdPolicy['Format'] = $nameIdPolicy->getAttribute('Format');
}
if ($nameIdPolicy->hasAttribute('SPNameQualifier')) {
$this->nameIdPolicy['SPNameQualifier'] = $nameIdPolicy->getAttribute('SPNameQualifier');
}
if ($nameIdPolicy->hasAttribute('AllowCreate')) {
$this->nameIdPolicy['AllowCreate'] = SAML2_Utils::parseBoolean($nameIdPolicy, 'AllowCreate', FALSE);
}
}
$requestedAuthnContext = SAML2_Utils::xpQuery($xml, './saml_protocol:RequestedAuthnContext');
if (!empty($requestedAuthnContext)) {
$requestedAuthnContext = $requestedAuthnContext[0];
$rac = array(
'AuthnContextClassRef' => array(),
'Comparison' => 'exact',
);
$accr = SAML2_Utils::xpQuery($requestedAuthnContext, './saml_assertion:AuthnContextClassRef');
foreach ($accr as $i) {
$rac['AuthnContextClassRef'][] = trim($i->textContent);
}
if ($requestedAuthnContext->hasAttribute('Comparison')) {
$rac['Comparison'] = $requestedAuthnContext->getAttribute('Comparison');
}
$this->requestedAuthnContext = $rac;
}
$scoping = SAML2_Utils::xpQuery($xml, './saml_protocol:Scoping');
if (!empty($scoping)) {
$scoping =$scoping[0];
if ($scoping->hasAttribute('ProxyCount')) {
$this->ProxyCount = (int)$scoping->getAttribute('ProxyCount');
}
$idpEntries = SAML2_Utils::xpQuery($scoping, './saml_protocol:IDPList/saml_protocol:IDPEntry');
foreach($idpEntries as $idpEntry) {
if (!$idpEntry->hasAttribute('ProviderID')) {
throw new Exception("Could not get ProviderID from Scoping/IDPEntry element in AuthnRequest object");
}
$this->IDPList[] = $idpEntry->getAttribute('ProviderID');
}
$requesterIDs = SAML2_Utils::xpQuery($scoping, './saml_protocol:RequesterID');
foreach ($requesterIDs as $requesterID) {
$this->RequesterID[] = trim($requesterID->textContent);
}
}
$this->extensions = SAML2_XML_samlp_Extensions::getList($xml);
}
/**
* Retrieve the NameIdPolicy.
*
* @see SAML2_AuthnRequest::setNameIdPolicy()
* @return array The NameIdPolicy.
*/
public function getNameIdPolicy() {
return $this->nameIdPolicy;
}
/**
* Set the NameIDPolicy.
*
* This function accepts an array with the following options:
* - 'Format'
* - 'SPNameQualifier'
* - 'AllowCreate'
*
* @param array $nameIdPolicy The NameIDPolicy.
*/
public function setNameIdPolicy(array $nameIdPolicy) {
$this->nameIdPolicy = $nameIdPolicy;
}
/**
* Retrieve the value of the ForceAuthn attribute.
*
* @return bool The ForceAuthn attribute.
*/
public function getForceAuthn() {
return $this->forceAuthn;
}
/**
* Set the value of the ForceAuthn attribute.
*
* @param bool $forceAuthn The ForceAuthn attribute.
*/
public function setForceAuthn($forceAuthn) {
assert('is_bool($forceAuthn)');
$this->forceAuthn = $forceAuthn;
}
/**
* Retrieve the value of the IsPassive attribute.
*
* @return bool The IsPassive attribute.
*/
public function getIsPassive() {
return $this->isPassive;
}
/**
* Set the value of the IsPassive attribute.
*
* @param bool $isPassive The IsPassive attribute.
*/
public function setIsPassive($isPassive) {
assert('is_bool($isPassive)');
$this->isPassive = $isPassive;
}
/**
* This function sets the scoping for the request
* See Core 3.4.1.2 for the definition of scoping
* Currently we only support an IDPList of idpEntries
* and only the required ProviderID in an IDPEntry
* $providerIDs is an array of Entity Identifiers
*
*/
public function setIDPList($IDPList) {
assert('is_array($IDPList)');
$this->IDPList = $IDPList;
}
/**
* This function retrieves the list of providerIDs from this authentication request.
* Currently we only support a list of ipd ientity id's.
* @return The list of idpidentityids from the request
*/
public function getIDPList() {
return $this->IDPList;
}
public function setProxyCount($ProxyCount) {
assert('is_int($ProxyCount)');
$this->ProxyCount = $ProxyCount;
}
public function getProxyCount() {
return $this->ProxyCount;
}
public function setRequesterID(array $RequesterID) {
$this->RequesterID = $RequesterID;
}
public function getRequesterID() {
return $this->RequesterID;
}
/**
* Retrieve the value of the AssertionConsumerServiceURL attribute.
*
* @return string|NULL The AssertionConsumerServiceURL attribute.
*/
public function getAssertionConsumerServiceURL() {
return $this->assertionConsumerServiceURL;
}
/**
* Set the value of the AssertionConsumerServiceURL attribute.
*
* @param string|NULL $assertionConsumerServiceURL The AssertionConsumerServiceURL attribute.
*/
public function setAssertionConsumerServiceURL($assertionConsumerServiceURL) {
assert('is_string($assertionConsumerServiceURL) || is_null($assertionConsumerServiceURL)');
$this->assertionConsumerServiceURL = $assertionConsumerServiceURL;
}
/**
* Retrieve the value of the ProtocolBinding attribute.
*
* @return string|NULL The ProtocolBinding attribute.
*/
public function getProtocolBinding() {
return $this->protocolBinding;
}
/**
* Set the value of the ProtocolBinding attribute.
*
* @param string $protocolBinding The ProtocolBinding attribute.
*/
public function setProtocolBinding($protocolBinding) {
assert('is_string($protocolBinding) || is_null($protocolBinding)');
$this->protocolBinding = $protocolBinding;
}
/**
* Retrieve the value of the AttributeConsumingServiceIndex attribute.
*
* @return int|NULL The AttributeConsumingServiceIndex attribute.
*/
public function getAttributeConsumingServiceIndex() {
return $this->attributeConsumingServiceIndex;
}
/**
* Set the value of the AttributeConsumingServiceIndex attribute.
*
* @param int|NULL $attributeConsumingServiceIndex The AttributeConsumingServiceIndex attribute.
*/
public function setAttributeConsumingServiceIndex($attributeConsumingServiceIndex) {
assert('is_int($attributeConsumingServiceIndex) || is_null($attributeConsumingServiceIndex)');
$this->attributeConsumingServiceIndex = $attributeConsumingServiceIndex;
}
/**
* Retrieve the value of the AssertionConsumerServiceIndex attribute.
*
* @return int|NULL The AssertionConsumerServiceIndex attribute.
*/
public function getAssertionConsumerServiceIndex() {
return $this->assertionConsumerServiceIndex;
}
/**
* Set the value of the AssertionConsumerServiceIndex attribute.
*
* @param int|NULL $assertionConsumerServiceIndex The AssertionConsumerServiceIndex attribute.
*/
public function setAssertionConsumerServiceIndex($assertionConsumerServiceIndex) {
assert('is_int($assertionConsumerServiceIndex) || is_null($assertionConsumerServiceIndex)');
$this->assertionConsumerServiceIndex = $assertionConsumerServiceIndex;
}
/**
* Retrieve the RequestedAuthnContext.
*
* @return array|NULL The RequestedAuthnContext.
*/
public function getRequestedAuthnContext() {
return $this->requestedAuthnContext;
}
/**
* Set the RequestedAuthnContext.
*
* @param array|NULL $requestedAuthnContext The RequestedAuthnContext.
*/
public function setRequestedAuthnContext($requestedAuthnContext) {
assert('is_array($requestedAuthnContext) || is_null($requestedAuthnContext)');
$this->requestedAuthnContext = $requestedAuthnContext;
}
/**
* Retrieve the Extensions.
*
* @return SAML2_XML_samlp_Extensions.
*/
public function getExtensions() {
return $this->extensions;
}
/**
* Set the Extensions.
*
* @param array|NULL $extensions The Extensions.
*/
public function setExtensions($extensions) {
assert('is_array($extensions) || is_null($extensions)');
$this->extensions = $extensions;
}
/**
* Convert this authentication request to an XML element.
*
* @return DOMElement This authentication request.
*/
public function toUnsignedXML() {
$root = parent::toUnsignedXML();
if ($this->forceAuthn) {
$root->setAttribute('ForceAuthn', 'true');
}
if ($this->isPassive) {
$root->setAttribute('IsPassive', 'true');
}
if ($this->assertionConsumerServiceIndex !== NULL) {
$root->setAttribute('AssertionConsumerServiceIndex', $this->assertionConsumerServiceIndex);
} else {
if ($this->assertionConsumerServiceURL !== NULL) {
$root->setAttribute('AssertionConsumerServiceURL', $this->assertionConsumerServiceURL);
}
if ($this->protocolBinding !== NULL) {
$root->setAttribute('ProtocolBinding', $this->protocolBinding);
}
}
if ($this->attributeConsumingServiceIndex !== NULL) {
$root->setAttribute('AttributeConsumingServiceIndex', $this->attributeConsumingServiceIndex);
}
if (!empty($this->nameIdPolicy)) {
$nameIdPolicy = $this->document->createElementNS(SAML2_Const::NS_SAMLP, 'NameIDPolicy');
if (array_key_exists('Format', $this->nameIdPolicy)) {
$nameIdPolicy->setAttribute('Format', $this->nameIdPolicy['Format']);
}
if (array_key_exists('SPNameQualifier', $this->nameIdPolicy)) {
$nameIdPolicy->setAttribute('SPNameQualifier', $this->nameIdPolicy['SPNameQualifier']);
}
if (array_key_exists('AllowCreate', $this->nameIdPolicy) && $this->nameIdPolicy['AllowCreate']) {
$nameIdPolicy->setAttribute('AllowCreate', 'true');
}
$root->appendChild($nameIdPolicy);
}
$rac = $this->requestedAuthnContext;
if (!empty($rac) && !empty($rac['AuthnContextClassRef'])) {
$e = $this->document->createElementNS(SAML2_Const::NS_SAMLP, 'RequestedAuthnContext');
$root->appendChild($e);
if (isset($rac['Comparison']) && $rac['Comparison'] !== 'exact') {
$e->setAttribute('Comparison', $rac['Comparison']);
}
foreach ($rac['AuthnContextClassRef'] as $accr) {
SAML2_Utils::addString($e, SAML2_Const::NS_SAML, 'AuthnContextClassRef', $accr);
}
}
if (!empty($this->extensions)) {
SAML2_XML_samlp_Extensions::addList($root, $this->extensions);
}
if ($this->ProxyCount !== null || count($this->IDPList) > 0 || count($this->RequesterID) > 0) {
$scoping = $this->document->createElementNS(SAML2_Const::NS_SAMLP, 'Scoping');
$root->appendChild($scoping);
if ($this->ProxyCount !== null) {
$scoping->setAttribute('ProxyCount', $this->ProxyCount);
}
if (count($this->IDPList) > 0) {
$idplist = $this->document->createElementNS(SAML2_Const::NS_SAMLP, 'IDPList');
foreach ($this->IDPList as $provider) {
$idpEntry = $this->document->createElementNS(SAML2_Const::NS_SAMLP, 'IDPEntry');
$idpEntry->setAttribute('ProviderID', $provider);
$idplist->appendChild($idpEntry);
}
$scoping->appendChild($idplist);
}
if (count($this->RequesterID) > 0) {
SAML2_Utils::addStrings($scoping, SAML2_Const::NS_SAMLP, 'RequesterID', FALSE, $this->RequesterID);
}
}
return $root;
}
}
?>

View File

@ -1,147 +0,0 @@
<?php
/**
* Base class for SAML 2 bindings.
*
* @package simpleSAMLphp
* @version $Id$
*/
abstract class SAML2_Binding {
/**
* The destination of messages.
*
* This can be NULL, in which case the destination in the message is used.
*/
protected $destination;
/**
* Retrieve a binding with the given URN.
*
* Will throw an exception if it is unable to locate the binding.
*
* @param string $urn The URN of the binding.
* @return SAML2_Binding The binding.
*/
public static function getBinding($urn) {
assert('is_string($urn)');
switch ($urn) {
case SAML2_Const::BINDING_HTTP_POST:
return new SAML2_HTTPPost();
case SAML2_Const::BINDING_HTTP_REDIRECT:
return new SAML2_HTTPRedirect();
case SAML2_Const::BINDING_HTTP_ARTIFACT:
return new SAML2_HTTPArtifact();
case SAML2_Const::BINDING_HOK_SSO:
return new SAML2_HTTPPost();
default:
throw new Exception('Unsupported binding: ' . var_export($urn, TRUE));
}
}
/**
* Guess the current binding.
*
* This function guesses the current binding and creates an instance
* of SAML2_Binding matching that binding.
*
* An exception will be thrown if it is unable to guess the binding.
*
* @return SAML2_Binding The binding.
*/
public static function getCurrentBinding() {
switch ($_SERVER['REQUEST_METHOD']) {
case 'GET':
if (array_key_exists('SAMLRequest', $_GET) || array_key_exists('SAMLResponse', $_GET)) {
return new SAML2_HTTPRedirect();
} elseif (array_key_exists('SAMLart', $_GET) ){
return new SAML2_HTTPArtifact();
}
break;
case 'POST':
if (isset($_SERVER['CONTENT_TYPE'])) {
$contentType = $_SERVER['CONTENT_TYPE'];
$contentType = explode(';', $contentType);
$contentType = $contentType[0]; /* Remove charset. */
} else {
$contentType = NULL;
}
if (array_key_exists('SAMLRequest', $_POST) || array_key_exists('SAMLResponse', $_POST)) {
return new SAML2_HTTPPost();
} elseif (array_key_exists('SAMLart', $_POST) ){
return new SAML2_HTTPArtifact();
} elseif ($contentType === 'text/xml') {
return new SAML2_SOAP();
}
break;
}
SimpleSAML_Logger::warning('Unable to find the SAML 2 binding used for this request.');
SimpleSAML_Logger::warning('Request method: ' . var_export($_SERVER['REQUEST_METHOD'], TRUE));
if (!empty($_GET)) {
SimpleSAML_Logger::warning("GET parameters: '" . implode("', '", array_map('addslashes', array_keys($_GET))) . "'");
}
if (!empty($_POST)) {
SimpleSAML_Logger::warning("POST parameters: '" . implode("', '", array_map('addslashes', array_keys($_POST))) . "'");
}
if (isset($_SERVER['CONTENT_TYPE'])) {
SimpleSAML_Logger::warning('Content-Type: ' . var_export($_SERVER['CONTENT_TYPE'], TRUE));
}
throw new Exception('Unable to find the current binding.');
}
/**
* Retrieve the destination of a message.
*
* @return string|NULL $destination The destination the message will be delivered to.
*/
public function getDestination() {
return $this->destination;
}
/**
* Override the destination of a message.
*
* Set to NULL to use the destination set in the message.
*
* @param string|NULL $destination The destination the message should be delivered to.
*/
public function setDestination($destination) {
assert('is_string($destination) || is_null($destination)');
$this->destination = $destination;
}
/**
* Send a SAML 2 message.
*
* This function will send a message using the specified binding.
* The message will be delivered to the destination set in the message.
*
* @param SAML2_Message $message The message which should be sent.
*/
abstract public function send(SAML2_Message $message);
/**
* Receive a SAML 2 message.
*
* This function will extract the message from the current request.
* An exception will be thrown if we are unable to process the message.
*
* @return SAML2_Message The received message.
*/
abstract public function receive();
}
?>

View File

@ -1,160 +0,0 @@
<?php
/**
* Various SAML 2 constants.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_Const {
/**
* Password authentication context.
*/
const AC_PASSWORD = 'urn:oasis:names:tc:SAML:2.0:ac:classes:Password';
/**
* Unspecified authentication context.
*/
const AC_UNSPECIFIED = 'urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified';
/**
* The URN for the HTTP-POST binding.
*/
const BINDING_HTTP_POST = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST';
/**
* The URN for the HTTP-Redirect binding.
*/
const BINDING_HTTP_REDIRECT = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect';
/**
* The URN for the HTTP-ARTIFACT binding.
*/
const BINDING_HTTP_ARTIFACT = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact';
/**
* The URN for the SOAP binding.
*/
const BINDING_SOAP = 'urn:oasis:names:tc:SAML:2.0:bindings:SOAP';
/**
* The URN for the Holder-of-Key Web Browser SSO Profile binding
*/
const BINDING_HOK_SSO = 'urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser';
/**
* Bearer subject confirmation method.
*/
const CM_BEARER = 'urn:oasis:names:tc:SAML:2.0:cm:bearer';
/**
* Holder-of-Key subject confirmation method.
*/
const CM_HOK = 'urn:oasis:names:tc:SAML:2.0:cm:holder-of-key';
/**
* The URN for the unspecified attribute NameFormat.
*/
const NAMEFORMAT_UNSPECIFIED = 'urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified';
/**
* Unspecified NameID format.
*/
const NAMEID_UNSPECIFIED = 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified';
/**
* Persistent NameID format.
*/
const NAMEID_PERSISTENT = 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent';
/**
* Transient NameID format.
*/
const NAMEID_TRANSIENT = 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient';
/**
* Encrypted NameID format.
*/
const NAMEID_ENCRYPTED = 'urn:oasis:names:tc:SAML:2.0:nameid-format:encrypted';
/**
* The namespace for the SOAP protocol.
*/
const NS_SOAP = 'http://schemas.xmlsoap.org/soap/envelope/';
/**
* The namespace for the SAML 2 protocol.
*/
const NS_SAMLP = 'urn:oasis:names:tc:SAML:2.0:protocol';
/**
* The namespace for the SAML 2 assertions.
*/
const NS_SAML = 'urn:oasis:names:tc:SAML:2.0:assertion';
/**
* The namespace for the SAML 2 metadata.
*/
const NS_MD = 'urn:oasis:names:tc:SAML:2.0:metadata';
/**
* The namespace fox XML schema.
*/
const NS_XS = 'http://www.w3.org/2001/XMLSchema';
/**
* The namespace for XML schema instance.
*/
const NS_XSI = 'http://www.w3.org/2001/XMLSchema-instance';
/**
* The namespace for the SAML 2 HoK Web Browser SSO Profile.
*/
const NS_HOK = 'urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser';
/**
* Top-level status code indicating successful processing of the request.
*/
const STATUS_SUCCESS = 'urn:oasis:names:tc:SAML:2.0:status:Success';
/**
* Top-level status code indicating that there was a problem with the request.
*/
const STATUS_REQUESTER = 'urn:oasis:names:tc:SAML:2.0:status:Requester';
/**
* Top-level status code indicating that there was a problem generating the response.
*/
const STATUS_RESPONDER = 'urn:oasis:names:tc:SAML:2.0:status:Responder';
/**
* Top-level status code indicating that the request was from an unsupported version of the SAML protocol.
*/
const STATUS_VERSION_MISMATCH = 'urn:oasis:names:tc:SAML:2.0:status:VersionMismatch';
/**
* Second-level status code for NoPassive errors.
*/
const STATUS_NO_PASSIVE = 'urn:oasis:names:tc:SAML:2.0:status:NoPassive';
/**
* Second-level status code for PartialLogout.
*/
const STATUS_PARTIAL_LOGOUT = 'urn:oasis:names:tc:SAML:2.0:status:PartialLogout';
/**
* Second-level status code for ProxyCountExceeded.
*/
const STATUS_PROXY_COUNT_EXCEEDED = 'urn:oasis:names:tc:SAML:2.0:status:ProxyCountExceeded';
}
?>

View File

@ -1,120 +0,0 @@
<?php
/**
* Class handling encrypted assertions.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_EncryptedAssertion {
/**
* The current encrypted assertion.
*
* @var DOMElement
*/
private $encryptedData;
/**
* Constructor for SAML 2 encrypted assertions.
*
* @param DOMElement|NULL $xml The encrypted assertion XML element.
*/
public function __construct(DOMElement $xml = NULL) {
if ($xml === NULL) {
return;
}
$data = SAML2_Utils::xpQuery($xml, './xenc:EncryptedData');
if (count($data) === 0) {
throw new Exception('Missing encrypted data in <saml:EncryptedAssertion>.');
} elseif (count($data) > 1) {
throw new Exception('More than one encrypted data element in <saml:EncryptedAssertion>.');
}
$this->encryptedData = $data[0];
}
/**
* Set the assertion.
*
* @param SAML2_Assertion $assertion The assertion.
* @param XMLSecurityKey $key The key we should use to encrypt the assertion.
*/
public function setAssertion(SAML2_Assertion $assertion, XMLSecurityKey $key) {
$xml = $assertion->toXML();
SimpleSAML_Utilities::debugMessage($xml, 'encrypt');
$enc = new XMLSecEnc();
$enc->setNode($xml);
$enc->type = XMLSecEnc::Element;
switch ($key->type) {
case XMLSecurityKey::TRIPLEDES_CBC:
case XMLSecurityKey::AES128_CBC:
case XMLSecurityKey::AES192_CBC:
case XMLSecurityKey::AES256_CBC:
$symmetricKey = $key;
break;
case XMLSecurityKey::RSA_1_5:
case XMLSecurityKey::RSA_OAEP_MGF1P:
$symmetricKey = new XMLSecurityKey(XMLSecurityKey::AES128_CBC);
$symmetricKey->generateSessionKey();
$enc->encryptKey($key, $symmetricKey);
break;
default:
throw new Exception('Unknown key type for encryption: ' . $key->type);
}
$this->encryptedData = $enc->encryptNode($symmetricKey);
}
/**
* Retrieve the assertion.
*
* @param XMLSecurityKey $key The key we should use to decrypt the assertion.
* @param array $blacklist Blacklisted decryption algorithms.
* @return SAML2_Assertion The decrypted assertion.
*/
public function getAssertion(XMLSecurityKey $inputKey, array $blacklist = array()) {
$assertionXML = SAML2_Utils::decryptElement($this->encryptedData, $inputKey, $blacklist);
SimpleSAML_Utilities::debugMessage($assertionXML, 'decrypt');
return new SAML2_Assertion($assertionXML);
}
/**
* Convert this encrypted assertion to an XML element.
*
* @param DOMNode|NULL $parentElement The DOM node the assertion should be created in.
* @return DOMElement This encrypted assertion.
*/
public function toXML(DOMNode $parentElement = NULL) {
if ($parentElement === NULL) {
$document = new DOMDocument();
$parentElement = $document;
} else {
$document = $parentElement->ownerDocument;
}
$root = $document->createElementNS(SAML2_Const::NS_SAML, 'saml:' . 'EncryptedAssertion');
$parentElement->appendChild($root);
$root->appendChild($document->importNode($this->encryptedData, TRUE));
return $root;
}
}

View File

@ -1,155 +0,0 @@
<?php
/**
* Class which implements the HTTP-Redirect binding.
*
* @author Danny Bollaert, UGent AS. <danny.bollaert@ugent.be>
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_HTTPArtifact extends SAML2_Binding {
private $spMetadata;
/**
* Create the redirect URL for a message.
*
* @param SAML2_Message $message The message.
* @return string The URL the user should be redirected to in order to send a message.
*/
public function getRedirectURL(SAML2_Message $message) {
$store = SimpleSAML_Store::getInstance();
if ($store === FALSE) {
throw new Exception('Unable to send artifact without a datastore configured.');
}
$generatedId = pack('H*', ((string) SimpleSAML_Utilities::stringToHex(SimpleSAML_Utilities::generateRandomBytes(20))));
$artifact = base64_encode("\x00\x04\x00\x00" . sha1($message->getIssuer(), TRUE) . $generatedId) ;
$artifactData = $message->toUnsignedXML();
$artifactDataString = $artifactData->ownerDocument->saveXML($artifactData);
$store->set('artifact', $artifact, $artifactDataString, time() + 15*60);
$params = array(
'SAMLart' => $artifact,
);
$relayState = $message->getRelayState();
if ($relayState !== NULL) {
$params['RelayState'] = $relayState;
}
return SimpleSAML_Utilities::addURLparameter($message->getDestination(), $params);
}
/**
* Send a SAML 2 message using the HTTP-Redirect binding.
*
* Note: This function never returns.
*
* @param SAML2_Message $message The message we should send.
*/
public function send(SAML2_Message $message) {
$destination = $this->getRedirectURL($message);
SimpleSAML_Utilities::redirect($destination);
}
/**
* Receive a SAML 2 message sent using the HTTP-Artifact binding.
*
* Throws an exception if it is unable receive the message.
*
* @return SAML2_Message The received message.
*/
public function receive() {
if (array_key_exists('SAMLart', $_REQUEST)) {
$artifact = base64_decode($_REQUEST['SAMLart']);
$endpointIndex = bin2hex(substr($artifact,2,2));
$sourceId = bin2hex(substr($artifact,4,20));
}else{
throw new Exception('Missing SAMLArt parameter.');
}
$metadataHandler = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
$idpmetadata = $metadataHandler->getMetaDataConfigForSha1($sourceId, 'saml20-idp-remote');
if ($idpmetadata === NULL) {
throw new Exception('No metadata found for remote provider with SHA1 ID: ' . var_export($sourceId, TRUE));
}
$endpoint = NULL;
foreach ($idpmetadata->getEndpoints('ArtifactResolutionService') as $ep) {
if ($ep['index'] === hexdec($endpointIndex)) {
$endpoint = $ep;
break;
}
}
if ($endpoint === NULL) {
throw new Exception('No ArtifactResolutionService with the correct index.');
}
SimpleSAML_Logger::debug("ArtifactResolutionService endpoint being used is := " . $endpoint['Location']);
//Construct the ArtifactResolve Request
$ar = new SAML2_ArtifactResolve();
/* Set the request attributes */
$ar->setIssuer($this->spMetadata->getString('entityid'));
$ar->setArtifact($_REQUEST['SAMLart']);
$ar->setDestination($endpoint['Location']);
/* Sign the request */
sspmod_saml_Message::addSign($this->spMetadata, $idpmetadata, $ar); // Shoaib - moved from the SOAPClient.
$soap = new SAML2_SOAPClient();
// Send message through SoapClient
$artifactResponse = $soap->send($ar, $this->spMetadata);
if (!$artifactResponse->isSuccess()) {
throw new Exception('Received error from ArtifactResolutionService.');
}
$xml = $artifactResponse->getAny();
if ($xml === NULL) {
/* Empty ArtifactResponse - possibly because of Artifact replay? */
return NULL;
}
$samlresponse = SAML2_Message::fromXML($xml);
$samlresponse->addValidator(array(get_class($this), 'validateSignature'), $artifactResponse);
if (isset($_REQUEST['RelayState'])) {
$samlresponse->setRelayState($_REQUEST['RelayState']);
}
return $samlresponse;
}
public function setSPMetadata($sp){
$this->spMetadata = $sp;
}
/**
* A validator which returns TRUE if the ArtifactResponse was signed with the given key
*
* @return TRUE
*/
public static function validateSignature(SAML2_ArtifactResponse $message, XMLSecurityKey $key) {
return $message->validate($key);
}
}

View File

@ -1,87 +0,0 @@
<?php
/**
* Class which implements the HTTP-POST binding.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_HTTPPost extends SAML2_Binding {
/**
* Send a SAML 2 message using the HTTP-POST binding.
*
* Note: This function never returns.
*
* @param SAML2_Message $message The message we should send.
*/
public function send(SAML2_Message $message) {
if ($this->destination === NULL) {
$destination = $message->getDestination();
} else {
$destination = $this->destination;
}
$relayState = $message->getRelayState();
$msgStr = $message->toSignedXML();
$msgStr = $msgStr->ownerDocument->saveXML($msgStr);
SimpleSAML_Utilities::debugMessage($msgStr, 'out');
$msgStr = base64_encode($msgStr);
if ($message instanceof SAML2_Request) {
$msgType = 'SAMLRequest';
} else {
$msgType = 'SAMLResponse';
}
$post = array();
$post[$msgType] = $msgStr;
if ($relayState !== NULL) {
$post['RelayState'] = $relayState;
}
SimpleSAML_Utilities::postRedirect($destination, $post);
}
/**
* Receive a SAML 2 message sent using the HTTP-POST binding.
*
* Throws an exception if it is unable receive the message.
*
* @return SAML2_Message The received message.
*/
public function receive() {
if (array_key_exists('SAMLRequest', $_POST)) {
$msg = $_POST['SAMLRequest'];
} elseif (array_key_exists('SAMLResponse', $_POST)) {
$msg = $_POST['SAMLResponse'];
} else {
throw new Exception('Missing SAMLRequest or SAMLResponse parameter.');
}
$msg = base64_decode($msg);
SimpleSAML_Utilities::debugMessage($msg, 'in');
$document = new DOMDocument();
$document->loadXML($msg);
$xml = $document->firstChild;
$msg = SAML2_Message::fromXML($xml);
if (array_key_exists('RelayState', $_POST)) {
$msg->setRelayState($_POST['RelayState']);
}
return $msg;
}
}
?>

View File

@ -1,240 +0,0 @@
<?php
/**
* Class which implements the HTTP-Redirect binding.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_HTTPRedirect extends SAML2_Binding {
const DEFLATE = 'urn:oasis:names:tc:SAML:2.0:bindings:URL-Encoding:DEFLATE';
/**
* Create the redirect URL for a message.
*
* @param SAML2_Message $message The message.
* @return string The URL the user should be redirected to in order to send a message.
*/
public function getRedirectURL(SAML2_Message $message) {
if ($this->destination === NULL) {
$destination = $message->getDestination();
} else {
$destination = $this->destination;
}
$relayState = $message->getRelayState();
$key = $message->getSignatureKey();
$msgStr = $message->toUnsignedXML();
$msgStr = $msgStr->ownerDocument->saveXML($msgStr);
SimpleSAML_Utilities::debugMessage($msgStr, 'out');
$msgStr = gzdeflate($msgStr);
$msgStr = base64_encode($msgStr);
/* Build the query string. */
if ($message instanceof SAML2_Request) {
$msg = 'SAMLRequest=';
} else {
$msg = 'SAMLResponse=';
}
$msg .= urlencode($msgStr);
if ($relayState !== NULL) {
$msg .= '&RelayState=' . urlencode($relayState);
}
if ($key !== NULL) {
/* Add the signature. */
$msg .= '&SigAlg=' . urlencode($key->type);
$signature = $key->signData($msg);
$msg .= '&Signature=' . urlencode(base64_encode($signature));
}
if (strpos($destination, '?') === FALSE) {
$destination .= '?' . $msg;
} else {
$destination .= '&' . $msg;
}
return $destination;
}
/**
* Send a SAML 2 message using the HTTP-Redirect binding.
*
* Note: This function never returns.
*
* @param SAML2_Message $message The message we should send.
*/
public function send(SAML2_Message $message) {
$destination = $this->getRedirectURL($message);
SimpleSAML_Logger::debug('Redirect to ' . strlen($destination) . ' byte URL: ' . $destination);
SimpleSAML_Utilities::redirect($destination);
}
/**
* Receive a SAML 2 message sent using the HTTP-Redirect binding.
*
* Throws an exception if it is unable receive the message.
*
* @return SAML2_Message The received message.
*/
public function receive() {
$data = self::parseQuery();
if (array_key_exists('SAMLRequest', $data)) {
$msg = $data['SAMLRequest'];
} elseif (array_key_exists('SAMLResponse', $data)) {
$msg = $data['SAMLResponse'];
} else {
throw new Exception('Missing SAMLRequest or SAMLResponse parameter.');
}
if (array_key_exists('SAMLEncoding', $data)) {
$encoding = $data['SAMLEncoding'];
} else {
$encoding = self::DEFLATE;
}
$msg = base64_decode($msg);
switch ($encoding) {
case self::DEFLATE:
$msg = gzinflate($msg);
break;
default:
throw new Exception('Unknown SAMLEncoding: ' . var_export($encoding, TRUE));
}
SimpleSAML_Utilities::debugMessage($msg, 'in');
$document = new DOMDocument();
$document->loadXML($msg);
$xml = $document->firstChild;
$msg = SAML2_Message::fromXML($xml);
if (array_key_exists('Signature', $data)) {
/* Save the signature validation data until we need it. */
$signatureValidationData = array(
'Signature' => $data['Signature'],
'Query' => $data['SignedQuery'],
);
}
if (array_key_exists('RelayState', $data)) {
$msg->setRelayState($data['RelayState']);
}
if (array_key_exists('Signature', $data)) {
if (!array_key_exists('SigAlg', $data)) {
throw new Exception('Missing signature algorithm.');
}
$signData = array(
'Signature' => $data['Signature'],
'SigAlg' => $data['SigAlg'],
'Query' => $data['SignedQuery'],
);
$msg->addValidator(array(get_class($this), 'validateSignature'), $signData);
}
return $msg;
}
/**
* Helper function to parse query data.
*
* This function returns the query string split into key=>value pairs.
* It also adds a new parameter, SignedQuery, which contains the data that is
* signed.
*
* @return string The query data that is signed.
*/
private static function parseQuery() {
/*
* Parse the query string. We need to do this ourself, so that we get access
* to the raw (urlencoded) values. This is required because different software
* can urlencode to different values.
*/
$data = array();
$relayState = '';
$sigAlg = '';
foreach (explode('&', $_SERVER['QUERY_STRING']) as $e) {
$tmp = explode('=', $e, 2);
$name = $tmp[0];
if (count($tmp) === 2) {
$value = $tmp[1];
} else {
/* No value for this paramter. */
$value = '';
}
$name = urldecode($name);
$data[$name] = urldecode($value);
switch ($name) {
case 'SAMLRequest':
case 'SAMLResponse':
$sigQuery = $name . '=' . $value;
break;
case 'RelayState':
$relayState = '&RelayState=' . $value;
break;
case 'SigAlg':
$sigAlg = '&SigAlg=' . $value;
break;
}
}
$data['SignedQuery'] = $sigQuery . $relayState . $sigAlg;
return $data;
}
/**
* Validate the signature on a HTTP-Redirect message.
*
* Throws an exception if we are unable to validate the signature.
*
* @param array $data The data we need to validate the query string.
* @param XMLSecurityKey $key The key we should validate the query against.
*/
public static function validateSignature(array $data, XMLSecurityKey $key) {
assert('array_key_exists("Query", $data)');
assert('array_key_exists("SigAlg", $data)');
assert('array_key_exists("Signature", $data)');
$query = $data['Query'];
$sigAlg = $data['SigAlg'];
$signature = $data['Signature'];
$signature = base64_decode($signature);
if ($key->type !== XMLSecurityKey::RSA_SHA1) {
throw new Exception('Invalid key type for validating signature on query string.');
}
if ($key->type !== $sigAlg) {
$key = SAML2_Utils::castKey($key, $sigAlg);
}
if (!$key->verifySignature($query,$signature)) {
throw new Exception('Unable to validate signature on query string.');
}
}
}
?>

View File

@ -1,282 +0,0 @@
<?php
/**
* Class for SAML 2 logout request messages.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_LogoutRequest extends SAML2_Request {
/**
* The expiration time of this request.
*
* @var int|NULL
*/
private $notOnOrAfter;
/**
* The encrypted NameID in the request.
*
* If this is not NULL, the NameID needs decryption before it can be accessed.
*
* @var DOMElement|NULL
*/
private $encryptedNameId;
/**
* The name identifier of the session that should be terminated.
*
* @var array
*/
private $nameId;
/**
* The SessionIndexes of the sessions that should be terminated.
*
* @var array
*/
private $sessionIndexes;
/**
* Constructor for SAML 2 logout request messages.
*
* @param DOMElement|NULL $xml The input message.
*/
public function __construct(DOMElement $xml = NULL) {
parent::__construct('LogoutRequest', $xml);
$this->sessionIndexes = array();
if ($xml === NULL) {
return;
}
if ($xml->hasAttribute('NotOnOrAfter')) {
$this->notOnOrAfter = SimpleSAML_Utilities::parseSAML2Time($xml->getAttribute('NotOnOrAfter'));
}
$nameId = SAML2_Utils::xpQuery($xml, './saml_assertion:NameID | ./saml_assertion:EncryptedID/xenc:EncryptedData');
if (empty($nameId)) {
throw new Exception('Missing <saml:NameID> or <saml:EncryptedID> in <samlp:LogoutRequest>.');
} elseif (count($nameId) > 1) {
throw new Exception('More than one <saml:NameID> or <saml:EncryptedD> in <samlp:LogoutRequest>.');
}
$nameId = $nameId[0];
if ($nameId->localName === 'EncryptedData') {
/* The NameID element is encrypted. */
$this->encryptedNameId = $nameId;
} else {
$this->nameId = SAML2_Utils::parseNameId($nameId);
}
$sessionIndexes = SAML2_Utils::xpQuery($xml, './saml_protocol:SessionIndex');
foreach ($sessionIndexes as $sessionIndex) {
$this->sessionIndexes[] = trim($sessionIndex->textContent);
}
}
/**
* Retrieve the expiration time of this request.
*
* @return int|NULL The expiration time of this request.
*/
public function getNotOnOrAfter() {
return $this->notOnOrAfter;
}
/**
* Set the expiration time of this request.
*
* @param int|NULL $notOnOrAfter The expiration time of this request.
*/
public function setNotOnOrAfter($notOnOrAfter) {
assert('is_int($notOnOrAfter) || is_null($notOnOrAfter)');
$this->notOnOrAfter = $notOnOrAfter;
}
/**
* Check whether the NameId is encrypted.
*
* @return TRUE if the NameId is encrypted, FALSE if not.
*/
public function isNameIdEncrypted() {
if ($this->encryptedNameId !== NULL) {
return TRUE;
}
return FALSE;
}
/**
* Encrypt the NameID in the LogoutRequest.
*
* @param XMLSecurityKey $key The encryption key.
*/
public function encryptNameId(XMLSecurityKey $key) {
/* First create a XML representation of the NameID. */
$doc = new DOMDocument();
$root = $doc->createElement('root');
$doc->appendChild($root);
SAML2_Utils::addNameId($root, $this->nameId);
$nameId = $root->firstChild;
SimpleSAML_Utilities::debugMessage($nameId, 'encrypt');
/* Encrypt the NameID. */
$enc = new XMLSecEnc();
$enc->setNode($nameId);
$enc->type = XMLSecEnc::Element;
$symmetricKey = new XMLSecurityKey(XMLSecurityKey::AES128_CBC);
$symmetricKey->generateSessionKey();
$enc->encryptKey($key, $symmetricKey);
$this->encryptedNameId = $enc->encryptNode($symmetricKey);
$this->nameId = NULL;
}
/**
* Decrypt the NameID in the LogoutRequest.
*
* @param XMLSecurityKey $key The decryption key.
* @param array $blacklist Blacklisted decryption algorithms.
*/
public function decryptNameId(XMLSecurityKey $key, array $blacklist = array()) {
if ($this->encryptedNameId === NULL) {
/* No NameID to decrypt. */
return;
}
$nameId = SAML2_Utils::decryptElement($this->encryptedNameId, $key, $blacklist);
SimpleSAML_Utilities::debugMessage($nameId, 'decrypt');
$this->nameId = SAML2_Utils::parseNameId($nameId);
$this->encryptedNameId = NULL;
}
/**
* Retrieve the name identifier of the session that should be terminated.
*
* @return array The name identifier of the session that should be terminated.
*/
public function getNameId() {
if ($this->encryptedNameId !== NULL) {
throw new Exception('Attempted to retrieve encrypted NameID without decrypting it first.');
}
return $this->nameId;
}
/**
* Set the name identifier of the session that should be terminated.
*
* The name identifier must be in the format accepted by SAML2_message::buildNameId().
*
* @see SAML2_message::buildNameId()
* @param array $nameId The name identifier of the session that should be terminated.
*/
public function setNameId($nameId) {
assert('is_array($nameId)');
$this->nameId = $nameId;
}
/**
* Retrieve the SessionIndexes of the sessions that should be terminated.
*
* @return array The SessionIndexes, or an empty array if all sessions should be terminated.
*/
public function getSessionIndexes() {
return $this->sessionIndexes;
}
/**
* Set the SessionIndexes of the sessions that should be terminated.
*
* @param array $sessionIndexes The SessionIndexes, or an empty array if all sessions should be terminated.
*/
public function setSessionIndexes(array $sessionIndexes) {
$this->sessionIndexes = $sessionIndexes;
}
/**
* Retrieve the sesion index of the session that should be terminated.
*
* @return string|NULL The sesion index of the session that should be terminated.
*/
public function getSessionIndex() {
if (empty($this->sessionIndexes)) {
return NULL;
}
return $this->sessionIndexes[0];
}
/**
* Set the sesion index of the session that should be terminated.
*
* @param string|NULL $sessionIndex The sesion index of the session that should be terminated.
*/
public function setSessionIndex($sessionIndex) {
assert('is_string($sessionIndex) || is_null($sessionIndex)');
if (is_null($sessionIndex)) {
$this->sessionIndexes = array();
} else {
$this->sessionIndexes = array($sessionIndex);
}
}
/**
* Convert this logout request message to an XML element.
*
* @return DOMElement This logout request.
*/
public function toUnsignedXML() {
$root = parent::toUnsignedXML();
if ($this->notOnOrAfter !== NULL) {
$root->setAttribute('NotOnOrAfter', gmdate('Y-m-d\TH:i:s\Z', $this->notOnOrAfter));
}
if ($this->encryptedNameId === NULL) {
SAML2_Utils::addNameId($root, $this->nameId);
} else {
$eid = $root->ownerDocument->createElementNS(SAML2_Const::NS_SAML, 'saml:' . 'EncryptedID');
$root->appendChild($eid);
$eid->appendChild($root->ownerDocument->importNode($this->encryptedNameId, TRUE));
}
foreach ($this->sessionIndexes as $sessionIndex) {
SAML2_Utils::addString($root, SAML2_Const::NS_SAMLP, 'SessionIndex', $sessionIndex);
}
return $root;
}
}

View File

@ -1,25 +0,0 @@
<?php
/**
* Class for SAML 2 LogoutResponse messages.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_LogoutResponse extends SAML2_StatusResponse {
/**
* Constructor for SAML 2 response messages.
*
* @param string $tagName The tag name of the root element.
* @param DOMElement|NULL $xml The input message.
*/
public function __construct(DOMElement $xml = NULL) {
parent::__construct('LogoutResponse', $xml);
/* No new fields added by LogoutResponse. */
}
}
?>

View File

@ -1,484 +0,0 @@
<?php
/**
* Base class for all SAML 2 messages.
*
* Implements what is common between the samlp:RequestAbstractType and
* samlp:StatusResponseType element types.
*
* @package simpleSAMLphp
* @version $Id$
*/
abstract class SAML2_Message implements SAML2_SignedElement {
/**
* The name of the root element of the DOM tree for the message.
*
* Used when creating a DOM tree from the message.
*
* @var string
*/
private $tagName;
/**
* The identifier of this message.
*
* @var string
*/
private $id;
/**
* The issue timestamp of this message, as an UNIX timestamp.
*
* @var int
*/
private $issueInstant;
/**
* The destination URL of this message if it is known.
*
* @var string|NULL
*/
private $destination;
/**
* The entity id of the issuer of this message, or NULL if unknown.
*
* @var string|NULL
*/
private $issuer;
/**
* The RelayState associated with this message.
*
* @var string|NULL
*/
private $relayState;
/**
* The DOMDocument we are currently building.
*
* This variable is used while generating XML from this message. It holds the
* DOMDocument of the XML we are generating.
*
* @var DOMDocument
*/
protected $document;
/**
* The private key we should use to sign the message.
*
* The private key can be NULL, in which case the message is sent unsigned.
*
* @var XMLSecurityKey|NULL
*/
private $signatureKey;
/**
* List of certificates that should be included in the message.
*
* @var array
*/
private $certificates;
/**
* Available methods for validating this message.
*
* @var array
*/
private $validators;
/**
* Initialize a message.
*
* This constructor takes an optional parameter with a DOMElement. If this
* parameter is given, the message will be initialized with data from that
* XML element.
*
* If no XML element is given, the message is initialized with suitable
* default values.
*
* @param string $tagName The tag name of the root element.
* @param DOMElement|NULL $xml The input message.
*/
protected function __construct($tagName, DOMElement $xml = NULL) {
assert('is_string($tagName)');
$this->tagName = $tagName;
$this->id = SimpleSAML_Utilities::generateID();
$this->issueInstant = time();
$this->certificates = array();
$this->validators = array();
if ($xml === NULL) {
return;
}
if (!$xml->hasAttribute('ID')) {
throw new Exception('Missing ID attribute on SAML message.');
}
$this->id = $xml->getAttribute('ID');
if ($xml->getAttribute('Version') !== '2.0') {
/* Currently a very strict check. */
throw new Exception('Unsupported version: ' . $xml->getAttribute('Version'));
}
$this->issueInstant = SimpleSAML_Utilities::parseSAML2Time($xml->getAttribute('IssueInstant'));
if ($xml->hasAttribute('Destination')) {
$this->destination = $xml->getAttribute('Destination');
}
$issuer = SAML2_Utils::xpQuery($xml, './saml_assertion:Issuer');
if (!empty($issuer)) {
$this->issuer = trim($issuer[0]->textContent);
}
/* Validate the signature element of the message. */
try {
$sig = SAML2_Utils::validateElement($xml);
if ($sig !== FALSE) {
$this->certificates = $sig['Certificates'];
$this->validators[] = array(
'Function' => array('SAML2_Utils', 'validateSignature'),
'Data' => $sig,
);
}
} catch (Exception $e) {
/* Ignore signature validation errors. */
}
}
/**
* Add a method for validating this message.
*
* This function is used by the HTTP-Redirect binding, to make it possible to
* check the signature against the one included in the query string.
*
* @param callback $function The function which should be called.
* @param mixed $data The data that should be included as the first parameter to the function.
*/
public function addValidator($function, $data) {
assert('is_callable($function)');
$this->validators[] = array(
'Function' => $function,
'Data' => $data,
);
}
/**
* Validate this message against a public key.
*
* TRUE is returned on success, FALSE is returned if we don't have any
* signature we can validate. An exception is thrown if the signature
* validation fails.
*
* @param XMLSecurityKey $key The key we should check against.
* @return boolean TRUE on success, FALSE when we don't have a signature.
*/
public function validate(XMLSecurityKey $key) {
if (count($this->validators) === 0) {
return FALSE;
}
$exceptions = array();
foreach ($this->validators as $validator) {
$function = $validator['Function'];
$data = $validator['Data'];
try {
call_user_func($function, $data, $key);
/* We were able to validate the message with this validator. */
return TRUE;
} catch (Exception $e) {
$exceptions[] = $e;
}
}
/* No validators were able to validate the message. */
throw $exceptions[0];
}
/**
* Retrieve the identifier of this message.
*
* @return string The identifier of this message.
*/
public function getId() {
return $this->id;
}
/**
* Set the identifier of this message.
*
* @param string $id The new identifier of this message.
*/
public function setId($id) {
assert('is_string($id)');
$this->id = $id;
}
/**
* Retrieve the issue timestamp of this message.
*
* @return int The issue timestamp of this message, as an UNIX timestamp.
*/
public function getIssueInstant() {
return $this->issueInstant;
}
/**
* Set the issue timestamp of this message.
*
* @param int $issueInstant The new issue timestamp of this message, as an UNIX timestamp.
*/
public function setIssueInstant($issueInstant) {
assert('is_int($issueInstant)');
$this->issueInstant = $issueInstant;
}
/**
* Retrieve the destination of this message.
*
* @return string|NULL The destination of this message, or NULL if no destination is given.
*/
public function getDestination() {
return $this->destination;
}
/**
* Set the destination of this message.
*
* @param string|NULL $destination The new destination of this message.
*/
public function setDestination($destination) {
assert('is_string($destination) || is_null($destination)');
$this->destination = $destination;
}
/**
* Retrieve the issuer if this message.
*
* @return string|NULL The issuer of this message, or NULL if no issuer is given.
*/
public function getIssuer() {
return $this->issuer;
}
/**
* Set the issuer of this message.
*
* @param string|NULL $issuer The new issuer of this message.
*/
public function setIssuer($issuer) {
assert('is_string($issuer) || is_null($issuer)');
$this->issuer = $issuer;
}
/**
* Retrieve the RelayState associated with this message.
*
* @return string|NULL The RelayState, or NULL if no RelayState is given.
*/
public function getRelayState() {
return $this->relayState;
}
/**
* Set the RelayState associated with this message.
*
* @param string|NULL $relayState The new RelayState.
*/
public function setRelayState($relayState) {
assert('is_string($relayState) || is_null($relayState)');
$this->relayState = $relayState;
}
/**
* Convert this message to an unsigned XML document.
*
* This method does not sign the resulting XML document.
*
* @return DOMElement The root element of the DOM tree.
*/
public function toUnsignedXML() {
$this->document = new DOMDocument();
$root = $this->document->createElementNS(SAML2_Const::NS_SAMLP, 'samlp:' . $this->tagName);
$this->document->appendChild($root);
/* Ugly hack to add another namespace declaration to the root element. */
$root->setAttributeNS(SAML2_Const::NS_SAML, 'saml:tmp', 'tmp');
$root->removeAttributeNS(SAML2_Const::NS_SAML, 'tmp');
$root->setAttribute('ID', $this->id);
$root->setAttribute('Version', '2.0');
$root->setAttribute('IssueInstant', gmdate('Y-m-d\TH:i:s\Z', $this->issueInstant));
if ($this->destination !== NULL) {
$root->setAttribute('Destination', $this->destination);
}
if ($this->issuer !== NULL) {
SAML2_Utils::addString($root, SAML2_Const::NS_SAML, 'saml:Issuer', $this->issuer);
}
return $root;
}
/**
* Convert this message to a signed XML document.
*
* This method sign the resulting XML document if the private key for
* the signature is set.
*
* @return DOMElement The root element of the DOM tree.
*/
public function toSignedXML() {
$root = $this->toUnsignedXML();
if ($this->signatureKey === NULL) {
/* We don't have a key to sign it with. */
return $root;
}
/* Find the position we should insert the signature node at. */
if ($this->issuer !== NULL) {
/*
* We have an issuer node. The signature node should come
* after the issuer node.
*/
$issuerNode = $root->firstChild;
$insertBefore = $issuerNode->nextSibling;
} else {
/* No issuer node - the signature element should be the first element. */
$insertBefore = $root->firstChild;
}
SAML2_Utils::insertSignature($this->signatureKey, $this->certificates, $root, $insertBefore);
return $root;
}
/**
* Retrieve the private key we should use to sign the message.
*
* @return XMLSecurityKey|NULL The key, or NULL if no key is specified.
*/
public function getSignatureKey() {
return $this->signatureKey;
}
/**
* Set the private key we should use to sign the message.
*
* If the key is NULL, the message will be sent unsigned.
*
* @param XMLSecurityKey|NULL $key
*/
public function setSignatureKey(XMLsecurityKey $signatureKey = NULL) {
$this->signatureKey = $signatureKey;
}
/**
* Set the certificates that should be included in the message.
*
* The certificates should be strings with the PEM encoded data.
*
* @param array $certificates An array of certificates.
*/
public function setCertificates(array $certificates) {
$this->certificates = $certificates;
}
/**
* Retrieve the certificates that are included in the message.
*
* @return array An array of certificates.
*/
public function getCertificates() {
return $this->certificates;
}
/**
* Convert an XML element into a message.
*
* @param DOMElement $xml The root XML element.
* @return SAML2_Message The message.
*/
public static function fromXML(DOMElement $xml) {
if ($xml->namespaceURI !== SAML2_Const::NS_SAMLP) {
throw new Exception('Unknown namespace of SAML message: ' . var_export($xml->namespaceURI, TRUE));
}
switch ($xml->localName) {
case 'AttributeQuery':
return new SAML2_AttributeQuery($xml);
case 'AuthnRequest':
return new SAML2_AuthnRequest($xml);
case 'LogoutResponse':
return new SAML2_LogoutResponse($xml);
case 'LogoutRequest':
return new SAML2_LogoutRequest($xml);
case 'Response':
return new SAML2_Response($xml);
case 'ArtifactResponse':
return new SAML2_ArtifactResponse($xml);
case 'ArtifactResolve':
return new SAML2_ArtifactResolve($xml);
default:
throw new Exception('Unknown SAML message: ' . var_export($xml->localName, TRUE));
}
}
}
?>

View File

@ -1,17 +0,0 @@
<?php
/**
* Base class for all SAML 2 request messages.
*
* Implements samlp:RequestAbstractType. All of the elements in that type is
* stored in the SAML2_Message class, and this class is therefore empty. It
* is included mainly to make it easy to separate requests from responses.
*
* @package simpleSAMLphp
* @version $Id$
*/
abstract class SAML2_Request extends SAML2_Message {
}
?>

View File

@ -1,84 +0,0 @@
<?php
/**
* Class for SAML 2 Response messages.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_Response extends SAML2_StatusResponse {
/**
* The assertions in this response.
*/
private $assertions;
/**
* Constructor for SAML 2 response messages.
*
* @param DOMElement|NULL $xml The input message.
*/
public function __construct(DOMElement $xml = NULL) {
parent::__construct('Response', $xml);
$this->assertions = array();
if ($xml === NULL) {
return;
}
for ($node = $xml->firstChild; $node !== NULL; $node = $node->nextSibling) {
if ($node->namespaceURI !== SAML2_Const::NS_SAML) {
continue;
}
if ($node->localName === 'Assertion') {
$this->assertions[] = new SAML2_Assertion($node);
} elseif($node->localName === 'EncryptedAssertion') {
$this->assertions[] = new SAML2_EncryptedAssertion($node);
}
}
}
/**
* Retrieve the assertions in this response.
*
* @return array Array of SAML2_Assertion and SAML2_EncryptedAssertion objects.
*/
public function getAssertions() {
return $this->assertions;
}
/**
* Set the assertions that should be included in this response.
*
* @param array The assertions.
*/
public function setAssertions(array $assertions) {
$this->assertions = $assertions;
}
/**
* Convert the response message to an XML element.
*
* @return DOMElement This response.
*/
public function toUnsignedXML() {
$root = parent::toUnsignedXML();
foreach ($this->assertions as $assertion) {
$node = $assertion->toXML($root);
}
return $root;
}
}
?>

View File

@ -1,57 +0,0 @@
<?php
/**
* Class which implements the SOAP binding.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_SOAP extends SAML2_Binding {
/**
* Send a SAML 2 message using the SOAP binding.
*
* Note: This function never returns.
*
* @param SAML2_Message $message The message we should send.
*/
public function send(SAML2_Message $message) {
header('Content-Type: text/xml',true);
$outputFromIdp = '<?xml version="1.0" encoding="UTF-8"?>';
$outputFromIdp .= '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">';
$outputFromIdp .= '<SOAP-ENV:Body>';
$xmlMessage = $message->toSignedXML();
SimpleSAML_Utilities::debugMessage($xmlMessage, 'out');
$tempOutputFromIdp = $xmlMessage->ownerDocument->saveXML($xmlMessage);
$outputFromIdp .= $tempOutputFromIdp;
$outputFromIdp .= '</SOAP-ENV:Body>';
$outputFromIdp .= '</SOAP-ENV:Envelope>';
print($outputFromIdp);
exit(0);
}
/**
* Receive a SAML 2 message sent using the HTTP-POST binding.
*
* Throws an exception if it is unable receive the message.
*
* @return SAML2_Message The received message.
*/
public function receive() {
$postText = file_get_contents('php://input');
if(empty($postText)){
throw new SimpleSAML_Error_BadRequest('Invalid message received to AssertionConsumerService endpoint.');
}
$document = new DOMDocument();
$document->loadXML($postText);
$xml = $document->firstChild;
SimpleSAML_Utilities::debugMessage($xml, 'in');
$results = SAML2_Utils::xpQuery($xml, '/soap-env:Envelope/soap-env:Body/*[1]');
return SAML2_Message::fromXML($results[0]);
}
}

View File

@ -1,223 +0,0 @@
<?php
/**
* Implementation of the SAML 2.0 SOAP binding.
*
* @author Shoaib Ali
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_SOAPClient {
const START_SOAP_ENVELOPE = '<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"><soap-env:Header/><soap-env:Body>';
const END_SOAP_ENVELOPE = '</soap-env:Body></soap-env:Envelope>';
/**
* This function sends the SOAP message to the service location and returns SOAP response
*
* @param SAML2_Message $m The request that should be sent.
* @param SimpleSAML_Configuration $srcMetadata The metadata of the issuer of the message.
* @param SimpleSAML_Configuration $dstMetadata The metadata of the destination of the message.
* @return SAML2_Message The response we received.
*/
public function send(SAML2_Message $msg, SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata = NULL) {
$issuer = $msg->getIssuer();
$ctxOpts = array(
'ssl' => array(
'capture_peer_cert' => TRUE,
),
);
// Determine if we are going to do a MutualSSL connection between the IdP and SP - Shoaib
if ($srcMetadata->hasValue('saml.SOAPClient.certificate')) {
$cert = $srcMetadata->getValue('saml.SOAPClient.certificate');
if ($cert !== FALSE) {
$ctxOpts['ssl']['local_cert'] = SimpleSAML_Utilities::resolveCert($srcMetadata->getString('saml.SOAPClient.certificate'));
if ($srcMetadata->hasValue('saml.SOAPClient.privatekey_pass')) {
$ctxOpts['ssl']['passphrase'] = $srcMetadata->getString('saml.SOAPClient.privatekey_pass');
}
}
} else {
/* Use the SP certificate and privatekey if it is configured. */
$privateKey = SimpleSAML_Utilities::loadPrivateKey($srcMetadata);
$publicKey = SimpleSAML_Utilities::loadPublicKey($srcMetadata);
if ($privateKey !== NULL && $publicKey !== NULL && isset($publicKey['PEM'])) {
$keyCertData = $privateKey['PEM'] . $publicKey['PEM'];
$file = SimpleSAML_Utilities::getTempDir() . '/' . sha1($keyCertData) . '.pem';
if (!file_exists($file)) {
SimpleSAML_Utilities::writeFile($file, $keyCertData);
}
$ctxOpts['ssl']['local_cert'] = $file;
if (isset($privateKey['password'])) {
$ctxOpts['ssl']['passphrase'] = $privateKey['password'];
}
}
}
// do peer certificate verification
if ($dstMetadata !== NULL) {
$peerPublicKeys = $dstMetadata->getPublicKeys('signing', TRUE);
$certData = '';
foreach ($peerPublicKeys as $key) {
if ($key['type'] !== 'X509Certificate') {
continue;
}
$certData .= "-----BEGIN CERTIFICATE-----\n" .
chunk_split($key['X509Certificate'], 64) .
"-----END CERTIFICATE-----\n";
}
$peerCertFile = SimpleSAML_Utilities::getTempDir() . '/' . sha1($certData) . '.pem';
if (!file_exists($peerCertFile)) {
SimpleSAML_Utilities::writeFile($peerCertFile, $certData);
}
// create ssl context
$ctxOpts['ssl']['verify_peer'] = TRUE;
$ctxOpts['ssl']['verify_depth'] = 1;
$ctxOpts['ssl']['cafile'] = $peerCertFile;
}
$context = stream_context_create($ctxOpts);
if ($context === NULL) {
throw new Exception('Unable to create SSL stream context');
}
$options = array(
'uri' => $issuer,
'location' => $msg->getDestination(),
'stream_context' => $context,
);
$x = new SoapClient(NULL, $options);
// Add soap-envelopes
$request = $msg->toSignedXML();
$request = self::START_SOAP_ENVELOPE . $request->ownerDocument->saveXML($request) . self::END_SOAP_ENVELOPE;
SimpleSAML_Utilities::debugMessage($request, 'out');
$action = 'http://www.oasis-open.org/committees/security';
$version = '1.1';
$destination = $msg->getDestination();
/* Perform SOAP Request over HTTP */
$soapresponsexml = $x->__doRequest($request, $destination, $action, $version);
if ($soapresponsexml === NULL || $soapresponsexml === "") {
throw new Exception('Empty SOAP response, check peer certificate.');
}
SimpleSAML_Utilities::debugMessage($soapresponsexml, 'in');
// Convert to SAML2_Message (DOMElement)
$dom = new DOMDocument();
if (!$dom->loadXML($soapresponsexml)) {
throw new Exception('Not a SOAP response.');
}
$soapfault = $this->getSOAPFault($dom);
if (isset($soapfault)) {
throw new Exception($soapfault);
}
//Extract the message from the response
$xml = $dom->firstChild; /* Soap Envelope */
$samlresponse = SAML2_Utils::xpQuery($dom->firstChild, '/soap-env:Envelope/soap-env:Body/*[1]');
$samlresponse = SAML2_Message::fromXML($samlresponse[0]);
/* Add validator to message which uses the SSL context. */
self::addSSLValidator($samlresponse, $context);
SimpleSAML_Logger::debug("Valid ArtifactResponse received from IdP");
return $samlresponse;
}
/**
* Add a signature validator based on a SSL context.
*
* @param SAML2_Message $msg The message we should add a validator to.
* @param resource $context The stream context.
*/
private static function addSSLValidator(SAML2_Message $msg, $context) {
$options = stream_context_get_options($context);
if (!isset($options['ssl']['peer_certificate'])) {
return;
}
//$out = '';
//openssl_x509_export($options['ssl']['peer_certificate'], $out);
$key = openssl_pkey_get_public($options['ssl']['peer_certificate']);
if ($key === FALSE) {
SimpleSAML_Logger::warning('Unable to get public key from peer certificate.');
return;
}
$keyInfo = openssl_pkey_get_details($key);
if ($keyInfo === FALSE) {
SimpleSAML_Logger::warning('Unable to get key details from public key.');
return;
}
if (!isset($keyInfo['key'])) {
SimpleSAML_Logger::warning('Missing key in public key details.');
return;
}
$msg->addValidator(array('SAML2_SOAPClient', 'validateSSL'), $keyInfo['key']);
}
/**
* Validate a SOAP message against the certificate on the SSL connection.
*
* @param string $data The public key that was used on the connection.
* @param XMLSecurityKey $key The key we should validate the certificate against.
*/
public static function validateSSL($data, XMLSecurityKey $key) {
assert('is_string($data)');
$keyInfo = openssl_pkey_get_details($key->key);
if ($keyInfo === FALSE) {
throw new Exception('Unable to get key details from XMLSecurityKey.');
}
if (!isset($keyInfo['key'])) {
throw new Exception('Missing key in public key details.');
}
if ($keyInfo['key'] !== $data) {
SimpleSAML_Logger::debug('Key on SSL connection did not match key we validated against.');
return FALSE;
}
SimpleSAML_Logger::debug('Message validated based on SSL certificate.');
}
/*
* Extracts the SOAP Fault from SOAP message
* @param $soapmessage Soap response needs to be type DOMDocument
* @return $soapfaultstring string|NULL
*/
private function getSOAPFault($soapmessage) {
$soapfault = SAML2_Utils::xpQuery($soapmessage->firstChild, '/soap-env:Envelope/soap-env:Body/soap-env:Fault');
if (empty($soapfault)) {
/* No fault. */
return NULL;
}
$soapfaultelement = $soapfault[0];
$soapfaultstring = "Unknown fault string found"; // There is a fault element but we havn't found out what the fault string is
// find out the fault string
$faultstringelement = SAML2_Utils::xpQuery($soapfaultelement, './soap-env:faultstring') ;
if (!empty($faultstringelement)) {
return $faultstringelement[0]->textContent;
}
return $soapfaultstring;
}
}

View File

@ -1,58 +0,0 @@
<?php
/**
* Interface to a SAML 2 element which may be signed.
*
* @package simpleSAMLphp
* @version $Id$
*/
interface SAML2_SignedElement {
/**
* Validate this element against a public key.
*
* If no signature is present, FALSE is returned. If a signature is present,
* but cannot be verified, an exception will be thrown.
*
* @param XMLSecurityKey $key The key we should check against.
* @return boolean TRUE if successful, FALSE if we don't have a signature that can be verified.
*/
public function validate(XMLSecurityKey $key);
/**
* Set the certificates that should be included in the element.
*
* The certificates should be strings with the PEM encoded data.
*
* @param array $certificates An array of certificates.
*/
public function setCertificates(array $certificates);
/**
* Retrieve the certificates that are included in the element (if any).
*
* @return array An array of certificates.
*/
public function getCertificates();
/**
* Retrieve the private key we should use to sign the element.
*
* @return XMLSecurityKey|NULL The key, or NULL if no key is specified.
*/
public function getSignatureKey();
/**
* Set the private key we should use to sign the element.
*
* If the key is NULL, the message will be sent unsigned.
*
* @param XMLSecurityKey|NULL $key
*/
public function setSignatureKey(XMLsecurityKey $signatureKey = NULL);
}

View File

@ -1,220 +0,0 @@
<?php
/**
* Helper class for processing signed elements.
*
* Can either be inherited from, or can be used by proxy.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_SignedElementHelper implements SAML2_SignedElement {
/**
* The private key we should use to sign the message.
*
* The private key can be NULL, in which case the message is sent unsigned.
*
* @var XMLSecurityKey|NULL
*/
private $signatureKey;
/**
* List of certificates that should be included in the message.
*
* @var array
*/
private $certificates;
/**
* Available methods for validating this message.
*
* @var array
*/
private $validators;
/**
* Initialize the helper class.
*
* @param DOMElement|NULL $xml The XML element which may be signed.
*/
protected function __construct(DOMElement $xml = NULL) {
$this->certificates = array();
$this->validators = array();
if ($xml === NULL) {
return;
}
/* Validate the signature element of the message. */
try {
$sig = SAML2_Utils::validateElement($xml);
if ($sig !== FALSE) {
$this->certificates = $sig['Certificates'];
$this->validators[] = array(
'Function' => array('SAML2_Utils', 'validateSignature'),
'Data' => $sig,
);
}
} catch (Exception $e) {
/* Ignore signature validation errors. */
}
}
/**
* Add a method for validating this element.
*
* This function is used for custom validation extensions
*
* @param callback $function The function which should be called.
* @param mixed $data The data that should be included as the first parameter to the function.
*/
public function addValidator($function, $data) {
assert('is_callable($function)');
$this->validators[] = array(
'Function' => $function,
'Data' => $data,
);
}
/**
* Validate this element against a public key.
*
* TRUE is returned on success, FALSE is returned if we don't have any
* signature we can validate. An exception is thrown if the signature
* validation fails.
*
* @param XMLSecurityKey $key The key we should check against.
* @return boolean TRUE on success, FALSE when we don't have a signature.
*/
public function validate(XMLSecurityKey $key) {
if (count($this->validators) === 0) {
return FALSE;
}
$exceptions = array();
foreach ($this->validators as $validator) {
$function = $validator['Function'];
$data = $validator['Data'];
try {
call_user_func($function, $data, $key);
/* We were able to validate the message with this validator. */
return TRUE;
} catch (Exception $e) {
$exceptions[] = $e;
}
}
/* No validators were able to validate the message. */
throw $exceptions[0];
}
/**
* Retrieve the private key we should use to sign the message.
*
* @return XMLSecurityKey|NULL The key, or NULL if no key is specified.
*/
public function getSignatureKey() {
return $this->signatureKey;
}
/**
* Set the private key we should use to sign the message.
*
* If the key is NULL, the message will be sent unsigned.
*
* @param XMLSecurityKey|NULL $key
*/
public function setSignatureKey(XMLsecurityKey $signatureKey = NULL) {
$this->signatureKey = $signatureKey;
}
/**
* Set the certificates that should be included in the message.
*
* The certificates should be strings with the PEM encoded data.
*
* @param array $certificates An array of certificates.
*/
public function setCertificates(array $certificates) {
$this->certificates = $certificates;
}
/**
* Retrieve the certificates that are included in the message.
*
* @return array An array of certificates.
*/
public function getCertificates() {
return $this->certificates;
}
/**
* Retrieve certificates that sign this element.
*
* @return array Array with certificates.
*/
public function getValidatingCertificates() {
$ret = array();
foreach ($this->certificates as $cert) {
/* We have found a matching fingerprint. */
$pemCert = "-----BEGIN CERTIFICATE-----\n" .
chunk_split($cert, 64) .
"-----END CERTIFICATE-----\n";
/* Extract the public key from the certificate for validation. */
$key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'public'));
$key->loadKey($pemCert);
try {
/* Check the signature. */
if ($this->validate($key)) {
$ret[] = $cert;
}
} catch (Exception $e) {
/* This certificate does not sign this element. */
}
}
return $ret;
}
/**
* Sign the given XML element.
*
* @param DOMElement $root The element we should sign.
* @param DOMElement|NULL $insertBefore The element we should insert the signature node before.
*/
protected function signElement(DOMElement $root, DOMElement $insertBefore = NULL) {
if ($this->signatureKey === NULL) {
/* We cannot sign this element. */
return;
}
SAML2_Utils::insertSignature($this->signatureKey, $this->certificates, $root, $insertBefore);
return $root;
}
}

View File

@ -1,193 +0,0 @@
<?php
/**
* Base class for all SAML 2 response messages.
*
* Implements samlp:StatusResponseType. All of the elements in that type is
* stored in the SAML2_Message class, and this class is therefore more
* or less empty. It is included mainly to make it easy to separate requests from
* responses.
*
* The status code is represented as an array on the following form:
* array(
* 'Code' => '<top-level status code>',
* 'SubCode' => '<second-level status code>',
* 'Message' => '<status message>',
* )
*
* Only the 'Code' field is required. The others will be set to NULL if they
* aren't present.
*
* @package simpleSAMLphp
* @version $Id$
*/
abstract class SAML2_StatusResponse extends SAML2_Message {
/**
* The ID of the request this is a response to, or NULL if this is an unsolicited response.
*
* @var string|NULL
*/
private $inResponseTo;
/**
* The status code of the response.
*
* @var array
*/
private $status;
/**
* Constructor for SAML 2 response messages.
*
* @param string $tagName The tag name of the root element.
* @param DOMElement|NULL $xml The input message.
*/
protected function __construct($tagName, DOMElement $xml = NULL) {
parent::__construct($tagName, $xml);
$this->status = array(
'Code' => SAML2_Const::STATUS_SUCCESS,
'SubCode' => NULL,
'Message' => NULL,
);
if ($xml === NULL) {
return;
}
if ($xml->hasAttribute('InResponseTo')) {
$this->inResponseTo = $xml->getAttribute('InResponseTo');
}
$status = SAML2_Utils::xpQuery($xml, './saml_protocol:Status');
if (empty($status)) {
throw new Exception('Missing status code on response.');
}
$status = $status[0];
$statusCode = SAML2_Utils::xpQuery($status, './saml_protocol:StatusCode');
if (empty($statusCode)) {
throw new Exception('Missing status code in status element.');
}
$statusCode = $statusCode[0];
$this->status['Code'] = $statusCode->getAttribute('Value');
$subCode = SAML2_Utils::xpQuery($statusCode, './saml_protocol:StatusCode');
if (!empty($subCode)) {
$this->status['SubCode'] = $subCode[0]->getAttribute('Value');
}
$message = SAML2_Utils::xpQuery($status, './saml_protocol:StatusMessage');
if (!empty($message)) {
$this->status['Message'] = trim($message[0]->textContent);
}
}
/**
* Determine whether this is a successful response.
*
* @return boolean TRUE if the status code is success, FALSE if not.
*/
public function isSuccess() {
assert('array_key_exists("Code", $this->status)');
if ($this->status['Code'] === SAML2_Const::STATUS_SUCCESS) {
return TRUE;
}
return FALSE;
}
/**
* Retrieve the ID of the request this is a response to.
*
* @return string|NULL The ID of the request.
*/
public function getInResponseTo() {
return $this->inResponseTo;
}
/**
* Set the ID of the request this is a response to.
*
* @param string|NULL $inResponseTo The ID of the request.
*/
public function setInResponseTo($inResponseTo) {
assert('is_string($inResponseTo) || is_null($inResponseTo)');
$this->inResponseTo = $inResponseTo;
}
/**
* Retrieve the status code.
*
* @return array The status code.
*/
public function getStatus() {
return $this->status;
}
/**
* Set the status code.
*
* @param array $status The status code.
*/
public function setStatus(array $status) {
assert('array_key_exists("Code", $status)');
$this->status = $status;
if (!array_key_exists('SubCode', $status)) {
$this->status['SubCode'] = NULL;
}
if (!array_key_exists('Message', $status)) {
$this->status['Message'] = NULL;
}
}
/**
* Convert status response message to an XML element.
*
* @return DOMElement This status response.
*/
public function toUnsignedXML() {
$root = parent::toUnsignedXML();
if ($this->inResponseTo !== NULL) {
$root->setAttribute('InResponseTo', $this->inResponseTo);
}
$status = $this->document->createElementNS(SAML2_Const::NS_SAMLP, 'Status');
$root->appendChild($status);
$statusCode = $this->document->createElementNS(SAML2_Const::NS_SAMLP, 'StatusCode');
$statusCode->setAttribute('Value', $this->status['Code']);
$status->appendChild($statusCode);
if (!is_null($this->status['SubCode'])) {
$subStatusCode = $this->document->createElementNS(SAML2_Const::NS_SAMLP, 'StatusCode');
$subStatusCode->setAttribute('Value', $this->status['SubCode']);
$statusCode->appendChild($subStatusCode);
}
if (!is_null($this->status['Message'])) {
SAML2_Utils::addString($status, SAML2_Const::NS_SAMLP, 'StatusMessage', $this->status['Message']);
}
return $root;
}
}
?>

View File

@ -1,116 +0,0 @@
<?php
/**
* Base class for SAML 2 subject query messages.
*
* This base class can be used for various requests which ask for
* information about a particular subject.
*
* Note that this class currently only handles the simple case - where the
* subject doesn't contain any sort of subject confirmation requirements.
*
* @package simpleSAMLphp
* @version $Id$
*/
abstract class SAML2_SubjectQuery extends SAML2_Request {
/**
* The NameId of the subject in the query.
*
* @var array
*/
private $nameId;
/**
* Constructor for SAML 2 subject query messages.
*
* @param string $tagName The tag name of the root element.
* @param DOMElement|NULL $xml The input message.
*/
protected function __construct($tagName, DOMElement $xml = NULL) {
parent::__construct($tagName, $xml);
$nameId = array();
if ($xml === NULL) {
return;
}
$this->parseSubject($xml);
}
/**
* Parse subject in query.
*
* @param DOMElement $xml The SubjectQuery XML element.
*/
private function parseSubject(DOMElement $xml) {
$subject = SAML2_Utils::xpQuery($xml, './saml_assertion:Subject');
if (empty($subject)) {
/* No Subject node. */
throw new Exception('Missing subject in subject query.');
} elseif (count($subject) > 1) {
throw new Exception('More than one <saml:Subject> in <saml:Assertion>.');
}
$subject = $subject[0];
$nameId = SAML2_Utils::xpQuery($subject, './saml_assertion:NameID');
if (empty($nameId)) {
throw new Exception('Missing <saml:NameID> in <saml:Subject>.');
} elseif (count($nameId) > 1) {
throw new Exception('More than one <saml:NameID> in <saml:Subject>.');
}
$nameId = $nameId[0];
$this->nameId = SAML2_Utils::parseNameId($nameId);
}
/**
* Retrieve the NameId of the subject in the query.
*
* The returned NameId is in the format used by SAML2_Utils::addNameId().
*
* @see SAML2_Utils::addNameId()
* @return array|NULL The name identifier of the assertion.
*/
public function getNameId() {
return $this->nameId;
}
/**
* Set the NameId of the subject in the query.
*
* The NameId must be in the format accepted by SAML2_Utils::addNameId().
*
* @see SAML2_Utils::addNameId()
* @param array|NULL $nameId The name identifier of the assertion.
*/
public function setNameId($nameId) {
assert('is_array($nameId) || is_null($nameId)');
$this->nameId = $nameId;
}
/**
* Convert subject query message to an XML element.
*
* @return DOMElement This subject query.
*/
public function toUnsignedXML() {
$root = parent::toUnsignedXML();
$subject = $root->ownerDocument->createElementNS(SAML2_Const::NS_SAML, 'saml:Subject');
$root->appendChild($subject);
SAML2_Utils::addNameId($subject, $this->nameId);
return $root;
}
}

View File

@ -1,641 +0,0 @@
<?php
/**
* Helper functions for the SAML2 library.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_Utils {
/**
* Check the Signature in a XML element.
*
* This function expects the XML element to contain a Signature-element
* which contains a reference to the XML-element. This is common for both
* messages and assertions.
*
* Note that this function only validates the element itself. It does not
* check this against any local keys.
*
* If no Signature-element is located, this function will return FALSE. All
* other validation errors result in an exception. On successful validation
* an array will be returned. This array contains the information required to
* check the signature against a public key.
*
* @param DOMElement $root The element which should be validated.
* @return array|FALSE An array with information about the Signature-element.
*/
public static function validateElement(DOMElement $root) {
/* Create an XML security object. */
$objXMLSecDSig = new XMLSecurityDSig();
/* Both SAML messages and SAML assertions use the 'ID' attribute. */
$objXMLSecDSig->idKeys[] = 'ID';
/* Locate the XMLDSig Signature element to be used. */
$signatureElement = self::xpQuery($root, './ds:Signature');
if (count($signatureElement) === 0) {
/* We don't have a signature element ot validate. */
return FALSE;
} elseif (count($signatureElement) > 1) {
throw new Exception('XMLSec: more than one signature element in root.');
}
$signatureElement = $signatureElement[0];
$objXMLSecDSig->sigNode = $signatureElement;
/* Canonicalize the XMLDSig SignedInfo element in the message. */
$objXMLSecDSig->canonicalizeSignedInfo();
/* Validate referenced xml nodes. */
if (!$objXMLSecDSig->validateReference()) {
throw new Exception('XMLsec: digest validation failed');
}
/* Check that $root is one of the signed nodes. */
$rootSigned = FALSE;
foreach ($objXMLSecDSig->getValidatedNodes() as $signedNode) {
if ($signedNode->isSameNode($root)) {
$rootSigned = TRUE;
break;
} elseif ($root->parentNode instanceof DOMDocument && $signedNode->isSameNode($root->ownerDocument)) {
/* $root is the root element of a signed document. */
$rootSigned = TRUE;
break;
}
}
if (!$rootSigned) {
throw new Exception('XMLSec: The root element is not signed.');
}
/* Now we extract all available X509 certificates in the signature element. */
$certificates = array();
foreach (self::xpQuery($signatureElement, './ds:KeyInfo/ds:X509Data/ds:X509Certificate') as $certNode) {
$certData = trim($certNode->textContent);
$certData = str_replace(array("\r", "\n", "\t", ' '), '', $certData);
$certificates[] = $certData;
}
$ret = array(
'Signature' => $objXMLSecDSig,
'Certificates' => $certificates,
);
return $ret;
}
/**
* Helper function to convert a XMLSecurityKey to the correct algorithm.
*
* @param XMLSecurityKey $key The key.
* @param string $algorithm The desired algorithm.
* @param string $types Public or private key, defaults to public.
* @return XMLSecurityKey The new key.
*/
public static function castKey(XMLSecurityKey $key, $algorithm, $type = 'public') {
assert('is_string($algorithm)');
assert('$type === "public" || $type === "private"');
// do nothing if algorithm is already the type of the key
if ($key->type === $algorithm) {
return $key;
}
$keyInfo = openssl_pkey_get_details($key->key);
if ($keyInfo === FALSE) {
throw new Exception('Unable to get key details from XMLSecurityKey.');
}
if (!isset($keyInfo['key'])) {
throw new Exception('Missing key in public key details.');
}
$newKey = new XMLSecurityKey($algorithm, array('type'=>$type));
$newKey->loadKey($keyInfo['key']);
return $newKey;
}
/**
* Check a signature against a key.
*
* An exception is thrown if we are unable to validate the signature.
*
* @param array $info The information returned by the validateElement()-function.
* @param XMLSecurityKey $key The publickey that should validate the Signature object.
*/
public static function validateSignature(array $info, XMLSecurityKey $key) {
assert('array_key_exists("Signature", $info)');
$objXMLSecDSig = $info['Signature'];
$sigMethod = self::xpQuery($objXMLSecDSig->sigNode, './ds:SignedInfo/ds:SignatureMethod');
if (empty($sigMethod)) {
throw new Exception('Missing SignatureMethod element.');
}
$sigMethod = $sigMethod[0];
if (!$sigMethod->hasAttribute('Algorithm')) {
throw new Exception('Missing Algorithm-attribute on SignatureMethod element.');
}
$algo = $sigMethod->getAttribute('Algorithm');
if ($key->type === XMLSecurityKey::RSA_SHA1 && $algo !== $key->type) {
$key = self::castKey($key, $algo);
}
/* Check the signature. */
if (! $objXMLSecDSig->verify($key)) {
throw new Exception("Unable to validate Signature");
}
}
/**
* Do an XPath query on an XML node.
*
* @param DOMNode $node The XML node.
* @param string $query The query.
* @return array Array with matching DOM nodes.
*/
public static function xpQuery(DOMNode $node, $query) {
assert('is_string($query)');
static $xpCache = NULL;
if ($node instanceof DOMDocument) {
$doc = $node;
} else {
$doc = $node->ownerDocument;
}
if ($xpCache === NULL || !$xpCache->document->isSameNode($doc)) {
$xpCache = new DOMXPath($doc);
$xpCache->registerNamespace('soap-env', SAML2_Const::NS_SOAP);
$xpCache->registerNamespace('saml_protocol', SAML2_Const::NS_SAMLP);
$xpCache->registerNamespace('saml_assertion', SAML2_Const::NS_SAML);
$xpCache->registerNamespace('saml_metadata', SAML2_Const::NS_MD);
$xpCache->registerNamespace('ds', XMLSecurityDSig::XMLDSIGNS);
$xpCache->registerNamespace('xenc', XMLSecEnc::XMLENCNS);
}
$results = $xpCache->query($query, $node);
$ret = array();
for ($i = 0; $i < $results->length; $i++) {
$ret[$i] = $results->item($i);
}
return $ret;
}
/**
* Make an exact copy the specific DOMElement.
*
* @param DOMElement $element The element we should copy.
* @param DOMElement|NULL $parent The target parent element.
* @return DOMElement The copied element.
*/
public static function copyElement(DOMElement $element, DOMElement $parent = NULL) {
if ($parent === NULL) {
$document = new DOMDocument();
} else {
$document = $parent->ownerDocument;
}
$namespaces = array();
for ($e = $element; $e !== NULL; $e = $e->parentNode) {
foreach (SAML2_Utils::xpQuery($e, './namespace::*') as $ns) {
$prefix = $ns->localName;
if ($prefix === 'xml' || $prefix === 'xmlns') {
continue;
}
$uri = $ns->nodeValue;
if (!isset($namespaces[$prefix])) {
$namespaces[$prefix] = $uri;
}
}
}
$newElement = $document->importNode($element, TRUE);
if ($parent !== NULL) {
/* We need to append the child to the parent before we add the namespaces. */
$parent->appendChild($newElement);
}
foreach ($namespaces as $prefix => $uri) {
$newElement->setAttributeNS($uri, $prefix . ':__ns_workaround__', 'tmp');
$newElement->removeAttributeNS($uri, '__ns_workaround__');
}
return $newElement;
}
/**
* Parse a boolean attribute.
*
* @param DOMElement $node The element we should fetch the attribute from.
* @param string $attributeName The name of the attribute.
* @param mixed $default The value that should be returned if the attribute doesn't exist.
* @return bool|mixed The value of the attribute, or $default if the attribute doesn't exist.
*/
public static function parseBoolean(DOMElement $node, $attributeName, $default = NULL) {
assert('is_string($attributeName)');
if (!$node->hasAttribute($attributeName)) {
return $default;
}
$value = $node->getAttribute($attributeName);
switch (strtolower($value)) {
case '0':
case 'false':
return FALSE;
case '1':
case 'true':
return TRUE;
default:
throw new Exception('Invalid value of boolean attribute ' . var_export($attributeName, TRUE) . ': ' . var_export($value, TRUE));
}
}
/**
* Create a NameID element.
*
* The NameId array can have the following elements: 'Value', 'Format',
* 'NameQualifier, 'SPNameQualifier'
*
* Only the 'Value'-element is required.
*
* @param DOMElement $node The DOM node we should append the NameId to.
* @param array $nameId The name identifier.
*/
public static function addNameId(DOMElement $node, array $nameId) {
assert('array_key_exists("Value", $nameId)');
$xml = SAML2_Utils::addString($node, SAML2_Const::NS_SAML, 'saml:NameID', $nameId['Value']);
if (array_key_exists('NameQualifier', $nameId) && $nameId['NameQualifier'] !== NULL) {
$xml->setAttribute('NameQualifier', $nameId['NameQualifier']);
}
if (array_key_exists('SPNameQualifier', $nameId) && $nameId['SPNameQualifier'] !== NULL) {
$xml->setAttribute('SPNameQualifier', $nameId['SPNameQualifier']);
}
if (array_key_exists('Format', $nameId) && $nameId['Format'] !== NULL) {
$xml->setAttribute('Format', $nameId['Format']);
}
}
/**
* Parse a NameID element.
*
* @param DOMElement $xml The DOM element we should parse.
* @return array The parsed name identifier.
*/
public static function parseNameId(DOMElement $xml) {
$ret = array('Value' => trim($xml->textContent));
foreach (array('NameQualifier', 'SPNameQualifier', 'Format') as $attr) {
if ($xml->hasAttribute($attr)) {
$ret[$attr] = $xml->getAttribute($attr);
}
}
return $ret;
}
/**
* Insert a Signature-node.
*
* @param XMLSecurityKey $key The key we should use to sign the message.
* @param array $certificates The certificates we should add to the signature node.
* @param DOMElement $root The XML node we should sign.
* @param DomElement $insertBefore The XML element we should insert the signature element before.
*/
public static function insertSignature(XMLSecurityKey $key, array $certificates, DOMElement $root, DOMNode $insertBefore = NULL) {
$objXMLSecDSig = new XMLSecurityDSig();
$objXMLSecDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);
switch ($key->type) {
case XMLSecurityKey::RSA_SHA256:
$type = XMLSecurityDSig::SHA256;
break;
case XMLSecurityKey::RSA_SHA384:
$type = XMLSecurityDSig::SHA384;
break;
case XMLSecurityKey::RSA_SHA512:
$type = XMLSecurityDSig::SHA512;
break;
default:
$type = XMLSecurityDSig::SHA1;
}
$objXMLSecDSig->addReferenceList(
array($root),
$type,
array('http://www.w3.org/2000/09/xmldsig#enveloped-signature', XMLSecurityDSig::EXC_C14N),
array('id_name' => 'ID', 'overwrite' => FALSE)
);
$objXMLSecDSig->sign($key);
foreach ($certificates as $certificate) {
$objXMLSecDSig->add509Cert($certificate, TRUE);
}
$objXMLSecDSig->insertSignature($root, $insertBefore);
}
/**
* Decrypt an encrypted element.
*
* This is an internal helper function.
*
* @param DOMElement $encryptedData The encrypted data.
* @param XMLSecurityKey $inputKey The decryption key.
* @param array &$blacklist Blacklisted decryption algorithms.
* @return DOMElement The decrypted element.
*/
private static function _decryptElement(DOMElement $encryptedData, XMLSecurityKey $inputKey, array &$blacklist) {
$enc = new XMLSecEnc();
$enc->setNode($encryptedData);
$enc->type = $encryptedData->getAttribute("Type");
$symmetricKey = $enc->locateKey($encryptedData);
if (!$symmetricKey) {
throw new Exception('Could not locate key algorithm in encrypted data.');
}
$symmetricKeyInfo = $enc->locateKeyInfo($symmetricKey);
if (!$symmetricKeyInfo) {
throw new Exception('Could not locate <dsig:KeyInfo> for the encrypted key.');
}
$inputKeyAlgo = $inputKey->getAlgorith();
if ($symmetricKeyInfo->isEncrypted) {
$symKeyInfoAlgo = $symmetricKeyInfo->getAlgorith();
if (in_array($symKeyInfoAlgo, $blacklist, TRUE)) {
throw new Exception('Algorithm disabled: ' . var_export($symKeyInfoAlgo, TRUE));
}
if ($symKeyInfoAlgo === XMLSecurityKey::RSA_OAEP_MGF1P && $inputKeyAlgo === XMLSecurityKey::RSA_1_5) {
/*
* The RSA key formats are equal, so loading an RSA_1_5 key
* into an RSA_OAEP_MGF1P key can be done without problems.
* We therefore pretend that the input key is an
* RSA_OAEP_MGF1P key.
*/
$inputKeyAlgo = XMLSecurityKey::RSA_OAEP_MGF1P;
}
/* Make sure that the input key format is the same as the one used to encrypt the key. */
if ($inputKeyAlgo !== $symKeyInfoAlgo) {
throw new Exception('Algorithm mismatch between input key and key used to encrypt ' .
' the symmetric key for the message. Key was: ' .
var_export($inputKeyAlgo, TRUE) . '; message was: ' .
var_export($symKeyInfoAlgo, TRUE));
}
$encKey = $symmetricKeyInfo->encryptedCtx;
$symmetricKeyInfo->key = $inputKey->key;
$keySize = $symmetricKey->getSymmetricKeySize();
if ($keySize === NULL) {
/* To protect against "key oracle" attacks, we need to be able to create a
* symmetric key, and for that we need to know the key size.
*/
throw new Exception('Unknown key size for encryption algorithm: ' . var_export($symmetricKey->type, TRUE));
}
try {
$key = $encKey->decryptKey($symmetricKeyInfo);
if (strlen($key) != $keySize) {
throw new Exception('Unexpected key size (' . strlen($key) * 8 . 'bits) for encryption algorithm: ' .
var_export($symmetricKey->type, TRUE));
}
} catch (Exception $e) {
/* We failed to decrypt this key. Log it, and substitute a "random" key. */
SimpleSAML_Logger::error('Failed to decrypt symmetric key: ' . $e->getMessage());
/* Create a replacement key, so that it looks like we fail in the same way as if the key was correctly padded. */
/* We base the symmetric key on the encrypted key and private key, so that we always behave the
* same way for a given input key.
*/
$encryptedKey = $encKey->getCipherValue();
$pkey = openssl_pkey_get_details($symmetricKeyInfo->key);
$pkey = sha1(serialize($pkey), TRUE);
$key = sha1($encryptedKey . $pkey, TRUE);
/* Make sure that the key has the correct length. */
if (strlen($key) > $keySize) {
$key = substr($key, 0, $keySize);
} elseif (strlen($key) < $keySize) {
$key = str_pad($key, $keySize);
}
}
$symmetricKey->loadkey($key);
} else {
$symKeyAlgo = $symmetricKey->getAlgorith();
/* Make sure that the input key has the correct format. */
if ($inputKeyAlgo !== $symKeyAlgo) {
throw new Exception('Algorithm mismatch between input key and key in message. ' .
'Key was: ' . var_export($inputKeyAlgo, TRUE) . '; message was: ' .
var_export($symKeyAlgo, TRUE));
}
$symmetricKey = $inputKey;
}
$algorithm = $symmetricKey->getAlgorith();
if (in_array($algorithm, $blacklist, TRUE)) {
throw new Exception('Algorithm disabled: ' . var_export($algorithm, TRUE));
}
$decrypted = $enc->decryptNode($symmetricKey, FALSE);
/*
* This is a workaround for the case where only a subset of the XML
* tree was serialized for encryption. In that case, we may miss the
* namespaces needed to parse the XML.
*/
$xml = '<root xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'.$decrypted.'</root>';
$newDoc = new DOMDocument();
if (!@$newDoc->loadXML($xml)) {
throw new Exception('Failed to parse decrypted XML. Maybe the wrong sharedkey was used?');
}
$decryptedElement = $newDoc->firstChild->firstChild;
if ($decryptedElement === NULL) {
throw new Exception('Missing encrypted element.');
}
if (!($decryptedElement instanceof DOMElement)) {
throw new Exception('Decrypted element was not actually a DOMElement.');
}
return $decryptedElement;
}
/**
* Decrypt an encrypted element.
*
* @param DOMElement $encryptedData The encrypted data.
* @param XMLSecurityKey $inputKey The decryption key.
* @param array $blacklist Blacklisted decryption algorithms.
* @return DOMElement The decrypted element.
*/
public static function decryptElement(DOMElement $encryptedData, XMLSecurityKey $inputKey, array $blacklist = array()) {
try {
return self::_decryptElement($encryptedData, $inputKey, $blacklist);
} catch (Exception $e) {
/*
* Something went wrong during decryption, but for security
* reasons we cannot tell the user what failed.
*/
SimpleSAML_Logger::error('Decryption failed: ' . $e->getMessage());
throw new Exception('Failed to decrypt XML element.');
}
}
/**
* Extract localized strings from a set of nodes.
*
* @param DOMElement $parent The element that contains the localized strings.
* @param string $namespaceURI The namespace URI the localized strings should have.
* @param string $localName The localName of the localized strings.
* @return array Localized strings.
*/
public static function extractLocalizedStrings(DOMElement $parent, $namespaceURI, $localName) {
assert('is_string($namespaceURI)');
assert('is_string($localName)');
$ret = array();
for ($node = $parent->firstChild; $node !== NULL; $node = $node->nextSibling) {
if ($node->namespaceURI !== $namespaceURI || $node->localName !== $localName) {
continue;
}
if ($node->hasAttribute('xml:lang')) {
$language = $node->getAttribute('xml:lang');
} else {
$language = 'en';
}
$ret[$language] = trim($node->textContent);
}
return $ret;
}
/**
* Extract strings from a set of nodes.
*
* @param DOMElement $parent The element that contains the localized strings.
* @param string $namespaceURI The namespace URI the string elements should have.
* @param string $localName The localName of the string elements.
* @return array The string values of the various nodes.
*/
public static function extractStrings(DOMElement $parent, $namespaceURI, $localName) {
assert('is_string($namespaceURI)');
assert('is_string($localName)');
$ret = array();
for ($node = $parent->firstChild; $node !== NULL; $node = $node->nextSibling) {
if ($node->namespaceURI !== $namespaceURI || $node->localName !== $localName) {
continue;
}
$ret[] = trim($node->textContent);
}
return $ret;
}
/**
* Append string element.
*
* @param DOMElement $parent The parent element we should append the new nodes to.
* @param string $namespace The namespace of the created element.
* @param string $name The name of the created element.
* @param string $value The value of the element.
* @return DOMElement The generated element.
*/
public static function addString(DOMElement $parent, $namespace, $name, $value) {
assert('is_string($namespace)');
assert('is_string($name)');
assert('is_string($value)');
$doc = $parent->ownerDocument;
$n = $doc->createElementNS($namespace, $name);
$n->appendChild($doc->createTextNode($value));
$parent->appendChild($n);
return $n;
}
/**
* Append string elements.
*
* @param DOMElement $parent The parent element we should append the new nodes to.
* @param string $namespace The namespace of the created elements
* @param string $name The name of the created elements
* @param bool $localized Whether the strings are localized, and should include the xml:lang attribute.
* @param array $values The values we should create the elements from.
*/
public static function addStrings(DOMElement $parent, $namespace, $name, $localized, array $values) {
assert('is_string($namespace)');
assert('is_string($name)');
assert('is_bool($localized)');
$doc = $parent->ownerDocument;
foreach ($values as $index => $value) {
$n = $doc->createElementNS($namespace, $name);
$n->appendChild($doc->createTextNode($value));
if ($localized) {
$n->setAttribute('xml:lang', $index);
}
$parent->appendChild($n);
}
}
/**
* Create a KeyDescriptor with the given certificate.
*
* @param string $x509Data The certificate, as a base64-encoded DER data.
* @return SAML2_XML_md_KeyDescriptor The keydescriptor.
*/
public static function createKeyDescriptor($x509Data) {
assert('is_string($x509Data)');
$x509Certificate = new SAML2_XML_ds_X509Certificate();
$x509Certificate->certificate = $x509Data;
$x509Data = new SAML2_XML_ds_X509Data();
$x509Data->data[] = $x509Certificate;
$keyInfo = new SAML2_XML_ds_KeyInfo();
$keyInfo->info[] = $x509Data;
$keyDescriptor = new SAML2_XML_md_KeyDescriptor();
$keyDescriptor->KeyInfo = $keyInfo;
return $keyDescriptor;
}
}

View File

@ -1,104 +0,0 @@
<?php
/**
* Serializable class used to hold an XML element.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_Chunk {
/**
* The localName of the element.
*
* @var string
*/
public $localName;
/**
* The namespaceURI of this element.
*
* @var string
*/
public $namespaceURI;
/**
* The DOMElement we contain.
*
* @var DOMElement
*/
private $xml;
/**
* The DOMElement as a text string. Used during serialization.
*
* @var string|NULL
*/
private $xmlString;
/**
* Create a XMLChunk from a copy of the given DOMElement.
*
* @param DOMElement $xml The element we should copy.
*/
public function __construct(DOMElement $xml) {
$this->localName = $xml->localName;
$this->namespaceURI = $xml->namespaceURI;
$this->xml = SAML2_Utils::copyElement($xml);
}
/**
* Get this DOMElement.
*
* @return DOMElement This element.
*/
public function getXML() {
assert('$this->xml instanceof DOMElement || is_string($this->xmlString)');
if ($this->xml === NULL) {
$doc = new DOMDocument();
$doc->loadXML($this->xmlString);
$this->xml = $doc->firstChild;
}
return $this->xml;
}
/**
* Append this XML element to a different XML element.
*
* @param DOMElement $parent The element we should append this element to.
* @return DOMElement The new element.
*/
public function toXML(DOMElement $parent) {
return SAML2_Utils::copyElement($this->getXML(), $parent);
}
/**
* Serialization handler.
*
* Converts the XML data to a string that can be serialized
*
* @return array List of properties that should be serialized.
*/
public function __sleep() {
assert('$this->xml instanceof DOMElement || is_string($this->xmlString)');
if ($this->xmlString === NULL) {
$this->xmlString = $this->xml->ownerDocument->saveXML($this->xml);
}
return array('xmlString', 'localName', 'namespaceURI');
}
}

View File

@ -1,94 +0,0 @@
<?php
/**
* Class representing a ds:KeyInfo element.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_ds_KeyInfo {
/**
* The Id attribute on this element.
*
* @var string|NULL
*/
public $Id = NULL;
/**
* The various key information elements.
*
* Array with various elements describing this key.
* Unknown elements will be represented by SAML2_XML_Chunk.
*
* @var array
*/
public $info = array();
/**
* Initialize a KeyInfo element.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
if ($xml === NULL) {
return;
}
if ($xml->hasAttribute('Id')) {
$this->Id = $xml->getAttribute('Id');
}
for ($n = $xml->firstChild; $n !== NULL; $n = $n->nextSibling) {
if (!($n instanceof DOMElement)) {
continue;
}
if ($n->namespaceURI !== XMLSecurityDSig::XMLDSIGNS) {
$this->info[] = new SAML2_XML_Chunk($n);
continue;
}
switch ($n->localName) {
case 'KeyName':
$this->info[] = new SAML2_XML_ds_KeyName($n);
break;
case 'X509Data':
$this->info[] = new SAML2_XML_ds_X509Data($n);
break;
default:
$this->info[] = new SAML2_XML_Chunk($n);
break;
}
}
}
/**
* Convert this KeyInfo to XML.
*
* @param DOMElement $parent The element we should append this KeyInfo to.
*/
public function toXML(DOMElement $parent) {
assert('is_null($this->Id) || is_string($this->Id)');
assert('is_array($this->info)');
$doc = $parent->ownerDocument;
$e = $doc->createElementNS(XMLSecurityDSig::XMLDSIGNS, 'ds:KeyInfo');
$parent->appendChild($e);
if (isset($this->Id)) {
$e->setAttribute('Id', $this->Id);
}
foreach ($this->info as $n) {
$n->toXML($e);
}
return $e;
}
}

View File

@ -1,45 +0,0 @@
<?php
/**
* Class representing a ds:KeyName element.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_ds_KeyName {
/**
* The key name.
*
* @var string
*/
public $name;
/**
* Initialize a KeyName element.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
if ($xml === NULL) {
return;
}
$this->name = $xml->textContent;
}
/**
* Convert this KeyName element to XML.
*
* @param DOMElement $parent The element we should append this KeyName element to.
*/
public function toXML(DOMElement $parent) {
assert('is_string($this->name)');
return SAML2_Utils::addString($parent, XMLSecurityDSig::XMLDSIGNS, 'ds:KeyName', $this->name);
}
}

View File

@ -1,45 +0,0 @@
<?php
/**
* Class representing a ds:X509Certificate element.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_ds_X509Certificate {
/**
* The base64-encoded certificate.
*
* @var string
*/
public $certificate;
/**
* Initialize an X509Certificate element.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
if ($xml === NULL) {
return;
}
$this->certificate = $xml->textContent;
}
/**
* Convert this X509Certificate element to XML.
*
* @param DOMElement $parent The element we should append this X509Certificate element to.
*/
public function toXML(DOMElement $parent) {
assert('is_string($this->certificate)');
return SAML2_Utils::addString($parent, XMLSecurityDSig::XMLDSIGNS, 'ds:X509Certificate', $this->certificate);
}
}

View File

@ -1,74 +0,0 @@
<?php
/**
* Class representing a ds:X509Data element.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_ds_X509Data {
/**
* The various X509 data elements.
*
* Array with various elements describing this certificate.
* Unknown elements will be represented by SAML2_XML_Chunk.
*
* @var array
*/
public $data = array();
/**
* Initialize a X509Data.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
if ($xml === NULL) {
return;
}
for ($n = $xml->firstChild; $n !== NULL; $n = $n->nextSibling) {
if (!($n instanceof DOMElement)) {
continue;
}
if ($n->namespaceURI !== XMLSecurityDSig::XMLDSIGNS) {
$this->data[] = new SAML2_XML_Chunk($n);
continue;
}
switch ($n->localName) {
case 'X509Certificate':
$this->data[] = new SAML2_XML_ds_X509Certificate($n);
break;
default:
$this->data[] = new SAML2_XML_Chunk($n);
break;
}
}
}
/**
* Convert this X509Data element to XML.
*
* @param DOMElement $parent The element we should append this X509Data element to.
*/
public function toXML(DOMElement $parent) {
assert('is_array($this->data)');
$doc = $parent->ownerDocument;
$e = $doc->createElementNS(XMLSecurityDSig::XMLDSIGNS, 'ds:X509Data');
$parent->appendChild($e);
foreach ($this->data as $n) {
$n->toXML($e);
}
return $e;
}
}

View File

@ -1,62 +0,0 @@
<?php
/**
* Class representing SAML 2 metadata AdditionalMetadataLocation element.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_md_AdditionalMetadataLocation {
/**
* The namespace of this metadata.
*
* @var string
*/
public $namespace;
/**
* The URI where the metadata is located.
*
* @var string
*/
public $location;
/**
* Initialize an AdditionalMetadataLocation element.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
if ($xml === NULL) {
return;
}
if (!$xml->hasAttribute('namespace')) {
throw new Exception('Missing namespace attribute on AdditionalMetadataLocation element.');
}
$this->namespace = $xml->getAttribute('namespace');
$this->location = $xml->textContent;
}
/**
* Convert this AdditionalMetadataLocation to XML.
*
* @param DOMElement $parent The element we should append to.
* @return DOMElement This AdditionalMetadataLocation-element.
*/
public function toXML(DOMElement $parent) {
assert('is_string($this->namespace)');
assert('is_string($this->location)');
$e = SAML2_Utils::addString($parent, SAML2_Const::NS_MD, 'md:AdditionalMetadataLocation', $this->location);
$e->setAttribute('namespace', $this->namespace);
return $e;
}
}

View File

@ -1,162 +0,0 @@
<?php
/**
* Class representing SAML 2 AffiliationDescriptor element.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_md_AffiliationDescriptor extends SAML2_SignedElementHelper {
/**
* The affiliationOwnerID.
*
* @var string
*/
public $affiliationOwnerID;
/**
* The ID of this element.
*
* @var string|NULL
*/
public $ID;
/**
* How long this element is valid, as a unix timestamp.
*
* @var int|NULL
*/
public $validUntil;
/**
* The length of time this element can be cached, as string.
*
* @var string|NULL
*/
public $cacheDuration;
/**
* Extensions on this element.
*
* Array of extension elements.
*
* @var array
*/
public $Extensions = array();
/**
* The AffiliateMember(s).
*
* Array of entity ID strings.
*
* @var array
*/
public $AffiliateMember = array();
/**
* KeyDescriptor elements.
*
* Array of SAML2_XML_md_KeyDescriptor elements.
*
* @var array
*/
public $KeyDescriptor = array();
/**
* Initialize a AffiliationDescriptor.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
parent::__construct($xml);
if ($xml === NULL) {
return;
}
if (!$xml->hasAttribute('affiliationOwnerID')) {
throw new Exception('Missing affiliationOwnerID on AffiliationDescriptor.');
}
$this->affiliationOwnerID = $xml->getAttribute('affiliationOwnerID');
if ($xml->hasAttribute('ID')) {
$this->ID = $xml->getAttribute('ID');
}
if ($xml->hasAttribute('validUntil')) {
$this->validUntil = SimpleSAML_Utilities::parseSAML2Time($xml->getAttribute('validUntil'));
}
if ($xml->hasAttribute('cacheDuration')) {
$this->cacheDuration = $xml->getAttribute('cacheDuration');
}
$this->Extensions = SAML2_XML_md_Extensions::getList($xml);
$this->AffiliateMember = SAML2_Utils::extractStrings($xml, SAML2_Const::NS_MD, 'AffiliateMember');
if (empty($this->AffiliateMember)) {
throw new Exception('Missing AffiliateMember in AffiliationDescriptor.');
}
foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:KeyDescriptor') as $kd) {
$this->KeyDescriptor[] = new SAML2_XML_md_KeyDescriptor($kd);
}
}
/**
* Add this AffiliationDescriptor to an EntityDescriptor.
*
* @param DOMElement $parent The EntityDescriptor we should append this endpoint to.
* @param string $name The name of the element we should create.
*/
public function toXML(DOMElement $parent) {
assert('is_string($this->affiliationOwnerID)');
assert('is_null($this->ID) || is_string($this->ID)');
assert('is_null($this->validUntil) || is_int($this->validUntil)');
assert('is_null($this->cacheDuration) || is_string($this->cacheDuration)');
assert('is_array($this->Extensions)');
assert('is_array($this->AffiliateMember)');
assert('!empty($this->AffiliateMember)');
assert('is_array($this->KeyDescriptor)');
$e = $parent->ownerDocument->createElementNS(SAML2_Const::NS_MD, 'md:AffiliationDescriptor');
$parent->appendChild($e);
$e->setAttribute('affiliationOwnerID', $this->affiliationOwnerID);
if (isset($this->ID)) {
$e->setAttribute('ID', $this->ID);
}
if (isset($this->validUntil)) {
$e->setAttribute('validUntil', gmdate('Y-m-d\TH:i:s\Z', $this->validUntil));
}
if (isset($this->cacheDuration)) {
$e->setAttribute('cacheDuration', $this->cacheDuration);
}
SAML2_XML_md_Extensions::addList($e, $this->Extensions);
SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:AffiliateMember', FALSE, $this->AffiliateMember);
foreach ($this->KeyDescriptor as $kd) {
$kd->toXML($e);
}
$this->signElement($e, $e->firstChild);
return $e;
}
}

View File

@ -1,128 +0,0 @@
<?php
/**
* Class representing SAML 2 metadata AttributeAuthorityDescriptor.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_md_AttributeAuthorityDescriptor extends SAML2_XML_md_RoleDescriptor {
/**
* List of AttributeService endpoints.
*
* Array with EndpointType objects.
*
* @var array
*/
public $AttributeService = array();
/**
* List of AssertionIDRequestService endpoints.
*
* Array with EndpointType objects.
*
* @var array
*/
public $AssertionIDRequestService = array();
/**
* List of supported NameID formats.
*
* Array of strings.
*
* @var array
*/
public $NameIDFormat = array();
/**
* List of supported attribute profiles.
*
* Array with strings.
*
* @var array
*/
public $AttributeProfile = array();
/**
* List of supported attributes.
*
* Array with SAML2_XML_saml_Attribute objects.
*
* @var array
*/
public $Attribute = array();
/**
* Initialize an IDPSSODescriptor.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
parent::__construct('md:AttributeAuthorityDescriptor', $xml);
if ($xml === NULL) {
return;
}
foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:AttributeService') as $ep) {
$this->AttributeService[] = new SAML2_XML_md_EndpointType($ep);
}
if (empty($this->AttributeService)) {
throw new Exception('Must have at least one AttributeService in AttributeAuthorityDescriptor.');
}
foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:AssertionIDRequestService') as $ep) {
$this->AssertionIDRequestService[] = new SAML2_XML_md_EndpointType($ep);
}
$this->NameIDFormat = SAML2_Utils::extractStrings($xml, SAML2_Const::NS_MD, 'NameIDFormat');
$this->AttributeProfile = SAML2_Utils::extractStrings($xml, SAML2_Const::NS_MD, 'AttributeProfile');
foreach (SAML2_Utils::xpQuery($xml, './saml_assertion:Attribute') as $a) {
$this->Attribute[] = new SAML2_XML_saml_Attribute($a);
}
}
/**
* Add this AttributeAuthorityDescriptor to an EntityDescriptor.
*
* @param DOMElement $parent The EntityDescriptor we should append this IDPSSODescriptor to.
*/
public function toXML(DOMElement $parent) {
assert('is_array($this->AttributeService)');
assert('!empty($this->AttributeService)');
assert('is_array($this->AssertionIDRequestService)');
assert('is_array($this->NameIDFormat)');
assert('is_array($this->AttributeProfile)');
assert('is_array($this->Attribute)');
$e = parent::toXML($parent);
foreach ($this->AttributeService as $ep) {
$ep->toXML($e, 'md:AttributeService');
}
foreach ($this->AssertionIDRequestService as $ep) {
$ep->toXML($e, 'md:AssertionIDRequestService');
}
SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:NameIDFormat', FALSE, $this->NameIDFormat);
SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:AttributeProfile', FALSE, $this->AttributeProfile);
foreach ($this->Attribute as $a) {
$a->toXML($e);
}
return $e;
}
}

View File

@ -1,124 +0,0 @@
<?php
/**
* Class representing SAML 2 Metadata AttributeConsumingService element.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_md_AttributeConsumingService {
/**
* The index of this AttributeConsumingService.
*
* @var int
*/
public $index;
/**
* Whether this is the default AttributeConsumingService.
*
* @var bool|NULL
*/
public $isDefault = NULL;
/**
* The ServiceName of this AttributeConsumingService.
*
* This is an associative array with language => translation.
*
* @var array
*/
public $ServiceName = array();
/**
* The ServiceDescription of this AttributeConsumingService.
*
* This is an associative array with language => translation.
*
* @var array
*/
public $ServiceDescription = array();
/**
* The RequestedAttribute elements.
*
* This is an array of SAML_RequestedAttributeType elements.
*
* @var array
*/
public $RequestedAttribute = array();
/**
* Initialize / parse an AttributeConsumingService.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
if ($xml === NULL) {
return;
}
if (!$xml->hasAttribute('index')) {
throw new Exception('Missing index on AttributeConsumingService.');
}
$this->index = (int)$xml->getAttribute('index');
$this->isDefault = SAML2_Utils::parseBoolean($xml, 'isDefault', NULL);
$this->ServiceName = SAML2_Utils::extractLocalizedStrings($xml, SAML2_Const::NS_MD, 'ServiceName');
if (empty($this->ServiceName)) {
throw new Exception('Missing ServiceName in AttributeConsumingService.');
}
$this->ServiceDescription = SAML2_Utils::extractLocalizedStrings($xml, SAML2_Const::NS_MD, 'ServiceDescription');
foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:RequestedAttribute') as $ra) {
$this->RequestedAttribute[] = new SAML2_XML_md_RequestedAttribute($ra);
}
}
/**
* Convert to DOMElement.
*
* @param DOMElement $parent The element we should append this AttributeConsumingService to.
*/
public function toXML(DOMElement $parent) {
assert('is_int($this->index)');
assert('is_null($this->isDefault) || is_bool($this->isDefault)');
assert('is_array($this->ServiceName)');
assert('is_array($this->ServiceDescription)');
assert('is_array($this->RequestedAttribute)');
$doc = $parent->ownerDocument;
$e = $doc->createElementNS(SAML2_Const::NS_MD, 'md:AttributeConsumingService');
$parent->appendChild($e);
$e->setAttribute('index', (string)$this->index);
if ($this->isDefault === TRUE) {
$e->setAttribute('isDefault', 'true');
} elseif ($this->isDefault === FALSE) {
$e->setAttribute('isDefault', 'false');
}
SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:ServiceName', TRUE, $this->ServiceName);
SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:ServiceDescription', TRUE, $this->ServiceDescription);
foreach ($this->RequestedAttribute as $ra) {
$ra->toXML($e);
}
return $e;
}
}

View File

@ -1,94 +0,0 @@
<?php
/**
* Class representing SAML 2 metadata AuthnAuthorityDescriptor.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_md_AuthnAuthorityDescriptor extends SAML2_XML_md_RoleDescriptor {
/**
* List of AuthnQueryService endpoints.
*
* Array with EndpointType objects.
*
* @var array
*/
public $AuthnQueryService = array();
/**
* List of AssertionIDRequestService endpoints.
*
* Array with EndpointType objects.
*
* @var array
*/
public $AssertionIDRequestService = array();
/**
* List of supported NameID formats.
*
* Array of strings.
*
* @var array
*/
public $NameIDFormat = array();
/**
* Initialize an IDPSSODescriptor.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
parent::__construct('md:AuthnAuthorityDescriptor', $xml);
if ($xml === NULL) {
return;
}
foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:AuthnQueryService') as $ep) {
$this->AuthnQueryService[] = new SAML2_XML_md_EndpointType($ep);
}
if (empty($this->AuthnQueryService)) {
throw new Exception('Must have at least one AuthnQueryService in AuthnAuthorityDescriptor.');
}
foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:AssertionIDRequestService') as $ep) {
$this->AssertionIDRequestService[] = new SAML2_XML_md_EndpointType($ep);
}
$this->NameIDFormat = SAML2_Utils::extractStrings($xml, SAML2_Const::NS_MD, 'NameIDFormat');
}
/**
* Add this IDPSSODescriptor to an EntityDescriptor.
*
* @param DOMElement $parent The EntityDescriptor we should append this AuthnAuthorityDescriptor to.
*/
public function toXML(DOMElement $parent) {
assert('is_array($this->AuthnQueryService)');
assert('!empty($this->AuthnQueryService)');
assert('is_array($this->AssertionIDRequestService)');
assert('is_array($this->NameIDFormat)');
$e = parent::toXML($parent);
foreach ($this->AuthnQueryService as $ep) {
$ep->toXML($e, 'md:AuthnQueryService');
}
foreach ($this->AssertionIDRequestService as $ep) {
$ep->toXML($e, 'md:AssertionIDRequestService');
}
SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:NameIDFormat', FALSE, $this->NameIDFormat);
return $e;
}
}

View File

@ -1,182 +0,0 @@
<?php
/**
* Class representing SAML 2 ContactPerson.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_md_ContactPerson {
/**
* The contact type.
*
* @var string
*/
public $contactType;
/**
* Extensions on this element.
*
* Array of extension elements.
*
* @var array
*/
public $Extensions = array();
/**
* The Company of this contact.
*
* @var string
*/
public $Company = NULL;
/**
* The GivenName of this contact.
*
* @var string
*/
public $GivenName = NULL;
/**
* The SurName of this contact.
*
* @var string
*/
public $SurName = NULL;
/**
* The EmailAddresses of this contact.
*
* @var array
*/
public $EmailAddress = array();
/**
* The TelephoneNumbers of this contact.
*
* @var array
*/
public $TelephoneNumber = array();
/**
* Initialize a ContactPerson element.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
if ($xml === NULL) {
return;
}
if (!$xml->hasAttribute('contactType')) {
throw new Exception('Missing contactType on ContactPerson.');
}
$this->contactType = $xml->getAttribute('contactType');
$this->Extensions = SAML2_XML_md_Extensions::getList($xml);
$this->Company = self::getStringElement($xml, 'Company');
$this->GivenName = self::getStringElement($xml, 'GivenName');
$this->SurName = self::getStringElement($xml, 'SurName');
$this->EmailAddress = self::getStringElements($xml, 'EmailAddress');
$this->TelephoneNumber = self::getStringElements($xml, 'TelephoneNumber');
}
/**
* Retrieve the value of a child DOMElements as an array of strings.
*
* @param DOMElement $parent The parent element.
* @param string $name The name of the child elements.
* @return array The value of the child elements.
*/
private static function getStringElements(DOMElement $parent, $name) {
assert('is_string($name)');
$e = SAML2_Utils::xpQuery($parent, './saml_metadata:' . $name);
$ret = array();
foreach ($e as $i) {
$ret[] = $i->textContent;
}
return $ret;
}
/**
* Retrieve the value of a child DOMElement as a string.
*
* @param DOMElement $parent The parent element.
* @param string $name The name of the child element.
* @return string|NULL The value of the child element.
*/
private static function getStringElement(DOMElement $parent, $name) {
assert('is_string($name)');
$e = self::getStringElements($parent, $name);
if (empty($e)) {
return NULL;
}
if (count($e) > 1) {
throw new Exception('More than one ' . $name . ' in ' . $parent->tagName);
}
return $e[0];
}
/**
* Convert this ContactPerson to XML.
*
* @param DOMElement $parent The element we should add this contact to.
* @return DOMElement The new ContactPerson-element.
*/
public function toXML(DOMElement $parent) {
assert('is_string($this->contactType)');
assert('is_array($this->Extensions)');
assert('is_null($this->Company) || is_string($this->Company)');
assert('is_null($this->GivenName) || is_string($this->GivenName)');
assert('is_null($this->SurName) || is_string($this->SurName)');
assert('is_array($this->EmailAddress)');
assert('is_array($this->TelephoneNumber)');
$doc = $parent->ownerDocument;
$e = $doc->createElementNS(SAML2_Const::NS_MD, 'md:ContactPerson');
$parent->appendChild($e);
$e->setAttribute('contactType', $this->contactType);
SAML2_XML_md_Extensions::addList($e, $this->Extensions);
if (isset($this->Company)) {
SAML2_Utils::addString($e, SAML2_Const::NS_MD, 'md:Company', $this->Company);
}
if (isset($this->GivenName)) {
SAML2_Utils::addString($e, SAML2_Const::NS_MD, 'md:GivenName', $this->GivenName);
}
if (isset($this->SurName)) {
SAML2_Utils::addString($e, SAML2_Const::NS_MD, 'md:SurName', $this->SurName);
}
if (!empty($this->EmailAddress)) {
SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:EmailAddress', FALSE, $this->EmailAddress);
}
if (!empty($this->TelephoneNumber)) {
SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:TelephoneNumber', FALSE, $this->TelephoneNumber);
}
return $e;
}
}

View File

@ -1,187 +0,0 @@
<?php
/**
* Class representing SAML 2 EndpointType.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_md_EndpointType {
/**
* The binding for this endpoint.
*
* @var string
*/
public $Binding;
/**
* The URI to this endpoint.
*
* @var string
*/
public $Location;
/**
* The URI where responses can be delivered.
*
* @var string|NULL
*/
public $ResponseLocation = NULL;
/**
* Extra (namespace qualified) attributes.
*
* @var array
*/
private $attributes = array();
/**
* Initialize an EndpointType.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
if ($xml === NULL) {
return;
}
if (!$xml->hasAttribute('Binding')) {
throw new Exception('Missing Binding on ' . $xml->tagName);
}
$this->Binding = $xml->getAttribute('Binding');
if (!$xml->hasAttribute('Location')) {
throw new Exception('Missing Location on ' . $xml->tagName);
}
$this->Location = $xml->getAttribute('Location');
if ($xml->hasAttribute('ResponseLocation')) {
$this->ResponseLocation = $xml->getAttribute('ResponseLocation');
}
foreach ($xml->attributes as $a) {
if ($a->namespaceURI === NULL) {
continue; /* Not namespace-qualified -- skip. */
}
$fullName = '{' . $a->namespaceURI . '}' . $a->localName;
$this->attributes[$fullName] = array(
'qualifiedName' => $a->nodeName,
'namespaceURI' => $a->namespaceURI,
'value' => $a->value,
);
}
}
/**
* Check if a namespace-qualified attribute exists.
*
* @param string $namespaceURI The namespace URI.
* @param string $localName The local name.
* @return boolean TRUE if the attribute exists, FALSE if not.
*/
public function hasAttributeNS($namespaceURI, $localName) {
assert('is_string($namespaceURI)');
assert('is_string($localName)');
$fullName = '{' . $namespaceURI . '}' . $localName;
return isset($this->attributes[$fullName]);
}
/**
* Get a namespace-qualified attribute.
*
* @param string $namespaceURI The namespace URI.
* @param string $localName The local name.
* @return string The value of the attribute, or an empty string if the attribute does not exist.
*/
public function getAttributeNS($namespaceURI, $localName) {
assert('is_string($namespaceURI)');
assert('is_string($localName)');
$fullName = '{' . $namespaceURI . '}' . $localName;
if (!isset($this->attributes[$fullName])) {
return '';
}
return $this->attributes[$fullName]['value'];
}
/**
* Get a namespace-qualified attribute.
*
* @param string $namespaceURI The namespace URI.
* @param string $qualifiedName The local name.
* @param string $value The attribute value.
*/
public function setAttributeNS($namespaceURI, $qualifiedName, $value) {
assert('is_string($namespaceURI)');
assert('is_string($qualifiedName)');
$name = explode(':', $qualifiedName, 2);
if (count($name) < 2) {
throw new Exception('Not a qualified name.');
}
$localName = $name[1];
$fullName = '{' . $namespaceURI . '}' . $localName;
$this->attributes[$fullName] = array(
'qualifiedName' => $qualifiedName,
'namespaceURI' => $namespaceURI,
'value' => $value,
);
}
/**
* Remove a namespace-qualified attribute.
*
* @param string $namespaceURI The namespace URI.
* @param string $localName The local name.
*/
public function removeAttributeNS($namespaceURI, $localName) {
assert('is_string($namespaceURI)');
assert('is_string($localName)');
$fullName = '{' . $namespaceURI . '}' . $localName;
unset($this->attributes[$fullName]);
}
/**
* Add this endpoint to an XML element.
*
* @param DOMElement $parent The element we should append this endpoint to.
* @param string $name The name of the element we should create.
*/
public function toXML(DOMElement $parent, $name) {
assert('is_string($name)');
assert('is_string($this->Binding)');
assert('is_string($this->Location)');
assert('is_null($this->ResponseLocation) || is_string($this->ResponseLocation)');
$e = $parent->ownerDocument->createElementNS(SAML2_Const::NS_MD, $name);
$parent->appendChild($e);
$e->setAttribute('Binding', $this->Binding);
$e->setAttribute('Location', $this->Location);
if (isset($this->ResponseLocation)) {
$e->setAttribute('ResponseLocation', $this->ResponseLocation);
}
foreach ($this->attributes as $a) {
$e->setAttributeNS($a['namespaceURI'], $a['qualifiedName'], $a['value']);
}
return $e;
}
}

View File

@ -1,147 +0,0 @@
<?php
/**
* Class representing SAML 2 EntitiesDescriptor element.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_md_EntitiesDescriptor extends SAML2_SignedElementHelper {
/**
* The ID of this element.
*
* @var string|NULL
*/
public $ID;
/**
* How long this element is valid, as a unix timestamp.
*
* @var int|NULL
*/
public $validUntil;
/**
* The length of time this element can be cached, as string.
*
* @var string|NULL
*/
public $cacheDuration;
/**
* The name of this entity collection.
*
* @var string|NULL
*/
public $Name;
/**
* Extensions on this element.
*
* Array of extension elements.
*
* @var array
*/
public $Extensions = array();
/**
* Child EntityDescriptor and EntitiesDescriptor elements.
*
* @var array
*/
public $children = array();
/**
* Initialize an EntitiesDescriptor.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
parent::__construct($xml);
if ($xml === NULL) {
return;
}
if ($xml->hasAttribute('ID')) {
$this->ID = $xml->getAttribute('ID');
}
if ($xml->hasAttribute('validUntil')) {
$this->validUntil = SimpleSAML_Utilities::parseSAML2Time($xml->getAttribute('validUntil'));
}
if ($xml->hasAttribute('cacheDuration')) {
$this->cacheDuration = $xml->getAttribute('cacheDuration');
}
if ($xml->hasAttribute('Name')) {
$this->Name = $xml->getAttribute('Name');
}
$this->Extensions = SAML2_XML_md_Extensions::getList($xml);
foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:EntityDescriptor|./saml_metadata:EntitiesDescriptor') as $node) {
if ($node->localName === 'EntityDescriptor') {
$this->children[] = new SAML2_XML_md_EntityDescriptor($node);
} else {
$this->children[] = new SAML2_XML_md_EntitiesDescriptor($node);
}
}
}
/**
* Convert this EntitiesDescriptor to XML.
*
* @param DOMElement|NULL $parent The EntitiesDescriptor we should append this EntitiesDescriptor to.
*/
public function toXML(DOMElement $parent = NULL) {
assert('is_null($this->ID) || is_string($this->ID)');
assert('is_null($this->validUntil) || is_int($this->validUntil)');
assert('is_null($this->cacheDuration) || is_string($this->cacheDuration)');
assert('is_null($this->Name) || is_string($this->Name)');
assert('is_array($this->Extensions)');
assert('is_array($this->children)');
if ($parent === NULL) {
$doc = new DOMDocument();
$e = $doc->createElementNS(SAML2_Const::NS_MD, 'md:EntitiesDescriptor');
$doc->appendChild($e);
} else {
$e = $parent->ownerDocument->createElementNS(SAML2_Const::NS_MD, 'md:EntitiesDescriptor');
$parent->appendChild($e);
}
if (isset($this->ID)) {
$e->setAttribute('ID', $this->ID);
}
if (isset($this->validUntil)) {
$e->setAttribute('validUntil', gmdate('Y-m-d\TH:i:s\Z', $this->validUntil));
}
if (isset($this->cacheDuration)) {
$e->setAttribute('cacheDuration', $this->cacheDuration);
}
if (isset($this->Name)) {
$e->setAttribute('Name', $this->Name);
}
SAML2_XML_md_Extensions::addList($e, $this->Extensions);
foreach ($this->children as $node) {
$node->toXML($e);
}
$this->signElement($e, $e->firstChild);
return $e;
}
}

View File

@ -1,252 +0,0 @@
<?php
/**
* Class representing SAML 2 EntityDescriptor element.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_md_EntityDescriptor extends SAML2_SignedElementHelper {
/**
* The entityID this EntityDescriptor represents.
*
* @var string
*/
public $entityID;
/**
* The ID of this element.
*
* @var string|NULL
*/
public $ID;
/**
* How long this element is valid, as a unix timestamp.
*
* @var int|NULL
*/
public $validUntil;
/**
* The length of time this element can be cached, as string.
*
* @var string|NULL
*/
public $cacheDuration;
/**
* Extensions on this element.
*
* Array of extension elements.
*
* @var array
*/
public $Extensions = array();
/**
* Array with all roles for this entity.
*
* Array of SAML2_XML_md_RoleDescriptor objects (and subclasses of RoleDescriptor).
*
* @var array
*/
public $RoleDescriptor = array();
/**
* AffiliationDescriptor of this entity.
*
* @var SAML2_XML_md_AffiliationDescriptor|NULL
*/
public $AffiliationDescriptor = NULL;
/**
* Organization of this entity.
*
* @var SAML2_XML_md_Organization|NULL
*/
public $Organization = NULL;
/**
* ContactPerson elements for this entity.
*
* @var array
*/
public $ContactPerson = array();
/**
* AdditionalMetadataLocation elements for this entity.
*
* @var array
*/
public $AdditionalMetadataLocation = array();
/**
* Initialize an EntitiyDescriptor.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
parent::__construct($xml);
if ($xml === NULL) {
return;
}
if (!$xml->hasAttribute('entityID')) {
throw new Exception('Missing required attribute entityID on EntityDescriptor.');
}
$this->entityID = $xml->getAttribute('entityID');
if ($xml->hasAttribute('ID')) {
$this->ID = $xml->getAttribute('ID');
}
if ($xml->hasAttribute('validUntil')) {
$this->validUntil = SimpleSAML_Utilities::parseSAML2Time($xml->getAttribute('validUntil'));
}
if ($xml->hasAttribute('cacheDuration')) {
$this->cacheDuration = $xml->getAttribute('cacheDuration');
}
$this->Extensions = SAML2_XML_md_Extensions::getList($xml);
for ($node = $xml->firstChild; $node !== NULL; $node = $node->nextSibling) {
if (!($node instanceof DOMElement)) {
continue;
}
if ($node->namespaceURI !== SAML2_Const::NS_MD) {
continue;
}
switch ($node->localName) {
case 'RoleDescriptor':
$this->RoleDescriptor[] = new SAML2_XML_md_UnknownRoleDescriptor($node);
break;
case 'IDPSSODescriptor':
$this->RoleDescriptor[] = new SAML2_XML_md_IDPSSODescriptor($node);
break;
case 'SPSSODescriptor':
$this->RoleDescriptor[] = new SAML2_XML_md_SPSSODescriptor($node);
break;
case 'AuthnAuthorityDescriptor':
$this->RoleDescriptor[] = new SAML2_XML_md_AuthnAuthorityDescriptor($node);
break;
case 'AttributeAuthorityDescriptor':
$this->RoleDescriptor[] = new SAML2_XML_md_AttributeAuthorityDescriptor($node);
break;
case 'PDPDescriptor':
$this->RoleDescriptor[] = new SAML2_XML_md_PDPDescriptor($node);
break;
}
}
$affiliationDescriptor = SAML2_Utils::xpQuery($xml, './saml_metadata:AffiliationDescriptor');
if (count($affiliationDescriptor) > 1) {
throw new Exception('More than one AffiliationDescriptor in the entity.');
} elseif (!empty($affiliationDescriptor)) {
$this->AffiliationDescriptor = new SAML2_XML_md_AffiliationDescriptor($affiliationDescriptor[0]);
}
if (empty($this->RoleDescriptor) && is_null($this->AffiliationDescriptor)) {
throw new Exception('Must have either one of the RoleDescriptors or an AffiliationDescriptor in EntityDescriptor.');
} elseif (!empty($this->RoleDescriptor) && !is_null($this->AffiliationDescriptor)) {
throw new Exception('AffiliationDescriptor cannot be combined with other RoleDescriptor elements in EntityDescriptor.');
}
$organization = SAML2_Utils::xpQuery($xml, './saml_metadata:Organization');
if (count($organization) > 1) {
throw new Exception('More than one Organization in the entity.');
} elseif (!empty($organization)) {
$this->Organization = new SAML2_XML_md_Organization($organization[0]);
}
foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:ContactPerson') as $cp) {
$this->ContactPerson[] = new SAML2_XML_md_ContactPerson($cp);
}
foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:AdditionalMetadataLocation') as $aml) {
$this->AdditionalMetadataLocation[] = new SAML2_XML_md_AdditionalMetadataLocation($aml);
}
}
/**
* Create this EntityDescriptor.
*
* @param DOMElement|NULL $parent The EntitiesDescriptor we should append this EntityDescriptor to.
*/
public function toXML(DOMElement $parent = NULL) {
assert('is_string($this->entityID)');
assert('is_null($this->ID) || is_string($this->ID)');
assert('is_null($this->validUntil) || is_int($this->validUntil)');
assert('is_null($this->cacheDuration) || is_string($this->cacheDuration)');
assert('is_array($this->Extensions)');
assert('is_array($this->RoleDescriptor)');
assert('is_null($this->AffiliationDescriptor) || $this->AffiliationDescriptor instanceof SAML2_XML_md_AffiliationDescriptor');
assert('is_null($this->Organization) || $this->Organization instanceof SAML2_XML_md_Organization');
assert('is_array($this->ContactPerson)');
assert('is_array($this->AdditionalMetadataLocation)');
if ($parent === NULL) {
$doc = new DOMDocument();
$e = $doc->createElementNS(SAML2_Const::NS_MD, 'md:EntityDescriptor');
$doc->appendChild($e);
} else {
$e = $parent->ownerDocument->createElementNS(SAML2_Const::NS_MD, 'md:EntityDescriptor');
$parent->appendChild($e);
}
$e->setAttribute('entityID', $this->entityID);
if (isset($this->ID)) {
$e->setAttribute('ID', $this->ID);
}
if (isset($this->validUntil)) {
$e->setAttribute('validUntil', gmdate('Y-m-d\TH:i:s\Z', $this->validUntil));
}
if (isset($this->cacheDuration)) {
$e->setAttribute('cacheDuration', $this->cacheDuration);
}
SAML2_XML_md_Extensions::addList($e, $this->Extensions);
foreach ($this->RoleDescriptor as $n) {
$n->toXML($e);
}
if (isset($this->AffiliationDescriptor)) {
$this->AffiliationDescriptor->toXML($e);
}
if (isset($this->Organization)) {
$this->Organization->toXML($e);
}
foreach ($this->ContactPerson as $cp) {
$cp->toXML($e);
}
foreach ($this->AdditionalMetadataLocation as $n) {
$n->toXML($e);
}
$this->signElement($e, $e->firstChild);
return $e;
}
}

View File

@ -1,62 +0,0 @@
<?php
/**
* Class for handling SAML2 metadata extensions.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_md_Extensions {
/**
* Get a list of Extensions in the given element.
*
* @param DOMElement $parent The element that may contain the md:Extensions element.
* @return array Array of extensions.
*/
public static function getList(DOMElement $parent) {
$ret = array();
foreach (SAML2_Utils::xpQuery($parent, './saml_metadata:Extensions/*') as $node) {
if ($node->namespaceURI === SAML2_XML_shibmd_Scope::NS && $node->localName === 'Scope') {
$ret[] = new SAML2_XML_shibmd_Scope($node);
} elseif ($node->namespaceURI === SAML2_XML_mdattr_EntityAttributes::NS && $node->localName === 'EntityAttributes') {
$ret[] = new SAML2_XML_mdattr_EntityAttributes($node);
} elseif ($node->namespaceURI === SAML2_XML_mdrpi_Common::NS_MDRPI && $node->localName === 'RegistrationInfo') {
$ret[] = new SAML2_XML_mdrpi_RegistrationInfo($node);
} elseif ($node->namespaceURI === SAML2_XML_mdrpi_Common::NS_MDRPI && $node->localName === 'PublicationInfo') {
$ret[] = new SAML2_XML_mdrpi_PublicationInfo($node);
} elseif ($node->namespaceURI === SAML2_XML_mdui_UIInfo::NS && $node->localName === 'UIInfo') {
$ret[] = new SAML2_XML_mdui_UIInfo($node);
} elseif ($node->namespaceURI === SAML2_XML_mdui_DiscoHints::NS && $node->localName === 'DiscoHints') {
$ret[] = new SAML2_XML_mdui_DiscoHints($node);
} else {
$ret[] = new SAML2_XML_Chunk($node);
}
}
return $ret;
}
/**
* Add a list of Extensions to the given element.
*
* @param DOMElement $parent The element we should add the extensions to.
* @param array $extensions List of extension objects.
*/
public static function addList(DOMElement $parent, array $extensions) {
if (empty($extensions)) {
return;
}
$extElement = $parent->ownerDocument->createElementNS(SAML2_Const::NS_MD, 'md:Extensions');
$parent->appendChild($extElement);
foreach ($extensions as $ext) {
$ext->toXML($extElement);
}
}
}

View File

@ -1,145 +0,0 @@
<?php
/**
* Class representing SAML 2 IDPSSODescriptor.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_md_IDPSSODescriptor extends SAML2_XML_md_SSODescriptorType {
/**
* Whether AuthnRequests sent to this IdP should be signed.
*
* @var bool|NULL
*/
public $WantAuthnRequestsSigned = NULL;
/**
* List of SingleSignOnService endpoints.
*
* Array with EndpointType objects.
*
* @var array
*/
public $SingleSignOnService = array();
/**
* List of NameIDMappingService endpoints.
*
* Array with EndpointType objects.
*
* @var array
*/
public $NameIDMappingService = array();
/**
* List of AssertionIDRequestService endpoints.
*
* Array with EndpointType objects.
*
* @var array
*/
public $AssertionIDRequestService = array();
/**
* List of supported attribute profiles.
*
* Array with strings.
*
* @var array
*/
public $AttributeProfile = array();
/**
* List of supported attributes.
*
* Array with SAML2_XML_saml_Attribute objects.
*
* @var array
*/
public $Attribute = array();
/**
* Initialize an IDPSSODescriptor.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
parent::__construct('md:IDPSSODescriptor', $xml);
if ($xml === NULL) {
return;
}
$this->WantAuthnRequestsSigned = SAML2_Utils::parseBoolean($xml, 'WantAuthnRequestsSigned', NULL);
foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:SingleSignOnService') as $ep) {
$this->SingleSignOnService[] = new SAML2_XML_md_EndpointType($ep);
}
foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:NameIDMappingService') as $ep) {
$this->NameIDMappingService[] = new SAML2_XML_md_EndpointType($ep);
}
foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:AssertionIDRequestService') as $ep) {
$this->AssertionIDRequestService[] = new SAML2_XML_md_EndpointType($ep);
}
$this->AttributeProfile = SAML2_Utils::extractStrings($xml, SAML2_Const::NS_MD, 'AttributeProfile');
foreach (SAML2_Utils::xpQuery($xml, './saml_assertion:Attribute') as $a) {
$this->Attribute[] = new SAML2_XML_saml_Attribute($a);
}
}
/**
* Add this IDPSSODescriptor to an EntityDescriptor.
*
* @param DOMElement $parent The EntityDescriptor we should append this IDPSSODescriptor to.
*/
public function toXML(DOMElement $parent) {
assert('is_null($this->WantAuthnRequestsSigned) || is_bool($this->WantAuthnRequestsSigned)');
assert('is_array($this->SingleSignOnService)');
assert('is_array($this->NameIDMappingService)');
assert('is_array($this->AssertionIDRequestService)');
assert('is_array($this->AttributeProfile)');
assert('is_array($this->Attribute)');
$e = parent::toXML($parent);
if ($this->WantAuthnRequestsSigned === TRUE) {
$e->setAttribute('WantAuthnRequestsSigned', 'true');
} elseif ($this->WantAuthnRequestsSigned === FALSE) {
$e->setAttribute('WantAuthnRequestsSigned', 'false');
}
foreach ($this->SingleSignOnService as $ep) {
$ep->toXML($e, 'md:SingleSignOnService');
}
foreach ($this->NameIDMappingService as $ep) {
$ep->toXML($e, 'md:NameIDMappingService');
}
foreach ($this->AssertionIDRequestService as $ep) {
$ep->toXML($e, 'md:AssertionIDRequestService');
}
SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:AttributeProfile', FALSE, $this->AttributeProfile);
foreach ($this->Attribute as $a) {
$a->toXML($e);
}
return $e;
}
}

View File

@ -1,71 +0,0 @@
<?php
/**
* Class representing SAML 2 IndexedEndpointType.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_md_IndexedEndpointType extends SAML2_XML_md_EndpointType {
/**
* The index for this endpoint.
*
* @var int
*/
public $index;
/**
* Whether this endpoint is the default.
*
* @var bool|NULL
*/
public $isDefault = NULL;
/**
* Initialize an IndexedEndpointType.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
parent::__construct($xml);
if ($xml === NULL) {
return;
}
if (!$xml->hasAttribute('index')) {
throw new Exception('Missing index on ' . $xml->tagName);
}
$this->index = (int)$xml->getAttribute('index');
$this->isDefault = SAML2_Utils::parseBoolean($xml, 'isDefault', NULL);
}
/**
* Add this endpoint to an XML element.
*
* @param DOMElement $parent The element we should append this endpoint to.
* @param string $name The name of the element we should create.
*/
public function toXML(DOMElement $parent, $name) {
assert('is_string($name)');
assert('is_int($this->index)');
assert('is_null($this->isDefault) || is_bool($this->isDefault)');
$e = parent::toXML($parent, $name);
$e->setAttribute('index', (string)$this->index);
if ($this->isDefault === TRUE) {
$e->setAttribute('isDefault', 'true');
} elseif ($this->isDefault === FALSE) {
$e->setAttribute('isDefault', 'false');
}
return $e;
}
}

View File

@ -1,97 +0,0 @@
<?php
/**
* Class representing a KeyDescriptor element.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_md_KeyDescriptor {
/**
* What this key can be used for.
*
* 'encryption', 'signing' or NULL.
*
* @var string|NULL
*/
public $use;
/**
* The KeyInfo for this key.
*
* @var SAML2_XML_ds_KeyInfo
*/
public $KeyInfo;
/**
* Supported EncryptionMethods.
*
* Array of SAML2_XML_Chunk objects.
*
* @var array
*/
public $EncryptionMethod = array();
/**
* Initialize an KeyDescriptor.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
if ($xml === NULL) {
return;
}
if ($xml->hasAttribute('use')) {
$this->use = $xml->getAttribute('use');
}
$keyInfo = SAML2_Utils::xpQuery($xml, './ds:KeyInfo');
if (count($keyInfo) > 1) {
throw new Exception('More than one ds:KeyInfo in the KeyDescriptor.');
} elseif (empty($keyInfo)) {
throw new Exception('No ds:KeyInfo in the KeyDescriptor.');
}
$this->KeyInfo = new SAML2_XML_ds_KeyInfo($keyInfo[0]);
foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:EncryptionMethod') as $em) {
$this->EncryptionMethod[] = new SAML2_XML_Chunk($em);
}
}
/**
* Convert this KeyDescriptor to XML.
*
* @param DOMElement $parent The element we should append this KeyDescriptor to.
*/
public function toXML(DOMElement $parent) {
assert('is_null($this->use) || is_string($this->use)');
assert('$this->KeyInfo instanceof SAML2_XML_ds_KeyInfo');
assert('is_array($this->EncryptionMethod)');
$doc = $parent->ownerDocument;
$e = $doc->createElementNS(SAML2_Const::NS_MD, 'md:KeyDescriptor');
$parent->appendChild($e);
if (isset($this->use)) {
$e->setAttribute('use', $this->use);
}
$this->KeyInfo->toXML($e);
foreach ($this->EncryptionMethod as $em) {
$em->toXML($e);
}
return $e;
}
}

View File

@ -1,105 +0,0 @@
<?php
/**
* Class representing SAML 2 Organization element.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_md_Organization {
/**
* Extensions on this element.
*
* Array of extension elements.
*
* @var array
*/
public $Extensions = array();
/**
* The OrganizationName, as an array of language => translation.
*
* @var array
*/
public $OrganizationName = array();
/**
* The OrganizationDisplayName, as an array of language => translation.
*
* @var array
*/
public $OrganizationDisplayName = array();
/**
* The OrganizationURL, as an array of language => translation.
*
* @var array
*/
public $OrganizationURL = array();
/**
* Initialize an Organization element.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
if ($xml === NULL) {
return;
}
$this->Extensions = SAML2_XML_md_Extensions::getList($xml);
$this->OrganizationName = SAML2_Utils::extractLocalizedStrings($xml, SAML2_Const::NS_MD, 'OrganizationName');
if (empty($this->OrganizationName)) {
$this->OrganizationName = array('invalid' => '');
}
$this->OrganizationDisplayName = SAML2_Utils::extractLocalizedStrings($xml, SAML2_Const::NS_MD, 'OrganizationDisplayName');
if (empty($this->OrganizationDisplayName)) {
$this->OrganizationDisplayName = array('invalid' => '');
}
$this->OrganizationURL = SAML2_Utils::extractLocalizedStrings($xml, SAML2_Const::NS_MD, 'OrganizationURL');
if (empty($this->OrganizationURL)) {
$this->OrganizationURL = array('invalid' => '');
}
}
/**
* Convert this Organization to XML.
*
* @param DOMElement $parent The element we should add this organization to.
* @return DOMElement This Organization-element.
*/
public function toXML(DOMElement $parent) {
assert('is_array($this->Extensions)');
assert('is_array($this->OrganizationName)');
assert('!empty($this->OrganizationName)');
assert('is_array($this->OrganizationDisplayName)');
assert('!empty($this->OrganizationDisplayName)');
assert('is_array($this->OrganizationURL)');
assert('!empty($this->OrganizationURL)');
$doc = $parent->ownerDocument;
$e = $doc->createElementNS(SAML2_Const::NS_MD, 'md:Organization');
$parent->appendChild($e);
SAML2_XML_md_Extensions::addList($e, $this->Extensions);
SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:OrganizationName', TRUE, $this->OrganizationName);
SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:OrganizationDisplayName', TRUE, $this->OrganizationDisplayName);
SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:OrganizationURL', TRUE, $this->OrganizationURL);
return $e;
}
}

View File

@ -1,94 +0,0 @@
<?php
/**
* Class representing SAML 2 metadata PDPDescriptor.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_md_PDPDescriptor extends SAML2_XML_md_RoleDescriptor {
/**
* List of AuthzService endpoints.
*
* Array with EndpointType objects.
*
* @var array
*/
public $AuthzService = array();
/**
* List of AssertionIDRequestService endpoints.
*
* Array with EndpointType objects.
*
* @var array
*/
public $AssertionIDRequestService = array();
/**
* List of supported NameID formats.
*
* Array of strings.
*
* @var array
*/
public $NameIDFormat = array();
/**
* Initialize an IDPSSODescriptor.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
parent::__construct('md:PDPDescriptor', $xml);
if ($xml === NULL) {
return;
}
foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:AuthzService') as $ep) {
$this->AuthzService[] = new SAML2_XML_md_EndpointType($ep);
}
if (empty($this->AuthzService)) {
throw new Exception('Must have at least one AuthzService in PDPDescriptor.');
}
foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:AssertionIDRequestService') as $ep) {
$this->AssertionIDRequestService[] = new SAML2_XML_md_EndpointType($ep);
}
$this->NameIDFormat = SAML2_Utils::extractStrings($xml, SAML2_Const::NS_MD, 'NameIDFormat');
}
/**
* Add this PDPDescriptor to an EntityDescriptor.
*
* @param DOMElement $parent The EntityDescriptor we should append this IDPSSODescriptor to.
*/
public function toXML(DOMElement $parent) {
assert('is_array($this->AuthzService)');
assert('!empty($this->AuthzService)');
assert('is_array($this->AssertionIDRequestService)');
assert('is_array($this->NameIDFormat)');
$e = parent::toXML($parent);
foreach ($this->AuthzService as $ep) {
$ep->toXML($e, 'md:AuthzService');
}
foreach ($this->AssertionIDRequestService as $ep) {
$ep->toXML($e, 'md:AssertionIDRequestService');
}
SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:NameIDFormat', FALSE, $this->NameIDFormat);
return $e;
}
}

View File

@ -1,54 +0,0 @@
<?php
/**
* Class representing SAML 2 metadata RequestedAttribute.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_md_RequestedAttribute extends SAML2_XML_saml_Attribute {
/**
* Whether this attribute is required.
*
* @var bool|NULL
*/
public $isRequired = NULL;
/**
* Initialize an RequestedAttribute.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
parent::__construct($xml);
if ($xml === NULL) {
return;
}
$this->isRequired = SAML2_Utils::parseBoolean($xml, 'isRequired', NULL);
}
/**
* Convert this RequestedAttribute to XML.
*
* @param DOMElement $parent The element we should append this RequestedAttribute to.
*/
public function toXML(DOMElement $parent) {
assert('is_bool($this->isRequired) || is_null($this->isRequired)');
$e = $this->toXMLInternal($parent, SAML2_Const::NS_MD, 'md:RequestedAttribute');
if ($this->isRequired === TRUE) {
$e->setAttribute('isRequired', 'true');
} elseif ($this->isRequired === FALSE) {
$e->setAttribute('isRequired', 'false');
}
return $e;
}
}

View File

@ -1,208 +0,0 @@
<?php
/**
* Class representing SAML 2 RoleDescriptor element.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_md_RoleDescriptor extends SAML2_SignedElementHelper {
/**
* The name of this descriptor element.
*
* @var string
*/
private $elementName;
/**
* The ID of this element.
*
* @var string|NULL
*/
public $ID;
/**
* How long this element is valid, as a unix timestamp.
*
* @var int|NULL
*/
public $validUntil;
/**
* The length of time this element can be cached, as string.
*
* @var string|NULL
*/
public $cacheDuration;
/**
* List of supported protocols.
*
* @var array
*/
public $protocolSupportEnumeration = array();
/**
* Error URL for this role.
*
* @var string|NULL
*/
public $errorURL;
/**
* Extensions on this element.
*
* Array of extension elements.
*
* @var array
*/
public $Extensions = array();
/**
* KeyDescriptor elements.
*
* Array of SAML2_XML_md_KeyDescriptor elements.
*
* @var array
*/
public $KeyDescriptor = array();
/**
* Organization of this role.
*
* @var SAML2_XML_md_Organization|NULL
*/
public $Organization = NULL;
/**
* ContactPerson elements for this role.
*
* Array of SAML2_XML_md_ContactPerson objects.
*
* @var array
*/
public $ContactPerson = array();
/**
* Initialize a RoleDescriptor.
*
* @param string $elementName The name of this element.
* @param DOMElement|NULL $xml The XML element we should load.
*/
protected function __construct($elementName, DOMElement $xml = NULL) {
assert('is_string($elementName)');
parent::__construct($xml);
$this->elementName = $elementName;
if ($xml === NULL) {
return;
}
if ($xml->hasAttribute('ID')) {
$this->ID = $xml->getAttribute('ID');
}
if ($xml->hasAttribute('validUntil')) {
$this->validUntil = SimpleSAML_Utilities::parseSAML2Time($xml->getAttribute('validUntil'));
}
if ($xml->hasAttribute('cacheDuration')) {
$this->cacheDuration = $xml->getAttribute('cacheDuration');
}
if (!$xml->hasAttribute('protocolSupportEnumeration')) {
throw new Exception('Missing protocolSupportEnumeration attribute on ' . $xml->localName);
}
$this->protocolSupportEnumeration = preg_split('/[\s]+/', $xml->getAttribute('protocolSupportEnumeration'));
if ($xml->hasAttribute('errorURL')) {
$this->errorURL = $xml->getAttribute('errorURL');
}
$this->Extensions = SAML2_XML_md_Extensions::getList($xml);
foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:KeyDescriptor') as $kd) {
$this->KeyDescriptor[] = new SAML2_XML_md_KeyDescriptor($kd);
}
$organization = SAML2_Utils::xpQuery($xml, './saml_metadata:Organization');
if (count($organization) > 1) {
throw new Exception('More than one Organization in the entity.');
} elseif (!empty($organization)) {
$this->Organization = new SAML2_XML_md_Organization($organization[0]);
}
foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:ContactPerson') as $cp) {
$this->contactPersons[] = new SAML2_XML_md_ContactPerson($cp);
}
}
/**
* Add this RoleDescriptor to an EntityDescriptor.
*
* @param DOMElement $parent The EntityDescriptor we should append this endpoint to.
* @param string $name The name of the element we should create.
*/
protected function toXML(DOMElement $parent) {
assert('is_null($this->ID) || is_string($this->ID)');
assert('is_null($this->validUntil) || is_int($this->validUntil)');
assert('is_null($this->cacheDuration) || is_string($this->cacheDuration)');
assert('is_array($this->protocolSupportEnumeration)');
assert('is_null($this->errorURL) || is_string($this->errorURL)');
assert('is_array($this->Extensions)');
assert('is_array($this->KeyDescriptor)');
assert('is_null($this->Organization) || $this->Organization instanceof SAML2_XML_md_Organization');
assert('is_array($this->ContactPerson)');
$e = $parent->ownerDocument->createElementNS(SAML2_Const::NS_MD, $this->elementName);
$parent->appendChild($e);
if (isset($this->ID)) {
$e->setAttribute('ID', $this->ID);
}
if (isset($this->validUntil)) {
$e->setAttribute('validUntil', gmdate('Y-m-d\TH:i:s\Z', $this->validUntil));
}
if (isset($this->cacheDuration)) {
$e->setAttribute('cacheDuration', $this->cacheDuration);
}
$e->setAttribute('protocolSupportEnumeration', implode(' ', $this->protocolSupportEnumeration));
if (isset($this->errorURL)) {
$e->setAttribute('errorURL', $this->errorURL);
}
SAML2_XML_md_Extensions::addList($e, $this->Extensions);
foreach ($this->KeyDescriptor as $kd) {
$kd->toXML($e);
}
if (isset($this->Organization)) {
$this->Organization->toXML($e);
}
foreach ($this->ContactPerson as $cp) {
$cp->toXML($e);
}
return $e;
}
}

View File

@ -1,107 +0,0 @@
<?php
/**
* Class representing SAML 2 SPSSODescriptor.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_md_SPSSODescriptor extends SAML2_XML_md_SSODescriptorType {
/**
* Whether this SP signs authentication requests.
*
* @var bool|NULL
*/
public $AuthnRequestsSigned = NULL;
/**
* Whether this SP wants the Assertion elements to be signed.
*
* @var bool|NULL
*/
public $WantAssertionsSigned = NULL;
/**
* List of AssertionConsumerService endpoints for this SP.
*
* Array with IndexedEndpointType objects.
*
* @var array
*/
public $AssertionConsumerService = array();
/**
* List of AttributeConsumingService descriptors for this SP.
*
* Array with SAML2_XML_md_AttribteConsumingService objects.
*
* @var array
*/
public $AttributeConsumingService = array();
/**
* Initialize a SPSSODescriptor.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
parent::__construct('md:SPSSODescriptor', $xml);
if ($xml === NULL) {
return;
}
$this->AuthnRequestsSigned = SAML2_Utils::parseBoolean($xml, 'AuthnRequestsSigned', NULL);
$this->WantAssertionsSigned = SAML2_Utils::parseBoolean($xml, 'WantAssertionsSigned', NULL);
foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:AssertionConsumerService') as $ep) {
$this->AssertionConsumerService[] = new SAML2_XML_md_IndexedEndpointType($ep);
}
foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:AttributeConsumingService') as $acs) {
$this->AttributeConsumingService[] = new SAML2_XML_md_AttributeConsumingService($acs);
}
}
/**
* Add this SPSSODescriptor to an EntityDescriptor.
*
* @param DOMElement $parent The EntityDescriptor we should append this SPSSODescriptor to.
*/
public function toXML(DOMElement $parent) {
assert('is_null($this->AuthnRequestsSigned) || is_bool($this->AuthnRequestsSigned)');
assert('is_null($this->WantAssertionsSigned) || is_bool($this->WantAssertionsSigned)');
assert('is_array($this->AssertionConsumerService)');
assert('is_array($this->AttributeConsumingService)');
$e = parent::toXML($parent);
if ($this->AuthnRequestsSigned === TRUE) {
$e->setAttribute('AuthnRequestsSigned', 'true');
} elseif ($this->AuthnRequestsSigned === FALSE) {
$e->setAttribute('AuthnRequestsSigned', 'false');
}
if ($this->WantAssertionsSigned === TRUE) {
$e->setAttribute('WantAssertionsSigned', 'true');
} elseif ($this->WantAssertionsSigned === FALSE) {
$e->setAttribute('WantAssertionsSigned', 'false');
}
foreach ($this->AssertionConsumerService as $ep) {
$ep->toXML($e, 'md:AssertionConsumerService');
}
foreach ($this->AttributeConsumingService as $acs) {
$acs->toXML($e);
}
}
}

View File

@ -1,114 +0,0 @@
<?php
/**
* Class representing SAML 2 SSODescriptorType.
*
* @package simpleSAMLphp
* @version $Id$
*/
abstract class SAML2_XML_md_SSODescriptorType extends SAML2_XML_md_RoleDescriptor {
/**
* List of ArtifactResolutionService endpoints.
*
* Array with IndexedEndpointType objects.
*
* @var array
*/
public $ArtifactResolutionService = array();
/**
* List of SingleLogoutService endpoints.
*
* Array with EndpointType objects.
*
* @var array
*/
public $SingleLogoutService = array();
/**
* List of ManageNameIDService endpoints.
*
* Array with EndpointType objects.
*
* @var array
*/
public $ManageNameIDService = array();
/**
* List of supported NameID formats.
*
* Array of strings.
*
* @var array
*/
public $NameIDFormat = array();
/**
* Initialize a SSODescriptor.
*
* @param string $elementName The name of this element.
* @param DOMElement|NULL $xml The XML element we should load.
*/
protected function __construct($elementName, DOMElement $xml = NULL) {
assert('is_string($elementName)');
parent::__construct($elementName, $xml);
if ($xml === NULL) {
return;
}
foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:ArtifactResolutionService') as $ep) {
$this->ArtifactResolutionService[] = new SAML2_XML_md_IndexedEndpointType($ep);
}
foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:SingleLogoutService') as $ep) {
$this->SingleLogoutService[] = new SAML2_XML_md_EndpointType($ep);
}
foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:ManageNameIDService') as $ep) {
$this->ManageNameIDService[] = new SAML2_XML_md_EndpointType($ep);
}
$this->NameIDFormat = SAML2_Utils::extractStrings($xml, SAML2_Const::NS_MD, 'NameIDFormat');
}
/**
* Add this SSODescriptorType to an EntityDescriptor.
*
* @param DOMElement $parent The EntityDescriptor we should append this SSODescriptorType to.
* @param string $name The name of the element we should create.
* @return DOMElement The generated SSODescriptor DOMElement.
*/
protected function toXML(DOMElement $parent) {
assert('is_array($this->ArtifactResolutionService)');
assert('is_array($this->SingleLogoutService)');
assert('is_array($this->ManageNameIDService)');
assert('is_array($this->NameIDFormat)');
$e = parent::toXML($parent);
foreach ($this->ArtifactResolutionService as $ep) {
$ep->toXML($e, 'md:ArtifactResolutionService');
}
foreach ($this->SingleLogoutService as $ep) {
$ep->toXML($e, 'md:SingleLogoutService');
}
foreach ($this->ManageNameIDService as $ep) {
$ep->toXML($e, 'md:ManageNameIDService');
}
SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:NameIDFormat', FALSE, $this->NameIDFormat);
return $e;
}
}

View File

@ -1,41 +0,0 @@
<?php
/**
* Class representing unknown RoleDescriptors.
*
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_md_UnknownRoleDescriptor extends SAML2_XML_md_RoleDescriptor {
/**
* This RoleDescriptor as XML
*
* @var SAML2_XML_Chunk
*/
private $xml;
/**
* Initialize an unknown RoleDescriptor.
*
* @param DOMElement $xml The XML element we should load.
*/
public function __construct(DOMElement $xml) {
parent::__construct('md:RoleDescriptor', $xml);
$this->xml = new SAML2_XML_Chunk($xml);
}
/**
* Add this RoleDescriptor to an EntityDescriptor.
*
* @param DOMElement $parent The EntityDescriptor we should append this RoleDescriptor to.
*/
public function toXML(DOMElement $parent) {
$this->xml->toXML($parent);
}
}

View File

@ -1,72 +0,0 @@
<?php
/**
* Class for handling the EntityAttributes metadata extension.
*
* @link: http://docs.oasis-open.org/security/saml/Post2.0/sstc-metadata-attr-cs-01.pdf
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_mdattr_EntityAttributes {
/**
* The namespace used for the EntityAttributes extension.
*/
const NS = 'urn:oasis:names:tc:SAML:metadata:attribute';
/**
* Array with child elements.
*
* The elements can be SAML2_XML_saml_Attribute or SAML2_XML_Chunk elements.
*
* @var array
*/
public $children;
/**
* Create a EntityAttributes element.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
if ($xml === NULL) {
return;
}
foreach (SAML2_Utils::xpQuery($xml, './saml_assertion:Attribute|./saml_assertion:Assertion') as $node) {
if ($node->localName === 'Attribute') {
$this->children[] = new SAML2_XML_saml_Attribute($node);
} else {
$this->children[] = new SAML2_XML_Chunk($node);
}
}
}
/**
* Convert this EntityAttributes to XML.
*
* @param DOMElement $parent The element we should append to.
*/
public function toXML(DOMElement $parent) {
assert('is_array($this->children)');
$doc = $parent->ownerDocument;
$e = $doc->createElementNS(SAML2_XML_mdattr_EntityAttributes::NS, 'mdattr:EntityAttributes');
$parent->appendChild($e);
if (!empty($this->children)) {
foreach ($this->children as $child) {
$child->toXML($e);
}
}
return $e;
}
}

View File

@ -1,14 +0,0 @@
<?php
/**
* Common definitions for the mdrpi metadata extension.
*
* @link: http://docs.oasis-open.org/security/saml/Post2.0/saml-metadata-rpi/v1.0/saml-metadata-rpi-v1.0.pdf
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_mdrpi_Common {
const NS_MDRPI = 'urn:oasis:names:tc:SAML:metadata:rpi';
}

View File

@ -1,102 +0,0 @@
<?php
/**
* Class for handling the mdrpi:PublicationInfo element.
*
* @link: http://docs.oasis-open.org/security/saml/Post2.0/saml-metadata-rpi/v1.0/saml-metadata-rpi-v1.0.pdf
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_mdrpi_PublicationInfo {
/**
* The identifier of the metadata publisher.
*
* @var string
*/
public $publisher;
/**
* The creation timestamp for the metadata, as a UNIX timestamp.
*
* @var int|NULL
*/
public $creationInstant;
/**
* Identifier for this metadata publication.
*
* @var string|NULL
*/
public $publicationId;
/**
* Link to usage policy for this metadata.
*
* This is an associative array with language=>URL.
*
* @var array
*/
public $UsagePolicy = array();
/**
* Create/parse a mdrpi:PublicationInfo element.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
if ($xml === NULL) {
return;
}
if (!$xml->hasAttribute('publisher')) {
throw new Exception('Missing required attribute "publisher" in mdrpi:PublicationInfo element.');
}
$this->publisher = $xml->getAttribute('publisher');
if ($xml->hasAttribute('creationInstant')) {
$this->creationInstant = SimpleSAML_Utilities::parseSAML2Time($xml->getAttribute('creationInstant'));
}
if ($xml->hasAttribute('publicationId')) {
$this->publicationId = $xml->getAttribute('publicationId');
}
$this->UsagePolicy = SAML2_Utils::extractLocalizedStrings($xml, SAML2_XML_mdrpi_Common::NS_MDRPI, 'UsagePolicy');
}
/**
* Convert this element to XML.
*
* @param DOMElement $parent The element we should append to.
*/
public function toXML(DOMElement $parent) {
assert('is_string($this->publisher)');
assert('is_int($this->creationInstant) || is_null($this->creationInstant)');
assert('is_string($this->publicationId) || is_null($this->publicationId)');
assert('is_array($this->UsagePolicy)');
$doc = $parent->ownerDocument;
$e = $doc->createElementNS(SAML2_XML_mdrpi_Common::NS_MDRPI, 'mdrpi:PublicationInfo');
$parent->appendChild($e);
$e->setAttribute('publisher', $this->publisher);
if ($this->creationInstant !== NULL) {
$e->setAttribute('creationInstant', gmdate('Y-m-d\TH:i:s\Z', $this->creationInstant));
}
if ($this->publicationId !== NULL) {
$e->setAttribute('publicationId', $this->publicationId);
}
SAML2_Utils::addStrings($e, SAML2_XML_mdrpi_Common::NS_MDRPI, 'mdrpi:UsagePolicy', TRUE, $this->UsagePolicy);
return $e;
}
}

View File

@ -1,86 +0,0 @@
<?php
/**
* Class for handling the mdrpi:RegistrationInfo element.
*
* @link: http://docs.oasis-open.org/security/saml/Post2.0/saml-metadata-rpi/v1.0/saml-metadata-rpi-v1.0.pdf
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_mdrpi_RegistrationInfo {
/**
* The identifier of the metadata registration authority.
*
* @var string
*/
public $registrationAuthority;
/**
* The registration timestamp for the metadata, as a UNIX timestamp.
*
* @var int|NULL
*/
public $registrationInstant;
/**
* Link to registration policy for this metadata.
*
* This is an associative array with language=>URL.
*
* @var array
*/
public $RegistrationPolicy = array();
/**
* Create/parse a mdrpi:RegistrationInfo element.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
if ($xml === NULL) {
return;
}
if (!$xml->hasAttribute('registrationAuthority')) {
throw new Exception('Missing required attribute "registrationAuthority" in mdrpi:RegistrationInfo element.');
}
$this->registrationAuthority = $xml->getAttribute('registrationAuthority');
if ($xml->hasAttribute('registrationInstant')) {
$this->registrationInstant = SimpleSAML_Utilities::parseSAML2Time($xml->getAttribute('registrationInstant'));
}
$this->RegistrationPolicy = SAML2_Utils::extractLocalizedStrings($xml, SAML2_XML_mdrpi_Common::NS_MDRPI, 'RegistrationPolicy');
}
/**
* Convert this element to XML.
*
* @param DOMElement $parent The element we should append to.
*/
public function toXML(DOMElement $parent) {
assert('is_string($this->registrationAuthority)');
assert('is_int($this->registrationInstant) || is_null($this->registrationInstant)');
assert('is_array($this->RegistrationPolicy)');
$doc = $parent->ownerDocument;
$e = $doc->createElementNS(SAML2_XML_mdrpi_Common::NS_MDRPI, 'mdrpi:RegistrationInfo');
$parent->appendChild($e);
$e->setAttribute('registrationAuthority', $this->registrationAuthority);
if ($this->registrationInstant !== NULL) {
$e->setAttribute('registrationInstant', gmdate('Y-m-d\TH:i:s\Z', $this->registrationInstant));
}
SAML2_Utils::addStrings($e, SAML2_XML_mdrpi_Common::NS_MDRPI, 'mdrpi:RegistrationPolicy', TRUE, $this->RegistrationPolicy);
return $e;
}
}

View File

@ -1,106 +0,0 @@
<?php
/**
* Class for handling the metadata extensions for login and discovery user interface
*
* @link: http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-metadata-ui/v1.0/sstc-saml-metadata-ui-v1.0.pdf
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_mdui_DiscoHints {
/**
* The namespace used for the DiscoHints extension.
*/
const NS = 'urn:oasis:names:tc:SAML:metadata:ui';
/**
* Array with child elements.
*
* The elements can be any of the other SAML2_XML_mdui_* elements.
*
* @var array
*/
public $children = array();
/**
* The IPHint, as an array of strings.
*
* @var array
*/
public $IPHint = array();
/**
* The DomainHint, as an array of strings.
*
* @var array
*/
public $DomainHint = array();
/**
* The GeolocationHint, as an array of strings.
*
* @var array
*/
public $GeolocationHint = array();
/**
* Create a DiscoHints element.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
if ($xml === NULL) {
return;
}
$this->IPHint = SAML2_Utils::extractStrings($xml, self::NS, 'IPHint');
$this->DomainHint = SAML2_Utils::extractStrings($xml, self::NS, 'DomainHint');
$this->GeolocationHint = SAML2_Utils::extractStrings($xml, self::NS, 'GeolocationHint');
foreach (SAML2_Utils::xpQuery($xml, "./*[namespace-uri()!='".self::NS."']") as $node) {
$this->children[] = new SAML2_XML_Chunk($node);
}
}
/**
* Convert this DiscoHints to XML.
*
* @param DOMElement $parent The element we should append to.
*/
public function toXML(DOMElement $parent) {
assert('is_array($this->IPHint)');
assert('is_array($this->DomainHint)');
assert('is_array($this->GeolocationHint)');
assert('is_array($this->children)');
if (!empty($this->IPHint)
|| !empty($this->DomainHint)
|| !empty($this->GeolocationHint)
|| !empty($this->children)) {
$doc = $parent->ownerDocument;
$e = $doc->createElementNS(self::NS, 'mdui:DiscoHints');
$parent->appendChild($e);
if (!empty($this->children)) {
foreach ($this->children as $child) {
$child->toXML($e);
}
}
SAML2_Utils::addStrings($e, self::NS, 'mdui:IPHint', FALSE, $this->IPHint);
SAML2_Utils::addStrings($e, self::NS, 'mdui:DomainHint', FALSE, $this->DomainHint);
SAML2_Utils::addStrings($e, self::NS, 'mdui:GeolocationHint', FALSE, $this->GeolocationHint);
return $e;
}
}
}

View File

@ -1,80 +0,0 @@
<?php
/**
* Class for handling the Keywords metadata extensions for login and discovery user interface
*
* @link: http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-metadata-ui/v1.0/sstc-saml-metadata-ui-v1.0.pdf
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_mdui_Keywords {
/**
* The keywords of this item.
*
* @var string
*/
public $Keywords;
/**
* The language of this item.
*
* @var string
*/
public $lang;
/**
* Initialize a Keywords.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
if ($xml === NULL) {
return;
}
if (!$xml->hasAttribute('xml:lang')) {
throw new Exception('Missing lang on Keywords.');
}
if (!is_string($xml->textContent) || !strlen($xml->textContent)) {
throw new Exception('Missing value for Keywords.');
}
$this->Keywords = array();
foreach (explode(' ', $xml->textContent) as $keyword) {
$this->Keywords[] = str_replace('+', ' ', $keyword);
}
$this->lang = $xml->getAttribute('xml:lang');
}
/**
* Convert this Keywords to XML.
*
* @param DOMElement $parent The element we should append this Keywords to.
*/
public function toXML(DOMElement $parent) {
assert('is_string($this->lang)');
assert('is_array($this->Keywords)');
$doc = $parent->ownerDocument;
$e = $doc->createElementNS(SAML2_XML_mdui_UIInfo::NS, 'mdui:Keywords');
$e->setAttribute('xml:lang', $this->lang);
$value = '';
foreach ($this->Keywords as $keyword) {
if (strpos($keyword, "+") !== false) {
throw new Exception('Keywords may not contain a "+" character.');
}
$value .= str_replace(' ', '+', $keyword) . ' ';
}
$value = rtrim($value);
$e->appendChild($doc->createTextNode($value));
$parent->appendChild($e);
return $e;
}
}

View File

@ -1,94 +0,0 @@
<?php
/**
* Class for handling the Logo metadata extensions for login and discovery user interface
*
* @link: http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-metadata-ui/v1.0/sstc-saml-metadata-ui-v1.0.pdf
* @package simpleSAMLphp
* @version $Id$
*/
class SAML2_XML_mdui_Logo {
/**
* The url of this logo.
*
* @var string
*/
public $url;
/**
* The width of this logo.
*
* @var string
*/
public $width;
/**
* The height of this logo.
*
* @var string
*/
public $height;
/**
* The language of this item.
*
* @var string
*/
public $lang;
/**
* Initialize a Logo.
*
* @param DOMElement|NULL $xml The XML element we should load.
*/
public function __construct(DOMElement $xml = NULL) {
if ($xml === NULL) {
return;
}
if (!$xml->hasAttribute('width')) {
throw new Exception('Missing width of Logo.');
}
if (!$xml->hasAttribute('height')) {
throw new Exception('Missing height of Logo.');
}
if (!is_string($xml->textContent) || !strlen($xml->textContent)) {
throw new Exception('Missing url value for Logo.');
}
$this->url = $xml->textContent;
$this->width = (int)$xml->getAttribute('width');
$this->height = (int)$xml->getAttribute('height');
$this->lang = $xml->hasAttribute('xml:lang') ? $xml->getAttribute('xml:lang') : NULL;
}
/**
* Convert this Logo to XML.
*
* @param DOMElement $parent The element we should append this Logo to.
*/
public function toXML(DOMElement $parent) {
assert('is_int($this->width)');
assert('is_int($this->height)');
assert('is_string($this->url)');
$doc = $parent->ownerDocument;
$e = $doc->createElementNS(SAML2_XML_mdui_UIInfo::NS, 'mdui:Logo');
$e->appendChild($doc->createTextNode($this->url));
$e->setAttribute('width', (int)$this->width);
$e->setAttribute('height', (int)$this->height);
if (isset($this->lang)) {
$e->setAttribute('xml:lang', $this->lang);
}
$parent->appendChild($e);
return $e;
}
}

Some files were not shown because too many files have changed in this diff Show More