Skip to content
Snippets Groups Projects
Commit 48839939 authored by Jaime Perez Crespo's avatar Jaime Perez Crespo
Browse files

Extract the discojuice module to its own repository. This closes #165.

parent 09bfb17e
No related branches found
No related tags found
No related merge requests found
This file indicates that the default state of this module
is disabled. To enable, create a file named enable in the
same directory as this file.
A-Select module for simpleSAMLphp
---------------------------------
This module allows one to use an A-Select server as authentication
source for simpleSAMLphp.
The module supports the A-Select protocol, including signing of
requests. Not supported is A-Select Cross.
Usage:
Enable the module if not already enabled:
$ touch modules/aselect/enabled
In config/authsources.php, configure your A-Selectserver as an
authentication source. The following is an example for a source
named 'aselect':
'aselect' => array(
'aselect:aselect',
'app_id' => 'simplesamlphp',
'server_id' => 'sso.example.com',
'server_url' => 'https://test.sso.example.com/server',
'private_key' => 'file:///etc/ssl/private/aselect.key',
'add_default_attributes' => FALSE
),
The parameters:
- app_id: the application I for simpleSAMLphp as configured in
your A-Select server;
- server_id: the A-Select server ID as configured in your
A-Select server;
- server_url: the URL for your A-Selectserver, usually ends in
'/server/.
- private_key: the key you want to use for signing requests.
If you're really sure you do not want request signing, you
can set this option to a null value.
- add_default_attributes: true to add default attributes
(uid and organization) to resulting attributes, false
to never do this, and null to do this only when no
attributes are returned.
Options 'serverurl' and 'serverid' (without underscore) are
supported for backwards compatibility.
Author: Wessel Dankers <wsl@uvt.nl>
Copyright: © 2011,2012 Tilburg University (http://www.tilburguniversity.edu)
License: LGPL version 2.1
<?php
/**
* Authentication module which acts as an A-Select client
*
* @author Wessel Dankers, Tilburg University
*/
class sspmod_aselect_Auth_Source_aselect extends SimpleSAML_Auth_Source {
private $app_id = 'simplesamlphp';
private $server_id;
private $server_url;
private $private_key;
private $add_default_attributes;
/**
* Constructor for this authentication source.
*
* @param array $info Information about this authentication source.
* @param array $config Configuration.
*/
public function __construct($info, $config) {
/* Call the parent constructor first, as required by the interface. */
parent::__construct($info, $config);
$cfg = SimpleSAML_Configuration::loadFromArray($config,
'Authentication source ' . var_export($this->authId, true));
$cfg->getValueValidate('type', array('app'), 'app');
$this->app_id = $cfg->getString('app_id');
$this->private_key = $cfg->getString('private_key', null);
// accept these arguments with '_' for consistency
// accept these arguments without '_' for backwards compatibility
$this->server_id = $cfg->getString('serverid', null);
if($this->server_id === null)
$this->server_id = $cfg->getString('server_id');
$this->server_url = $cfg->getString('serverurl', null);
if($this->server_url === null)
$this->server_url = $cfg->getString('server_url');
$this->add_default_attributes = $cfg->getBoolean('add_default_attributes', null);
}
/**
* Initiate authentication.
*
* @param array &$state Information about the current authentication.
*/
public function authenticate(&$state) {
$state['aselect::authid'] = $this->authId;
$state['aselect::add_default_attributes'] = $this->add_default_attributes;
$id = SimpleSAML_Auth_State::saveState($state, 'aselect:login', true);
try {
$app_url = SimpleSAML_Module::getModuleURL('aselect/credentials.php', array('ssp_state' => $id));
$as_url = $this->request_authentication($app_url);
\SimpleSAML\Utils\HTTP::redirectTrustedURL($as_url);
} catch(Exception $e) {
// attach the exception to the state
SimpleSAML_Auth_State::throwException($state, $e);
}
}
/**
* Sign a string using the configured private key
*
* @param string $str The string to calculate a signature for
*/
private function base64_signature($str) {
$key = openssl_pkey_get_private($this->private_key);
if($key === false)
throw new SimpleSAML_Error_Exception("Unable to load private key: ".openssl_error_string());
if(!openssl_sign($str, $sig, $key))
throw new SimpleSAML_Error_Exception("Unable to create signature: ".openssl_error_string());
openssl_pkey_free($key);
return base64_encode($sig);
}
/**
* Parse a base64 encoded attribute blob. Can't use parse_str() because it
* may contain multi-valued attributes.
*
* @param string $base64 The base64 string to decode.
*/
private static function decode_attributes($base64) {
$blob = base64_decode($base64, true);
if($blob === false)
throw new SimpleSAML_Error_Exception("Attributes parameter base64 malformed");
$pairs = explode('&', $blob);
$ret = array();
foreach($pairs as $pair) {
$keyval = explode('=', $pair, 2);
if(count($keyval) < 2)
throw new SimpleSAML_Error_Exception("Missing value in attributes parameter");
$key = urldecode($keyval[0]);
$val = urldecode($keyval[1]);
$ret[$key][] = $val;
}
return $ret;
}
/**
* Default options for curl invocations.
*/
private static $curl_options = array(
CURLOPT_BINARYTRANSFER => true,
CURLOPT_FAILONERROR => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 1,
CURLOPT_TIMEOUT => 5,
CURLOPT_USERAGENT => "simpleSAMLphp",
);
/**
* Create a (possibly signed) URL to contact the A-Select server.
*
* @param string $request The name of the request (authenticate / verify_credentials).
* @param array $parameters The parameters to pass for this request.
*/
private function create_aselect_url($request, $parameters) {
$parameters['request'] = $request;
$parameters['a-select-server'] = $this->server_id;
if(!is_null($this->private_key)) {
$signable = '';
foreach(array('a-select-server', 'app_id', 'app_url', 'aselect_credentials', 'rid') as $p)
if(array_key_exists($p, $parameters))
$signable .= $parameters[$p];
$parameters['signature'] = $this->base64_signature($signable);
}
return \SimpleSAML\Utils\HTTP::addURLParameters($this->server_url, $parameters);
}
/**
* Contact the A-Select server and return the result as an associative array.
*
* @param string $request The name of the request (authenticate / verify_credentials).
* @param array $parameters The parameters to pass for this request.
*/
private function call_aselect($request, $parameters) {
$url = $this->create_aselect_url($request, $parameters);
$curl = curl_init($url);
if($curl === false)
throw new SimpleSAML_Error_Exception("Unable to create CURL handle");
if(!curl_setopt_array($curl, self::$curl_options))
throw new SimpleSAML_Error_Exception("Unable to set CURL options: ".curl_error($curl));
$str = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if($str === false)
throw new SimpleSAML_Error_Exception("Unable to retrieve URL: $err");
parse_str($str, $res);
// message is only available with some A-Select server implementations
if($res['result_code'] != '0000')
if(array_key_exists('message', $res))
throw new SimpleSAML_Error_Exception("Unable to contact SSO service: result_code=".$res['result_code']." message=".$res['message']);
else
throw new SimpleSAML_Error_Exception("Unable to contact SSO service: result_code=".$res['result_code']);
unset($res['result_code']);
return $res;
}
/**
* Initiate authentication. Returns a URL to redirect the user to.
*
* @param string $app_url The SSP URL to return to after authenticating (similar to an ACS).
*/
public function request_authentication($app_url) {
$res = $this->call_aselect('authenticate',
array('app_id' => $this->app_id, 'app_url' => $app_url));
$as_url = $res['as_url'];
unset($res['as_url']);
return \SimpleSAML\Utils\HTTP::addURLParameters($as_url, $res);
}
/**
* Verify the credentials upon return from the A-Select server. Returns an associative array
* with the information given by the A-Select server. Any attributes are pre-parsed.
*
* @param string $server_id The A-Select server ID as passed by the client
* @param string $credentials The credentials as passed by the client
* @param string $rid The request ID as passed by the client
*/
public function verify_credentials($server_id, $credentials, $rid) {
if($server_id != $this->server_id)
throw new SimpleSAML_Error_Exception("Acquired server ID ($server_id) does not match configured server ID ($this->server_id)");
$res = $this->call_aselect('verify_credentials',
array('aselect_credentials' => $credentials, 'rid' => $rid));
if(array_key_exists('attributes', $res))
$res['attributes'] = self::decode_attributes($res['attributes']);
return $res;
}
}
<?php
/**
* Check the credentials that the user got from the A-Select server.
* This function is called after the user returns from the A-Select server.
*
* @author Wessel Dankers, Tilburg University
*/
if (!array_key_exists('ssp_state', $_REQUEST)) {
throw new SimpleSAML_Error_Exception("Missing ssp_state parameter");
}
$state = SimpleSAML_Auth_State::loadState($_REQUEST['ssp_state'], 'aselect:login');
if (!array_key_exists('a-select-server', $_REQUEST)) {
SimpleSAML_Auth_State::throwException($state, new SimpleSAML_Error_Exception("Missing a-select-server parameter"));
}
$server_id = $_REQUEST['a-select-server'];
if (!array_key_exists('aselect_credentials', $_REQUEST)) {
SimpleSAML_Auth_State::throwException($state,
new SimpleSAML_Error_Exception("Missing aselect_credentials parameter"));
}
$credentials = $_REQUEST['aselect_credentials'];
if (!array_key_exists('rid', $_REQUEST)) {
SimpleSAML_Auth_State::throwException($state, new SimpleSAML_Error_Exception("Missing rid parameter"));
}
$rid = $_REQUEST['rid'];
try {
if (!array_key_exists('aselect::authid', $state)) {
throw new SimpleSAML_Error_Exception("ASelect authentication source missing in state");
}
$authid = $state['aselect::authid'];
$aselect = SimpleSAML_Auth_Source::getById($authid);
if (is_null($aselect)) {
throw new SimpleSAML_Error_Exception("Could not find authentication source with id $authid");
}
$creds = $aselect->verify_credentials($server_id, $credentials, $rid);
if ($state['aselect::add_default_attributes'] === true) {
// Add default attributes
$state['Attributes'] = array('uid' => array($creds['uid']), 'organization' => array($creds['organization']));
if (array_key_exists('attributes', $creds)) {
$state['Attributes'] = array_merge($state['Attributes'], $creds['attributes']);
}
} elseif ($state['aselect::add_default_attributes'] === false) {
// Do not add default attributes
if (array_key_exists('attributes', $creds)) {
$state['Attributes'] = $creds['attributes'];
} else {
$state['Attributes'] = array();
}
} else {
// Legacy behaviour: add default attributes if no attributes are returned
if (array_key_exists('attributes', $creds)) {
$state['Attributes'] = $creds['attributes'];
} else {
$state['Attributes'] = array('uid' => array($creds['uid']), 'organization' => array($creds['organization']));
}
}
} catch (Exception $e) {
SimpleSAML_Auth_State::throwException($state, $e);
}
SimpleSAML_Auth_Source::completeAuth($state);
SimpleSAML_Auth_State::throwException($state, new SimpleSAML_Error_Exception("Internal error in A-Select component"));
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment