PageRenderTime 81ms CodeModel.GetById 46ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/simplesamlphp-1.10.0/modules/aselect/lib/Auth/Source/aselect.php

https://bitbucket.org/sahkoinenaanestys/sahkoinenaanestys
PHP | 203 lines | 114 code | 29 blank | 60 comment | 17 complexity | 6f112faec166506ad575f9614d53c646 MD5 | raw file
  1. <?php
  2. /**
  3. * Authentication module which acts as an A-Select client
  4. *
  5. * @author Wessel Dankers, Tilburg University
  6. */
  7. class sspmod_aselect_Auth_Source_aselect extends SimpleSAML_Auth_Source {
  8. private $app_id = 'simplesamlphp';
  9. private $server_id;
  10. private $server_url;
  11. private $private_key;
  12. /**
  13. * Constructor for this authentication source.
  14. *
  15. * @param array $info Information about this authentication source.
  16. * @param array $config Configuration.
  17. */
  18. public function __construct($info, $config) {
  19. /* Call the parent constructor first, as required by the interface. */
  20. parent::__construct($info, $config);
  21. $cfg = SimpleSAML_Configuration::loadFromArray($config,
  22. 'Authentication source ' . var_export($this->authId, true));
  23. $cfg->getValueValidate('type', array('app'), 'app');
  24. $this->app_id = $cfg->getString('app_id');
  25. $this->private_key = $cfg->getString('private_key', null);
  26. // accept these arguments with '_' for consistency
  27. // accept these arguments without '_' for backwards compatibility
  28. $this->server_id = $cfg->getString('serverid', null);
  29. if($this->server_id === null)
  30. $this->server_id = $cfg->getString('server_id');
  31. $this->server_url = $cfg->getString('serverurl', null);
  32. if($this->server_url === null)
  33. $this->server_url = $cfg->getString('server_url');
  34. }
  35. /**
  36. * Initiate authentication.
  37. *
  38. * @param array &$state Information about the current authentication.
  39. */
  40. public function authenticate(&$state) {
  41. $state['aselect::authid'] = $this->authId;
  42. $id = SimpleSAML_Auth_State::saveState($state, 'aselect:login', true);
  43. try {
  44. $app_url = SimpleSAML_Module::getModuleURL('aselect/credentials.php', array('ssp_state' => $id));
  45. $as_url = $this->request_authentication($app_url);
  46. SimpleSAML_Utilities::redirect($as_url);
  47. } catch(Exception $e) {
  48. // attach the exception to the state
  49. SimpleSAML_Auth_State::throwException($state, $e);
  50. }
  51. }
  52. /**
  53. * Sign a string using the configured private key
  54. *
  55. * @param string $str The string to calculate a signature for
  56. */
  57. private function base64_signature($str) {
  58. $key = openssl_pkey_get_private($this->private_key);
  59. if($key === false)
  60. throw new SimpleSAML_Error_Exception("Unable to load private key: ".openssl_error_string());
  61. if(!openssl_sign($str, $sig, $key))
  62. throw new SimpleSAML_Error_Exception("Unable to create signature: ".openssl_error_string());
  63. openssl_pkey_free($key);
  64. return base64_encode($sig);
  65. }
  66. /**
  67. * Parse a base64 encoded attribute blob. Can't use parse_str() because it
  68. * may contain multi-valued attributes.
  69. *
  70. * @param string $base64 The base64 string to decode.
  71. */
  72. private static function decode_attributes($base64) {
  73. $blob = base64_decode($base64, true);
  74. if($blob === false)
  75. throw new SimpleSAML_Error_Exception("Attributes parameter base64 malformed");
  76. $pairs = explode('&', $blob);
  77. $ret = array();
  78. foreach($pairs as $pair) {
  79. $keyval = explode('=', $pair, 2);
  80. if(count($keyval) < 2)
  81. throw new SimpleSAML_Error_Exception("Missing value in attributes parameter");
  82. $key = urldecode($keyval[0]);
  83. $val = urldecode($keyval[1]);
  84. $ret[$key][] = $val;
  85. }
  86. return $ret;
  87. }
  88. /**
  89. * Default options for curl invocations.
  90. */
  91. private static $curl_options = array(
  92. CURLOPT_BINARYTRANSFER => true,
  93. CURLOPT_FAILONERROR => true,
  94. CURLOPT_RETURNTRANSFER => true,
  95. CURLOPT_CONNECTTIMEOUT => 1,
  96. CURLOPT_TIMEOUT => 5,
  97. CURLOPT_USERAGENT => "simpleSAMLphp",
  98. );
  99. /**
  100. * Create a (possibly signed) URL to contact the A-Select server.
  101. *
  102. * @param string $request The name of the request (authenticate / verify_credentials).
  103. * @param array $parameters The parameters to pass for this request.
  104. */
  105. private function create_aselect_url($request, $parameters) {
  106. $parameters['request'] = $request;
  107. $parameters['a-select-server'] = $this->server_id;
  108. if(!is_null($this->private_key)) {
  109. $signable = '';
  110. foreach(array('a-select-server', 'app_id', 'app_url', 'aselect_credentials', 'rid') as $p)
  111. if(array_key_exists($p, $parameters))
  112. $signable .= $parameters[$p];
  113. $parameters['signature'] = $this->base64_signature($signable);
  114. }
  115. return SimpleSAML_Utilities::addURLparameter($this->server_url, $parameters);
  116. }
  117. /**
  118. * Contact the A-Select server and return the result as an associative array.
  119. *
  120. * @param string $request The name of the request (authenticate / verify_credentials).
  121. * @param array $parameters The parameters to pass for this request.
  122. */
  123. private function call_aselect($request, $parameters) {
  124. $url = $this->create_aselect_url($request, $parameters);
  125. $curl = curl_init($url);
  126. if($curl === false)
  127. throw new SimpleSAML_Error_Exception("Unable to create CURL handle");
  128. if(!curl_setopt_array($curl, self::$curl_options))
  129. throw new SimpleSAML_Error_Exception("Unable to set CURL options: ".curl_error($curl));
  130. $str = curl_exec($curl);
  131. $err = curl_error($curl);
  132. curl_close($curl);
  133. if($str === false)
  134. throw new SimpleSAML_Error_Exception("Unable to retrieve URL: $error");
  135. parse_str($str, $res);
  136. // message is only available with some A-Select server implementations
  137. if($res['result_code'] != '0000')
  138. if(array_key_exists('message', $res))
  139. throw new SimpleSAML_Error_Exception("Unable to contact SSO service: result_code=".$res['result_code']." message=".$res['message']);
  140. else
  141. throw new SimpleSAML_Error_Exception("Unable to contact SSO service: result_code=".$res['result_code']);
  142. unset($res['result_code']);
  143. return $res;
  144. }
  145. /**
  146. * Initiate authentication. Returns a URL to redirect the user to.
  147. *
  148. * @param string $app_url The SSP URL to return to after authenticating (similar to an ACS).
  149. */
  150. public function request_authentication($app_url) {
  151. $res = $this->call_aselect('authenticate',
  152. array('app_id' => $this->app_id, 'app_url' => $app_url));
  153. $as_url = $res['as_url'];
  154. unset($res['as_url']);
  155. return SimpleSAML_Utilities::addURLparameter($as_url, $res);
  156. }
  157. /**
  158. * Verify the credentials upon return from the A-Select server. Returns an associative array
  159. * with the information given by the A-Select server. Any attributes are pre-parsed.
  160. *
  161. * @param string $server_id The A-Select server ID as passed by the client
  162. * @param string $credentials The credentials as passed by the client
  163. * @param string $rid The request ID as passed by the client
  164. */
  165. public function verify_credentials($server_id, $credentials, $rid) {
  166. if($server_id != $this->server_id)
  167. throw new SimpleSAML_Error_Exception("Acquired server ID ($server_id) does not match configured server ID ($this->server_id)");
  168. $res = $this->call_aselect('verify_credentials',
  169. array('aselect_credentials' => $credentials, 'rid' => $rid));
  170. if(array_key_exists('attributes', $res))
  171. $res['attributes'] = self::decode_attributes($res['attributes']);
  172. return $res;
  173. }
  174. }