-
Tomasz Wolniewicz authoredTomasz Wolniewicz authored
API.php 59.24 KiB
<?php
setlocale(LC_ALL, 'en_GB.UTF8');
date_default_timezone_set('UTC');
require(eduGAIN_config."access_keys.php");
if (isset($_SESSION) && isset($_SESSION['auth_ok']) && isset($_SESSION['user']) && $_SESSION['auth_ok'] == 'authenticated') {
$user = $_SESSION['user'];
}
class API {
public function __construct() {
$this->action = isset($_REQUEST['action']) ? $_REQUEST['action'] : 0;
$this->opts = [];
$this->fed_id = 0;
if (!empty($_REQUEST['edugain'])) {
$this->fed_id = $_REQUEST['edugain'];
}
if (!empty($_REQUEST['fed_id'])) {
$this->fed_id = $_REQUEST['fed_id'];
}
// first validate that the input code maches the allowed patterns
if (!preg_match('/^:?([a-zA-Z]*-?[a-zA-Z]*)(:[a-aA-Z]*-?[a-zA-Z]*)*$/', $this->fed_id)) {
$this->fed_id = 0;
}
// check if reg_auth has has been provided (only if fed_id is missing
if ($this->fed_id === 0 && !empty($_REQUEST['reg_auth']) ) {
$edugain = new eduGAIN_core();
$this->fed_id = $edugain->getCodeFromRegAuth($_REQUEST['reg_auth']);
}
// we have moved from country codes to federations but we are still supporting the old model
if ($this->fed_id !== 0) {
$edugain = new eduGAIN_core();
$this->fed_id = $edugain->getCode($this->fed_id);
}
// default reply format is 'json'
$this->format = 'json';
if (isset($_REQUEST['format'])) {
if ($_REQUEST['format'] == 'print_r') {
$this->format = 'print_r';
}
if ($_REQUEST['format'] == 'xml') {
$this->format = 'xml';
}
if ($_REQUEST['format'] == 'csv') {
$this->format = 'csv';
}
if ($_REQUEST['format'] == 'html') {
$this->format = 'html';
}
if ($_REQUEST['format'] == 'png') {
$this->format = 'png';
}
if ($_REQUEST['format'] == 'internal') {
$this->format = 'internal';
}
}
// now check that request parameters are supported
if (isset($_REQUEST['key']))
$this->key = $_REQUEST['key'];
else
$this->key = 0;
$supportedOptions = [
'opt',
'type',
'entity_cat',
'eccs_status',
'ec', // entity category
'ecs', // entity category support
'row_id',
'entityid', // this is an alias for e_id it is important that it comes after e_id
'e_id',
'proto', // is serves no putpose now, but lef to avoid old links from failing
'clashes',
'warnings',
'coco',
'sirtfi',
'search_type',
'help',
'date',
'start_date',
'end_date',
'not_empty',
'map_size',
'map_type',
'show_list',
'new_entities',
'only_errors',
'url_type',
'mod_time',
'lang',
'details',
];
foreach ($supportedOptions as $opt) {
$this->assignOpt($opt);
}
// print_r($this->opts);
}
private function optionError($optName) {
header('Content-Type: text/html; charset=utf-8');
print ("incorrect value for option $optName");
die("incorrect value for option $optName");
}
/* check that input provided by the user is valid and secure, many checkes are repeated to make library call secure also when called by a different path */
private function assignOpt($optName) {
$optValue = isset($_REQUEST[$optName]) ? $_REQUEST[$optName] : 'NOTSET';
switch ($optName) {
case 'opt':
break;
case 'type':
if ($optValue === 0 || $optValue === 'NOTSET' || $optValue === 'all') {
$optValue = 7;
}
switch ($optValue) { // these values can be ALL, IDP, SP, AA
case 'NOTSET':
$optValue = 7;
case 'idp' :
$optValue = 4;
break;
case 'sp' :
$optValue = 2;
break;
case 'aa' :
$optValue = 1;
break;
case 7;
case 4;
case 2;
case 1;
break;
default:
$this->optionError($optName);
break;
}
break;
case 'entity_cat': // security checks are complex and have been moved to eduGAIN_entity::getEntityList
if ($optValue === 0 || $optValue === 'NOTSET') {
$optValue = -2;
}
break;
case 'eccs_status':
switch ($optValue) { // these values can be only 0,1,2,3,4
case 'NOTSET':
$optValue = 0;
break;
case 0:
break;
default:
if (isset(Constants::ECCS_Colours[$optValue])) {
break;
}
$this->optionError($optName);
break;
}
break;
case 'ec':
switch ($optValue) { // these values can be only 0,1
case 'NOTSET':
$optValue = 0;
case 0;
case 1;
break;
default:
$this->optionError($optName);
break;
}
break;
case 'ecs':
switch ($optValue) { // these values can be only 0,1
case 'NOTSET':
$optValue = 0;
case 0;
case 1;
break;
default:
$this->optionError($optName);
break;
}
break;
case 'entityid': // alias for e_id;
$optName = 'e_id';
break;
case 'e_id': // beware this value is an URI therefore require proper cleaning, this is done in eduGAIN_entity::getEntityList
if ($optValue == 'NOTSET') {
$optValue = $this->opts['e_id'];
}
break;
case 'row_id': // database row identifier from the entities table
if ($optValue == 'NOTSET') {
$optValue = 0;
}
if (!is_numeric($optValue)) {
$this->optionError($optName);
}
break;
// case 'proto':
case 'clashes':
case 'warnings':
case 'coco':
case 'sirtfi':
if ($optValue == 'NOTSET') {
$optValue = 0;
}
break;
case 'search_type':
switch ($optValue) {
case 'entityid':
case 'text':
case 'rev-text':
break;
default:
$optValue = '';
}
break;
case 'help':
if ($optValue == 'NOTSET') {
$optValue = 0;
} else {
$optValue = 1;
}
break;
case 'show_list':
case 'not_empty':
if ($optValue == 'NOTSET') {
$optValue = 0;
} else {
if ($optValue !== '0') {
$optValue = 1;
}
}
break;
case 'date':
case 'start_date':
case 'end_date':
if (!preg_match('/^\d\d\d\d-\d\d-\d\d$/', $optValue)) {
$optValue = 0;
} else {
$optValue = strtotime($optValue);
}
break;
case 'mod_time':
if ($optValue == 'NOTSET') {
$optValue = 24;
} elseif (!preg_match('/^\d\d?$/', $optValue) && !preg_match('/^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d$/', $optValue)) {
$this->optionError($optName);
}
break;
case 'map_size':
if ($optValue == 'NOTSET' || $optValue != 'small') {
$optValue = 'l';
} else {
$optValue = 's';
}
break;
case 'map_type':
if ($optValue == 'NOTSET' || $optValue != 'europe') {
$optValue = 'world';
}
break;
case 'new_entities':
if ($optValue === 0 || $optValue === 'NOTSET') {
$optValue = 7;
}
switch ($optValue) { // these values can be
case 'NOTSET':
$optValue = 7;
case 7:
case 5:
case 4:
case 2:
case 1:
break;
default:
$this->optionError($optName);
break;
}
break;
case 'url_type':
// there will be additional sanitasation in functions that use that
$optValue = filter_var($optValue, FILTER_SANITIZE_URL);
break;
case 'lang':
if (preg_match('/^([a-z][a-z])/', $optValue, $m)) {
$optValue = $m[1];
} else {
$optValue = 'NOTSET';
}
break;
case 'only_errors':
if ($optValue != 1) {
$optValue = 0;
}
case 'details':
if ($optValue != 1) {
$optValue = 0;
}
default:
}
$this->opts[$optName] = $optValue;
}
private function description($desc) {
$this->descriptionArray = $desc;
}
private function printHelpHeaders() {
print '<body><div class="api-help">
<h1>Documentation of eduGAIN database access API</h1>';
}
private function printDescription() {
$desc = $this->descriptionArray;
header('Content-type: text/html; charset=utf-8');
$this->printHelpHeaders();
print "<h2>Method: $this->action</h2>";
print "<h3>Description:</h3>";
print $desc['header'];
print "<p class='api-help-formats'><strong>Supported formats:</strong> ";
print implode(', ', $desc['supportedFormats']);
print "<p><strong>Arguments used:</strong><dl>";
foreach ($desc['arguments'] as $arg) {
$req = $arg['required'] ? 'required' : 'optional';
print "<dt><b>".$arg['arg']."</b> ($req)</dt><dd>";
if (!$arg['required'] && isset($arg['default'])) {
print "default: ".$arg['default']."<br />";
}
print "allowed values: ";
if (is_array($arg['values'])) {
} else {
print $arg['values'];
}
if (!empty($arg['description'])) {
print "<br><i>".$arg['description']."</i>";
}
print "</dt>";
}
print "</dl>";
if (!empty($desc['returns']['description'])) {
print "<p><strong>Returns:</strong><br>";
print $desc['returns']['description'];
}
if (!empty($desc['examples'])) {
print "<p><strong>";
$exURLs = '';
if(count($desc['examples']) > 1) {
print "Examples";
} else {
print "Example";
}
print ":</strong><br><dl>";
foreach ($desc['examples'] as $example) {
$format = '&format='.'print_r';
if (isset($example['format'])) {
if ($example['format'] == 'default') {
$format = '';
} else {
$format = '&format='.$example['format'];
}
}
$exURL = ROOT_URL.'/api.php?action='.$this->action.$format;
foreach ($example['opt'] as $exOption => $exOptionValue) {
$exURL .= '&'.$exOption.'='.$exOptionValue;
}
print '<dt>'.$example['title'].'</dt>';
print '<dd><a href="'.str_replace("&","&",$exURL).'">'.str_replace("&","&",$exURL).'</a></dd>';
}
print $exURLs;
}
print '</dl><p><a href="api.php">Show full action list</a>';
print '</div></body></html>';
}
private $action;
private $format;
private $opts;
private $fed_id;
private $key;
private $descriptionArray = [];
// This is the generic wrappper around all actions
public function run_action() {
$a_name = 'action_'.$this->action;
if (!method_exists($this, $a_name)) {
$a_name = 'list_api_actions';
}
$this->output($this->$a_name());
}
// API actions start here. Each AIP should set the description property explaining what it does
private function action_new_fed_code() {
$this->description([
'header' => "Get the federation new code from the old one. If no mapping is available, the input code will be returned.",
'supportedFormats' => ['json', 'print_r'],
'arguments' => [
$this->addStdArgument('fed_id'),
$this->addStdArgument('format'),
],
'returns' => ['description' => 'The current code assigned to the federation.',]
]);
if ($this->opts['help'] == 1) {
return "";
}
return($this->fed_id);
}
private function action_list_fed_codes() {
$this->description([
'header' => "List federations codes and their names.",
'supportedFormats' => ['json', 'print_r'],
'arguments' => [
[
'arg' => 'opt',
'required' => FALSE,
'default' => '0',
'values' => '0, 1, 2, 3, 4',
'description' => '0 - show all; 1 - only production feds; 2 - all members; 3 - only candidates; 4 - only voting-only',
],
$this->addStdArgument('format'),
],
'returns' => [
'description' => 'An array of code,name pairs.',
],
'examples' => [
['opt' => [], 'title' => 'all federations'],
['opt' => ['opt' => 3], 'title' => 'show candidates only'],
]
]);
if ($this->opts['help'] == 1) {
return "";
}
$productionOnly = $this->opts['opt'];
if ($productionOnly != 0 && $productionOnly != 1 && $productionOnly != 2 && $productionOnly != 3 &&$productionOnly != 4) {
$productionOnly = 0;
}
$edugain = new eduGAIN($productionOnly);
return $edugain->listFedCodes();
}
private function action_list_feds() {
$this->description([
'header' => "List federation details (code, name, contact email, registration authority string, status).",
'supportedFormats' => ['json', 'print_r'],
'arguments' => [
[
'arg' => 'opt',
'required' => FALSE,
'default' => '0',
'values' => '0, 1, 2, 3, 4',
'description' => '0 - show all; 1 - only production feds; 2 - all members; 3 - only candidates; 4 - only voting-only'],
$this->addStdArgument('format'),
],
'returns' => [
'description' => 'a fed_id indexed array of basic federatins info:<ul>
<li>name - federation name
<li>email - contact email
<li>reg_auth - registrationAuthority value
<li>status - numeric representation of status: 1 - candidate, 4 - voting-only, 6 - participant
</ul>'
],
'examples' => [
['opt' => [], 'title' => 'show all feds'],
['opt' => ['opt' => 1], 'title' => 'show all production feds'],
],
]);
if ($this->opts['help'] == 1) {
return "";
}
$out = [];
if ($this->opts['opt'] != 1 && $this->opts['opt'] != 2 && $this->opts['opt'] != 3 && $this->opts['opt'] != 4) {
$this->opts['opt'] = 0;
}
$edugain = new eduGAIN($this->opts['opt']);
$F = $edugain->FEDS;
ksort($F, SORT_STRING | SORT_FLAG_CASE);
foreach ($F as $fed => $A) {
$out[$fed] = ['name' => $A['name'],
'email' => $A['contact_email'],
'reg_auth' => $A['reg_auth'],
'status' => $A['status'],
'membership_date' => $A['membership_date'],
'production_date' => $A['production_date']
];
}
return $out;
}
private function action_show_federation() {
global $accessKeys;
$this->description([
'header' => "Show federation detils.",
'supportedFormats' => ['json', 'print_r'],
'arguments' => [
$this->addStdArgument('fed_id', TRUE),
$this->addStdArgument('reg_auth'),
$this->addStdArgument('format'),
],
'returns' => ['description' => 'returns all details about the federation, authenticated users will also see e-mail addresses of federation delegates and deputis.'],
'examples' => [
['opt' => ['fed_id' => 'PIONIER-ID'], 'title' => 'PIONIER.Id federation details'],
['opt' => ['reg_auth' => 'https://aai.pionier.net.pl'], 'title' => 'PIONIER.Id federation details, but called with the reg_auth'],
],
]);
if ($this->opts['help'] == 1) {
return "";
}
if ($this->fed_id === 0) {
return "";
}
$edugain = new eduGAIN(-1, $this->fed_id);
$show_email = 0;
if (isset($_SESSION) && isset($_SESSION['auth_ok']) && isset($_SESSION['user']) && $_SESSION['auth_ok'] == 'authenticated') {
$user = $_SESSION['user'];
$show_email = 1;
} elseif (!empty($this->key) && in_array($this->key, $accessKeys)) {
$show_email = 1;
}
$edugain->load_federation_details('sha1', $show_email);
$out = $edugain->FEDS[$this->fed_id];
return $out;
}
private function action_list_eccs_idps() {
$this->description([
'header' => "This method is exclusively for the ECCS service.",
'supportedFormats' => ['json', 'print_r'],
'arguments' => [
$this->addStdArgument('format'),
]
]);
if ($this->opts['help'] == 1) {
return "";
}
$e = new eduGAIN_entity();
$out = $e->getECCSEntityList();
return $out;
}
private function action_edugain_status() {
$this->description([
'header' => "Provides basic status information about metadata aggregation.",
'supportedFormats' => ['json', 'print_r'],
'arguments' => [
$this->addStdArgument('fed_id'),
$this->addStdArgument('reg_auth'),
$this->addStdArgument('format'),
],
'returns' => [
'description' => 'if a valid federation code is present return an array of:<ul><li>code - the Federation Code
<li>feed_pull_time - the UTC timestamp of last successful mmetadata pull
<li>last_validation - last successfull metadata validation
<li>valid_until - the validUntil value as set in last successfully validated federation metadata
<li>creationinstant - the creationInstant value as set in last successfully validated federation metadata
<li>valid_sec - validity time remaining in seconds
<li>feed_problem - 0 when all is fine, 1 when validation fails, 2 when feed is unavailable
<li>feed_problem_desc - a textual description of the problem
</ul>
when no federation code is present an array of code-indexed participating federations with details as described above'
],
'examples' => [
['opt' => ['fed_id' => 'PIONIER-ID',],'title' => 'show status of PIONIER.Id',],
['opt' => ['fed_id' => 'PIONIER-ID',], 'format' => 'json', 'title' => 'show status of PIONIER.Id in JSON',]
]
]);
if ($this->opts['help'] == 1) {
return "";
}
$edugain = new eduGAIN(1, $this->fed_id, true);
$edugain->load_federations_state();
$out = $edugain->FEDS;
return $out;
}
private function action_list_entities() {
$this->description([
'header' => "Provides an entities listing according to search parameters provided.",
'supportedFormats' => ['json', 'print_r', 'csv', 'internal'],
'arguments' => [
[
'arg' => 'type',
'required' => FALSE,
'values' => '7 or "all" - all entities; 4 or "idp" - IdPs only; 2 or "sp" - SPs only; 1 or "aa" - standalone AAs only.',
'default' => 7,
'description' => 'limits the results to a givien entity type',
],
$this->addStdArgument('fed_id'),
[
'arg' => 'entity_cat',
'required' => FALSE,
'values' => '-2 - no filter; -1 - any category; any valid entitycategory identiefier (URL encoded)',
'default' => -2,
'description' => 'limits the results to a given entity category identifier',
],
[
'arg' => 'ec',
'required' => FALSE,
'values' => '0 - filter not set; 1 - filter set',
'description' => 'only display entities which announce the given entity category',
],
[
'arg' => 'ecs',
'required' => FALSE,
'values' => '0 - filter not set; 1 - filter set',
'description' => 'only display entities which announce support for the given entity category',
],
[
'arg' => 'e_id',
'required' => FALSE,
'values' => 'any string',
'description' => 'input for the entity search',
],
[
'arg' => 'search_type',
'required' => FALSE,
'values' => 'entityid - EntityID substring match; text - Whole entity multiword search; rev-text - Reverse whole entity multiword search (this will throw away rows which match the provided words',
'description' => 'determine the type of search to be performed; while this argument is optional, in case when e_id is set search_type has to be set as well.',
],
[
'arg' => 'eccs_status',
'required' => FALSE,
'default' => '0',
'values' => '0 - no filter; 1 - status OK; 2 - status Warning; 3 - status Error',
'description' => 'filter on eduGAIN Connectivity Check Service',
],
[
'arg' => 'clashes',
'required' => FALSE,
'default' => '0',
'values' => '0 - no info shown; 1 - show clashes info; 2 - show only entities appearing in more then one federation',
'description' => 'display/filter on entity clashes (entities appearing in more then one federation)',
],
[
'arg' => 'warnings',
'required' => FALSE,
'default' => '0',
'values' => '0 - no filter; 2 - show only entities with validator warnings, 3 - show only entities with warnings except for those which only report missing logos',
'description' => 'filter on validator warnings',
],
[
'arg' => 'coco',
'required' => FALSE,
'default' => '0',
'values' => '0 - no filter; 2 - any status; 3 - warnings and errors; 4 - only errors',
'description' => 'filter on Code of Conduct monitoring status',
],
[
'arg' => 'sirtfi',
'required' => FALSE,
'default' => '0',
'values' => '0 - no filter; 1 - SIFTI asserted via the dedicated attibute value; 2 - formal SIRTFI errors',
'description' => 'filter on REFEDS SITFI status',
],
$this->addStdArgument('format'),
],
'examples' => [
['opt' => [], 'title' => 'All entities'],
['opt' => [], 'title' => 'All entities in CSV', 'format' => 'csv'],
['opt' => [ 'clashes' => 2], 'title' => 'clashes - eneties in several federations'],
['opt' => [ 'eccs_status' => 3], 'title' => 'entities with ECCS errors'],
],
]);
if ($this->opts['help'] == 1) {
return "";
}
$out = [];
$e = new eduGAIN_entity();
$startDate = $this->opts['start_date'];
$endDate = $this->opts['end_date'];
switch ($this->opts['new_entities']) {
case 7:
$startDate = strtotime("2017-04-01");
break;
case 5:
$startDate = strtotime(date("Y", strtotime("now"))."-01-01");
break;
case 4:
$startDate = strtotime(date("Y-m", strtotime("now"))."-01");
break;
case 2:
$startDate = strtotime("-1 week");
break;
case 1:
break;
}
if ($this->format == 'print_r' || $this->format == 'json' || $this->format == 'csv') {
$out = $e->getEntityList($this->opts['type'],
$this->fed_id,
$this->opts['entity_cat'],
$this->opts['ec'],
$this->opts['ecs'],
$this->opts['e_id'],
$this->opts['search_type'],
$this->opts['eccs_status'],
$this->opts['clashes'],
$this->opts['warnings'],
$this->opts['coco'],
$this->opts['sirtfi'],
$startDate,
$endDate,
$this->format);
return($out);
}
$this->format = 'json';
$out['html'] = $e->getEntityList($this->opts['type'],
$this->fed_id,
$this->opts['entity_cat'],
$this->opts['ec'],
$this->opts['ecs'],
$this->opts['e_id'],
$this->opts['search_type'],
$this->opts['eccs_status'],
$this->opts['clashes'],
$this->opts['warnings'],
$this->opts['coco'],
$this->opts['sirtfi'],
$startDate,
$endDate,
'internal');
$out['stats'] = $e->globalStats;
return $out;
}
private function action_list_feds_full() {
global $accessKeys;
$this->description([
'header' => "List full federation details incliding contact e-mails to federation representatives.",
'supportedFormats' => ['xml - this is set automatically and need not be specified'],
'arguments' => [
[
'arg' => 'key',
'required' => TRUE,
'values' => 'secret value provided by eduGAIN OT',
'description' => 'This method is resticted since it shows federation representatives e-mails even in cases where they have been declared not to be public.',
],
$this->addStdArgument('format'),
]
]);
if ($this->opts['help'] == 1) {
return "";
}
if (!in_array($this->key, $accessKeys))
return;
$edugain = new eduGAIN();
$edugain->load_all();
$out = $edugain->FEDS;
return $out;
}
private function action_modified_entities() {
$this->description([
'header' => "Show the list of entities modified recently",
'supportedFormats' => ['json', 'print_r'],
'arguments' => [
[
'arg' => 'mod_time',
'required' => FALSE,
'values' => 'an integer between 1 and 23 or a valid UTC time in yyyy-mm-ddTHH:MM:SS format',
'description' => 'the starting time limit for the list to show - missing argment is interpreted ans last 24 hours, '
. 'integer between 1 and 23 is the number of hours back',
],
$this->addStdArgument('format'),
],
'examples' => [
['opt' => [], 'title' => 'show entities modified in last 24 hours'],
['opt' => ['mod_time' => '2023-01-01T00:00:00'], 'title' => 'show entities modified since 2023-01-01'],
],
]);
if ($this->opts['help'] == 1) {
return "";
}
$modTime = $this->opts['mod_time'];
if (preg_match('/^\d\d?$/', $modTime) && $modTime > 0 && $modTime < 25) {
$searchTime = strtotime("-$modTime hours");
} elseif (preg_match('/^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d$/', $modTime)) {
$searchTime = strtotime($modTime);
} else {
$this->optionError($optName);
}
$e = new eduGAIN_entity();
$out = $e->getModified($searchTime);
return $out;
}
private function action_show_entity_clashes() {
$this->description([
'header' => "Show federations supplyilng this entity. Will only work for entities appearing in more then one federation. This method is meant for internal use.",
'supportedFormats' => ['xml - this is set automatically and need not be specified'],
'arguments' => [
[
'arg' => 'row_id',
'required' => TRUE,
'values' => 'valid internal identifier',
'description' => 'internal database identity identifier',
],
$this->addStdArgument('format'),
]
]);
if ($this->opts['help'] == 1) {
return "";
}
$e = new eduGAIN_entity();
$out = $e->showEntityClashes($this->opts['row_id']);
return $out;
}
private function action_show_entity() {
$this->description([
'header' => "Show the full entityID XML. This method is mostly for internal use.",
'supportedFormats' => ['xml - this is set automatically and need not be specified'],
'arguments' => [
[
'arg' => 'row_id',
'required' => FALSE,
'values' => 'valid internal identifier',
'description' => 'internal database identity identifier, either e_id or row_id is required',
],
[
'arg' => 'e_id',
'required' => FALSE,
'values' => 'a valid entityId',
'description' => 'a valid entityId (full string), either e_id or row_id is required, e_id takes precedence',
],
],
'examples' => [
['opt' => ['e_id' => 'https://sso.umk.pl/idp/shibboleth'],
'format' => 'default',
'title' => 'download entity metadata vased on the editityId',
],
]
]);
if ($this->opts['help'] == 1) {
return "";
}
$this->format = 'xml';
$e = new eduGAIN_entity();
$out = $e->showEntity($this->opts['row_id'], $this->opts['e_id']);
return $out;
}
private function action_show_entity_details() {
$this->description([
'header' => "Show the full entity info. This method is mostly for internal use.",
'supportedFormats' => ['json', 'html', 'print_r'],
'arguments' => [
[
'arg' => 'row_id',
'required' => FALSE,
'values' => 'valid internal identifier',
'description' => 'internal database identity identifier, either e_id or row_id is required, e_id takes precedence',
],
[
'arg' => 'e_id',
'required' => FALSE,
'values' => 'a valid entityId',
'description' => 'a valid entityId (full string), either e_id or row_id is required',
],
[
'arg' => 'opt',
'required' => FALSE,
'values' => '"internal" or none',
'description' => 'only useful with the html format setting, internal is meant for internal'
. ' system use and does not contain the CSS info.'
],
$this->addStdArgument('format'),
],
'examples' => [
['opt' => ['e_id' => 'https://sso.umk.pl/idp/shibboleth', 'opt' => 'standalone'],
'format' => 'html',
'title' => 'show the entity on a standalone HTML page'],
['opt' => ['e_id' => 'https://sso.umk.pl/idp/shibboleth'],
'format' => 'default',
'title' => 'show the entity info in json format'],
],
]);
if ($this->opts['help'] == 1) {
return "";
}
$e = new eduGAIN_entityDetails();
$entity_html = $e->printEntity($this->opts['row_id'], $this->opts['e_id']);
if ($this->format !== 'html') {
return $e->entity;
}
if ($this->opts['opt'] !== 'internal' && $this->format === 'html') {
$out = $e->printHeader();
}
$out .= $entity_html;
return $out;
}
private function list_api_actions() {
$this->description(
[
'header' => "Show the list of available actions",
'supportedFormats' => ['format setting is not used'],
]
);
if ($this->opts['help'] == 1) {
return "";
}
$this->format = 'html';
$A = get_class_methods('API');
$Out = [];
foreach ($A as $a) {
if (preg_match('/^action_/', $a))
$Out[] = substr($a, 7);
}
sort($Out);
if ($this->format == 'html') {
$this->printHelpHeaders();
$out = '<p>
The general API call syntax is by the specification of the <i>action</i> argument:
<pre>'.ROOT_URL.'/api.php?action=action_name</pre>
If either no action or an unrecognised action is specified <b>this</b> page is shown.
Additional arguments can be added and they are specified in every action escription. Adding the <i>help</i> argument will cause the description to be displayed and all other arguments be disregarded.
The <i>format</i> argument is common to all API calls and in most cases allows to generate the result in a desired form. Currently each action needs to be consulted for a list of supported formats.
<p>
Click action names for a full description.</p>';
$out .= '<ul>';
foreach ($Out as $action) {
$out .= '<li><a href="api.php?action='.$action.'&help">'.$action.'</a></li>';
}
$out .= '</ul>';
} else {
$out = $Out;
}
$out .= "</div>";
return $out;
}
private function action_get_entity_name() {
$this->description([
'header' => "Show the entity display name, this works as a name resolver of sorts. The name is shown in the specified lanuage (if the corresponfing value exists) or in English as a fallback.",
'supportedFormats' => ['print_r', 'json'],
'arguments' => [
[
'arg' => 'e_id',
'required' => TRUE,
'values' => 'eitityID string',
'description' => 'entityID to search for',
],
[
'arg' => 'type',
'required' => FALSE,
'values' => '7 or "all" - all entities; 4 or "idp" - IdPs only; 2 or "sp" - SPs only; 1 or "aa" - standalone AAs only.',
'default' => 7,
'description' => 'limits the results to a givien entity type',
],
[
'arg' => 'lang',
'required' => FALSE,
'values' => '',
'description' => ''
],
[
'arg' => 'opt',
'required' => FALSE,
'values' => '1 show request innitiator; none or any other - do not show',
'description' => ''
]
],
'returns' => ['description' => 'an array of names assigned to entity roles'],
'examples' => [
[ 'opt' => ['e_id' => 'https://sso.umk.pl/idp/shibboleth'], 'title' => 'show default name'],
['opt' => ['e_id' => 'https://sso.umk.pl/idp/shibboleth',
'lang' => 'pl',],
'title' => 'show the Polish name'],
],
]);
if ($this->opts['help'] == 1) {
return "";
}
if ($this->opts['e_id'] == 'NOTSET') {
return "";
}
$e = new eduGAIN_entity();
$details = $e->showEntityName($this->opts['e_id'], $this->opts['lang'], $this->opts['type']);
if ($this->opts['opt'] == 1) {
$out = $details;
} else {
$out = $details[0];
}
return $out;
}
private function action_show_global_history() {
$this->description([
'header' => "Show global eduGAIN history. In no <i>data</i>, <i>start_date</i>, <i>end_date</i> arguments are specified, the current day is used",
'supportedFormats' => ['json', 'print_r'],
'arguments' => [
$this->addStdArgument('date'),
$this->addStdArgument('start_date'),
$this->addStdArgument('end_date'),
[
'arg' => 'details',
'required' => FALSE,
'default' => '0',
'values' => '1 - show history details, any other value is mapped to 0',
'description' => '',
],
[
'arg' => 'not_empty',
'required' => FALSE,
'default' => '0',
'values' => '0 - no filter, 1 - apply filter',
'description' => 'Show only those history entires that have enitiy count filled in (older statistics are not complete)',
],
$this->addStdArgument('format'),
],
'returns' => ['description' => ''],
'examples' => [
['opt' =>[], 'title' => 'show current numbers'],
['opt' =>['start_date' => '2023-01-01'], 'title' => 'show history since 2023-01-01'],
['opt' =>['start_date' => '2023-01-01', 'details' => 1], 'title' => 'show history since 2023-01-01 with more details'],
],
]);
if ($this->opts['help'] == 1) {
return "";
}
$startDate = $this->opts['start_date'];
$endDate = $this->opts['end_date'];
if ($this->opts['date']) {
$startDate = $this->opts['date'];
$endDate = $this->opts['date'];
}
$notEmpty = $this->opts['not_empty'];
$edugainHistory = new eduGAIN_history();
if ($this->opts['details'] == 1) {
$out = $edugainHistory->getFullHistory($startDate, $endDate);
} else {
$out = $edugainHistory->getGlobalHistory($startDate, $endDate, $notEmpty);
}
return $out;
}
private function action_show_per_federation_history() {
$this->description([
'header' => "Show eduGAIN history in a per-federation split. In no <i>data</i>, <i>start_date</i>, <i>end_date</i> arguments are specified, the current day is used",
'supportedFormats' => ['json', 'print_r'],
'arguments' => [
$this->addStdArgument('fed_id'),
$this->addStdArgument('reg_auth'),
[
'arg' => 'date',
'required' => FALSE,
'default' => 'yesterday',
'values' => 'Any date in the format YYYY-MM-DD is allowed.',
'description' => 'The data for the single date is shown. If this argument is present then <i>start_date</i> and <i>end_date</i> are not taken into account.',
],
$this->addStdArgument('start_date'),
$this->addStdArgument('end_date'),
$this->addStdArgument('format'),
],
'returns' => ['description' => ''],
'examples' => [
['opt' =>[], 'title' => 'show newest numbers'],
['opt' =>['start_date' => '2023-01-01'], 'title' => 'show history since 2023-01-01'],
['opt' =>['start_date' => '2023-01-01', 'details' => 1], 'title' => 'show history since 2023-01-01 with more details'],
],
]);
if ($this->opts['help'] == 1) {
return "";
}
$startDate = $this->opts['start_date'];
if ($startDate == 0) {
$startDate = -1;
}
$endDate = $this->opts['end_date'];
if ($this->opts['date']) {
$startDate = $this->opts['date'];
$endDate = $this->opts['date'];
}
$edugainHistory = new eduGAIN_history();
$out = $edugainHistory->getPerFederationHistory($this->fed_id, $startDate, $endDate);
return $out;
}
private function action_list_federation_map_codes() {
$this->description([
'header' => "Show show country/region codes served by federations, used internally for map generation.",
'supportedFormats' => ['json', 'print_r'],
'arguments' => [
$this->addStdArgument('format'),
[
'arg' => 'opt',
'required' => FALSE,
'default' => '0',
'values' => '0, 1',
'description' => '0 - show all; 1 - only production feds',
],
],
]);
if ($this->opts['help'] == 1) {
return "";
}
$productionOnly = $this->opts['opt'];
if ($productionOnly != 1) {
$productionOnly = 0;
}
$edugain = new eduGAIN($productionOnly);
$edugain->load_federation_map_codes();
$F = $edugain->FEDS;
ksort($F, SORT_STRING | SORT_FLAG_CASE);
foreach ($F as $fed => $A) {
$out[$fed] = ['code' => $fed, 'status' => $A['status'], 'country_code' => $A['country_code']];
}
return $out;
}
private function action_show_map() {
$this->description([
'header' => "Show eduGAIN maps as a PNG image",
'supportedFormats' => ['png'],
'arguments' => [
[
'arg' => 'opt',
'required' => FALSE,
'default' => '0',
'values' => '0, 1',
'description' => 'with value 1 only show production federations',
],
[
'arg' => 'map_type',
'required' => FALSE,
'values' => "europe, world",
'default' => 'world',
'description' => "Defines if the Europe or a full world map is to be shown",
],
[
'arg' => 'map_size',
'required' => FALSE,
'default' => 'large',
'values' => 'large, small',
'description' => 'The map size, only matters for the world map',
],
],
'returns' => ['description' => ''],
'examples' => [
['opt' => [], 'title' => 'the default - large worl map'],
['opt' => ['map_type' => 'europe'], 'title' => 'the Europe map'],
['opt' => ['map_size' => 'small'], 'title' => 'small world map'],
],
]);
if ($this->opts['help'] == 1) {
return "";
}
$this->format = 'png';
if ($this->opts['opt'] == 1) {
$mapSuffix = '_active';
} else {
$mapSuffix = '';
}
if ($this->opts['map_type'] == 'europe') {
$mapName = TECHNICAL_HOME.'/web/maps/europe'.$mapSuffix.'.png';
} else {
$mapName = TECHNICAL_HOME.'/web/maps/world_'.$this->opts['map_size'].$mapSuffix.'.png';
}
return file_get_contents($mapName);
}
private function action_show_entity_history() {
$this->description([
'header' => "Show a count or list of entities that have appeared in eduGAIN in a given period of time.
Entities that have appeared and also vanished in this perion and have been never seen again, are not counted
unless specifically asked for. The list/count can be limited to a given role of and entity (IdP, SP, AA-only).",
'supportedFormats' => ['json', 'print_r'],
'arguments' => [
[
'arg' => 'type',
'required' => FALSE,
'values' => '7 - all entities; 4 - IdPs only; 2 - SPs only; 1 - standalone AAs only.',
'default' => 7,
'description' => 'limits the results to a givien entity type',
],
[
'arg' => 'opt',
'required' => FALSE,
'default' => '0',
'values' => '0, 1, 2',
'description' => 'with value 0 only show entities present in the current feed, with value 1 also show entities which have been withdrawn, with value 2 show withdrown entites only.',
],
$this->addStdArgument('start_date'),
$this->addStdArgument('end_date'),
[
'arg' => 'show_list',
'required' => FALSE,
'values' => 'Not set or 0 - show only the count; any value except 0 - show the list of entities.',
'description' => 'The data until this date is shown. This argument is diregarded in the presence of the <i>date</i> argument.',
],
[
'arg' => 'e_id',
'required' => FALSE,
'values' => 'any string',
'description' => 'Input for the entity search. If this is set then the start_date will be set to the beginning of history, type set to 7, opt set to 1, show_lost set to 1.',
],
$this->addStdArgument('format'),
],
'returns' => ['description' => ''],
'examples' => [
['opt' =>[], 'title' => 'full history'],
['opt' => ['opt' => 2, 'start_date' => '2022-01-01', 'show_list' => 1], 'title' => 'show the list of withrown entities since 2022-01-01']
],
]);
if ($this->opts['help'] == 1) {
return "";
}
$entity_status = $this->opts['opt'];
if ($entity_status != 1 && $entity_status != 2) {
$entity_status = 0;
}
$startDate = $this->opts['start_date'];
$endDate = $this->opts['end_date'];
if ($this->opts['date']) {
$startDate = $this->opts['date'];
$endDate = $this->opts['date'];
}
if ($this->opts['e_id'] !== 'NOTSET') {
$startDate = strtotime("2017-04-01");
$entity_status = 1;
}
$edugain = new eduGAIN_history();
$out = $edugain->getEntityHistory($startDate, $endDate, $this->opts['type'], $this->opts['show_list'], $this->opts['e_id'], $entity_status);
return $out;
}
/*
private function action_show_category_support() {
$this->description([
'header' => "Show the support for a given category in eduGAIN federtions (including SIRTFI which is not an entity category).",
'supportedFormats' => ['json', 'csv', 'print_r'],
'arguments' => [
[
'arg' => 'entity_cat',
'required' => FALSE,
'values' => ' 0 or none - no fileter; any valid entitycategory identiefier or https://refeds.org/sirtfi for SIRTFI',
'default' => 0,
'description' => 'limits the results to a given entity category identifier',
],
[
'arg' => 'format',
'required' => FALSE,
'default' => 'json',
'values' => 'any supported format',
'description' => '',
],
],
'returns' => ['description' => '']
]);
if($this->opts['help'] == 1) {
return "";
}
$edugain = new eduGAIN();
$out = $edugain->getCategorySupport($this->opts['entity_cat']);
return $out;
}
*/
private function action_validator_warnings() {
$this->description([
'header' => "Show validator codes and corresponding messages. The codes correspond to bit numbers, therefore to map them to valkues shown in entity details one needs to shift 1 lest by the number shown in the code and then binary mask it with the number provided by entity details validator_status value.",
'supportedFormats' => ['json', 'print_r'],
'arguments' => [
$this->addStdArgument('format'),
],
'returns' => ['description' => 'pairs (code, description string)']
]);
if ($this->opts['help'] == 1) {
return "";
}
$edugain = new eduGAIN();
return($edugain->getValidatorWarningsDict());
}
private function action_entity_attributes() {
$this->description([
'header' => "Show entity attribute dictionary.",
'supportedFormats' => ['json', 'print_r'],
'arguments' => [
$this->addStdArgument('format'),
],
'returns' => ['description' => 'associative array'],
'examples' => [['opt' => [], 'title' => 'show the dictionary'],],
]);
if ($this->opts['help'] == 1) {
return "";
}
$edugain = new eduGAIN();
return($edugain->getEntityAttributeDict());
}
private function action_link_tests() {
$this->description([
'header' => "Show the list of link test results. The result gives a cummulative view on links of given type. "
. 'If there are several docments listed under the same type then the result wil show failure uness all these documents are OK. '
. 'The last OK status will allso be understood as depending on the whole group.',
'supportedFormats' => ['json', 'print_r'],
'arguments' => [
$this->addStdArgument('fed_id'),
$this->addStdArgument('reg_auth'),
$this->addStdArgument('date'),
$this->addStdArgument('start_date'),
$this->addStdArgument('end_date'),
[
'arg' => 'only_errors',
'required' => FALSE,
'values' => '1 to indicate the option is set, any other value will be disregarded',
'description' => 'Show only tests that failed.',
],
$this->addStdArgument('format'),
],
'returns' => ['description' => 'Arrays of structured data - one entry per link type and test time.'],
'examples' => [['opt' => [], 'title' => 'Status list from the last test'],],
]);
if ($this->opts['help'] == 1) {
return "";
}
$startDate = $this->opts['start_date'];
$endDate = $this->opts['end_date'];
if ($this->opts['date']) {
$startDate = $this->opts['date'];
$endDate = $this->opts['date'];
}
$edugain = new eduGAIN_history();
$out = $edugain->getLinkHistory($startDate, $endDate, $this->fed_id, $this->opts['only_errors']);
return $out;
}
private function action_link_tests_details() {
$edugain = new eduGAIN_history();
$this->description([
'header' => "Show the detailed list of link test results. Contrary to the link_tests call, the last OK is shown per document",
'supportedFormats' => ['json', 'print_r'],
'arguments' => [
$this->addStdArgument('fed_id'),
$this->addStdArgument('reg_auth'),
$this->addStdArgument('date'),
$this->addStdArgument('start_date'),
$this->addStdArgument('end_date'),
[
'arg' => 'only_errors',
'required' => FALSE,
'values' => '1 to indicate the option is set, any other value will be disregarded',
'description' => 'Show only tests that failed.',
],
[
'arg' => 'url_type',
'required' => FALSE,
'values' => implode(", ", $edugain->getUrlTypes()),
'description' => 'If set, limit the results to the given url_type. Values which are out of scope will be treated as empty',
],
$this->addStdArgument('format'),
],
'returns' => ['description' => 'Arrays of structured data - one entry per link type and test time.'],
'examples' => [['opt' => [], 'title' => 'Status list from the last test'],],
]);
if ($this->opts['help'] == 1) {
return "";
}
$startDate = $this->opts['start_date'];
$endDate = $this->opts['end_date'];
if ($this->opts['date']) {
$startDate = $this->opts['date'];
$endDate = $this->opts['date'];
}
$out = $edugain->getLinkTestsDetails($startDate, $endDate, $this->fed_id, $this->opts['only_errors'], $this->opts['url_type']);
return $out;
}
private function output($out) {
if ($this->opts['help'] == 1) {
$this->printDescription();
return;
}
switch ($this->format) {
case 'json':
header('Content-type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');
print json_encode($out, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
break;
case 'print_r':
header('Content-type: text/html; charset=utf-8');
print "<pre>";
print_r($out);
print "</pre>";
break;
case 'xml':
header('Content-type: text/xml');
print $out;
break;
case 'csv':
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: inline; filename="entites.csv"');
print $out;
break;
case 'html':
header('Content-type: text/html; charset=utf-8');
print '<html xmlns="http://www.w3.org/1999/xhtml">';
print $out;
break;
case 'png':
header('Content-type: image/png');
print $out;
break;
default:
break;
}
}
private function addStdArgument($argName, $required = FALSE) {
$arg = $this->stdArguments[$argName];
$arg['required'] = $required;
return($arg);
}
private $stdArguments = [
'format' => [
'arg' => 'format',
'required' => FALSE,
'default' => 'json',
'values' => 'any supported format',
'description' => '',
],
'fed_id' => [
'arg' => 'fed_id',
'required' => FALSE,
'values' => 'a federation code (see <a href="api.php?action=list_fed_codes&help">list_fed_codes</a> for a list of available codes).',
'description' => 'Limits the results to a single federation.',
],
'date' => [
'arg' => 'date',
'required' => FALSE,
'default' => 'today',
'values' => 'Any date in the format YYYY-MM-DD is allowed.',
'description' => 'The data for the single date is shown. If this argument is present then <i>start_date</i> and <i>end_date</i> are not taken into account.',
],
'start_date' => [
'arg' => 'start_date',
'required' => FALSE,
'values' => 'Any date in the format YYYY-MM-DD is allowed.',
'description' => 'The data starting from this date is shown. This argument is diregarded in the presence of the <i>date</i> argument.',
],
'end_date' => [
'arg' => 'end_date',
'required' => FALSE,
'values' => 'Any date in the format YYYY-MM-DD is allowed.',
'description' => 'The data until this date is shown. This argument is diregarded in the presence of the <i>date</i> argument.',
],
'reg_auth' => [
'arg' => 'reg_auth',
'reuired' => FALSE,
'values' => 'a federation registration authority URN',
'description' => "Limits the results to a single federation. If fed_id argument is also present then it takes precedence over reg_auth",
],
];
}