Skip to content
Snippets Groups Projects
Commit 319731d4 authored by Nils Behlen's avatar Nils Behlen
Browse files

improved comments, add realm to triggerchallenge

parent 27012b9d
No related branches found
No related tags found
No related merge requests found
<?php <?php
namespace PrivacyIdea\PHPClient; //namespace PrivacyIdea\PHPClient;
class PIBadRequestException extends \Exception {} class PIBadRequestException extends Exception
{ {}
}
\ No newline at end of file
<?php <?php
namespace PrivacyIdea\PHPClient; //namespace PrivacyIdea\PHPClient;
class PIChallenge class PIChallenge
{ {
/* @var string Token's type. */ /* @var string Type of the token this challenge is for. */
public $type = ""; public $type = "";
/* @var string Message from single challenge. */
/* @var string Message for this challenge. */
public $message = ""; public $message = "";
/* @var string */
/* @var string TransactionId to reference this challenge in later requests. */
public $transactionID = ""; public $transactionID = "";
/* @var string Token's serial. */
/* @var string Serial of the token this challenge is for. */
public $serial = ""; public $serial = "";
/* @var string */
/* @var string Arbitrary attributes that can be appended to the challenge by the server. */
public $attributes = ""; public $attributes = "";
/* @var string JSON format */ /* @var string JSON format */
public $webAuthnSignRequest = ""; public $webAuthnSignRequest = "";
/* @var string JSON format */ /* @var string JSON format */
public $u2fSignRequest = ""; public $u2fSignRequest = "";
} }
\ No newline at end of file
<?php <?php
namespace PrivacyIdea\PHPClient; //namespace PrivacyIdea\PHPClient;
/** /**
* Interface PILog * Logging interface. This is used to relay the log messages of the PHP-Client to the logger implementation of the project that uses the client.
* Call the functions that collect debug and error messages
*/ */
interface PILog interface PILog
{ {
......
<?php <?php
namespace PrivacyIdea\PHPClient; //namespace PrivacyIdea\PHPClient;
class PIResponse class PIResponse
{ {
/* @var string All tokens messages which are sent by PI and can be used in UI to help user interact with service. */ /* @var string Combined messages of all triggered token. */
public $messages = ""; public $messages = "";
/* @var string PI message. */
/* @var string Message from the response. Should be shown to the user. */
public $message = ""; public $message = "";
/* @var string Transaction ID which is needed by some PI API requests. */
/* @var string TransactionID is used to reference the challenges contained in this response in later requests. */
public $transactionID = ""; public $transactionID = "";
/* @var string This is the raw PI response in JSON format. */
/* @var string Raw response in JSON format. */
public $raw = ""; public $raw = "";
/* @var array Here are all triggered challenges delivered as object of PIChallenge class. */
/* @var array Array of PIChallenge objects representing triggered token challenges. */
public $multiChallenge = array(); public $multiChallenge = array();
/* @var bool The status indicates if the request was processed correctly by the server. */
/* @var bool Status indicates if the request was processed successfully by the server. */
public $status = false; public $status = false;
/* @var bool The value tell us if authentication was successful. */
/* @var bool Value is true if the authentication was successful. */
public $value = false; public $value = false;
/* @var array All interesting details about user which can be shown in the UI at the end of the authentication. */
/* @var array Additional attributes of the user that can be sent by the server. */
public $detailAndAttributes = array(); public $detailAndAttributes = array();
/* @var string PI error code will be delivered here. */
/* @var string If an error occurred, the error code will be set. */
public $errorCode; public $errorCode;
/* @var string PI error message will be delivered here. */
/* @var string If an error occurred, the error message will be set. */
public $errorMessage; public $errorMessage;
/** /**
* Prepare a good readable PI response and return it as an object * Create a PIResponse object from the json response of the server.
*
* @param $json * @param $json
* @param PrivacyIDEA $privacyIDEA * @param PrivacyIDEA $privacyIDEA
* @return PIResponse|null * @return PIResponse|null returns null if the response of the server is empty or malformed
*/ */
public static function fromJSON($json, PrivacyIDEA $privacyIDEA) public static function fromJSON($json, PrivacyIDEA $privacyIDEA)
{ {
...@@ -37,25 +47,22 @@ class PIResponse ...@@ -37,25 +47,22 @@ class PIResponse
if ($json == null || $json == "") if ($json == null || $json == "")
{ {
$privacyIDEA->errorLog("PrivacyIDEA - PIResponse: No response from PI."); $privacyIDEA->errorLog("Response from server is empty.");
return null; return null;
} }
// Build an PIResponse object and decode the response from JSON to PHP
$ret = new PIResponse(); $ret = new PIResponse();
$map = json_decode($json, true); $map = json_decode($json, true);
// If wrong response format - throw error
if ($map == null) if ($map == null)
{ {
$privacyIDEA->errorLog("PrivacyIDEA - PIResponse: Response from PI was in wrong format. JSON expected."); $privacyIDEA->errorLog("Response from the server is malformed:\n" . $json);
return null; return null;
} }
// Prepare raw JSON Response if needed
$ret->raw = $json; $ret->raw = $json;
// Possibility to show an error message from PI server if no value // If value is not present, an error occurred
if (!isset($map['result']['value'])) if (!isset($map['result']['value']))
{ {
$ret->errorCode = $map['result']['error']['code']; $ret->errorCode = $map['result']['error']['code'];
...@@ -63,7 +70,6 @@ class PIResponse ...@@ -63,7 +70,6 @@ class PIResponse
return $ret; return $ret;
} }
// Set information from PI response to property
if (isset($map['detail']['messages'])) if (isset($map['detail']['messages']))
{ {
$ret->messages = implode(", ", array_unique($map['detail']['messages'])) ?: ""; $ret->messages = implode(", ", array_unique($map['detail']['messages'])) ?: "";
...@@ -79,7 +85,7 @@ class PIResponse ...@@ -79,7 +85,7 @@ class PIResponse
$ret->status = $map['result']['status'] ?: false; $ret->status = $map['result']['status'] ?: false;
$ret->value = $map['result']['value'] ?: false; $ret->value = $map['result']['value'] ?: false;
// Prepare attributes and detail // Attributes and detail
if (!empty($map['detail']['user'])) if (!empty($map['detail']['user']))
{ {
$attributes = $map['detail']['user']; $attributes = $map['detail']['user'];
...@@ -93,7 +99,7 @@ class PIResponse ...@@ -93,7 +99,7 @@ class PIResponse
$ret->detailAndAttributes = array("detail" => $detail, "attributes" => $attributes); $ret->detailAndAttributes = array("detail" => $detail, "attributes" => $attributes);
} }
// Set all challenges to objects and set it all to one array // Add any challenges to multiChallenge
if (isset($map['detail']['multi_challenge'])) if (isset($map['detail']['multi_challenge']))
{ {
$mc = $map['detail']['multi_challenge']; $mc = $map['detail']['multi_challenge'];
...@@ -128,7 +134,7 @@ class PIResponse ...@@ -128,7 +134,7 @@ class PIResponse
} }
/** /**
* Get array with all triggered token types. * Get an array with all triggered token types.
* @return array * @return array
*/ */
public function triggeredTokenTypes() public function triggeredTokenTypes()
...@@ -142,7 +148,7 @@ class PIResponse ...@@ -142,7 +148,7 @@ class PIResponse
} }
/** /**
* Get OTP message if OTP token(s) triggered. * Get the message of any token that is not Push or WebAuthn. Those are OTP token requiring an input field.
* @return string * @return string
*/ */
public function otpMessage() public function otpMessage()
...@@ -158,7 +164,7 @@ class PIResponse ...@@ -158,7 +164,7 @@ class PIResponse
} }
/** /**
* Get push message if push token triggered. * Get the Push token message if any were triggered.
* @return string * @return string
*/ */
public function pushMessage() public function pushMessage()
...@@ -174,7 +180,7 @@ class PIResponse ...@@ -174,7 +180,7 @@ class PIResponse
} }
/** /**
* Get WebAuthn message if that kind of token triggered. * Get the WebAuthn token message if any were triggered.
* @return string * @return string
*/ */
public function webauthnMessage() public function webauthnMessage()
...@@ -190,8 +196,8 @@ class PIResponse ...@@ -190,8 +196,8 @@ class PIResponse
} }
/** /**
* Get WebAuthn Sign Request which comes in PIResponse if WebAuthn token is triggered. * Get the WebAuthnSignRequest for any triggered WebAuthn token. If none were triggered, this returns an empty string.
* @return string * @return string WebAuthnSignRequest or empty string
*/ */
public function webAuthnSignRequest() public function webAuthnSignRequest()
{ {
...@@ -209,11 +215,21 @@ class PIResponse ...@@ -209,11 +215,21 @@ class PIResponse
$arr[] = $challenge->attributes['webAuthnSignRequest']['allowCredentials'][0]; $arr[] = $challenge->attributes['webAuthnSignRequest']['allowCredentials'][0];
} }
} }
$webauthn->allowCredentials = $arr; if (empty($webauthn))
{
return json_encode($webauthn); return "";
}
else
{
$webauthn->allowCredentials = $arr;
return json_encode($webauthn);
}
} }
/**
* Get the U2FSignRequest for any triggered U2F token. If none were triggered, this returns an empty string.
* @return string U2FSignRequest or empty string
*/
public function u2fSignRequest() public function u2fSignRequest()
{ {
$ret = ""; $ret = "";
......
<?php <?php
namespace PrivacyIdea\PHPClient; //namespace PrivacyIdea\PHPClient;
const AUTHENTICATORDATA = "authenticatordata"; const AUTHENTICATORDATA = "authenticatordata";
const CLIENTDATA = "clientdata"; const CLIENTDATA = "clientdata";
...@@ -18,28 +18,36 @@ const ASSERTIONCLIENTEXTENSIONS = "assertionclientextensions"; ...@@ -18,28 +18,36 @@ const ASSERTIONCLIENTEXTENSIONS = "assertionclientextensions";
*/ */
class PrivacyIDEA class PrivacyIDEA
{ {
/* @var string Plugins name which must to be verified in privacyIDEA. */ /* @var string UserAgent to use in requests made to privacyIDEA. */
public $userAgent = ""; public $userAgent = "";
/* @var string This is the URL to your privacyIDEA server. */
/* @var string URL of the privacyIDEA server. */
public $serverURL = ""; public $serverURL = "";
/* @var string Here is realm of users account. */ /* @var string Here is realm of users account. */
public $realm = ""; public $realm = "";
/* @var bool You can decide if you want to verify your ssl certificate. */
/* @var bool Host verification can be disabled in SSL. */
public $sslVerifyHost = true; public $sslVerifyHost = true;
/* @var bool You can decide if you want to verify your ssl certificate. */
/* @var bool Peer verification can be disabled in SSL. */
public $sslVerifyPeer = true; public $sslVerifyPeer = true;
/* @var string Username to your service account. You need it to get auth token which is needed by some PI API requests. */
/* @var string Account name for a service account to the privacyIDEA server. This is required to use the /validate/triggerchallenge endpoint. */
public $serviceAccountName = ""; public $serviceAccountName = "";
/* @var string Password to your service account. You need it to get auth token which is needed by some PI API requests. */
/* @var string Password for a service account to the privacyIDEA server. This is required to use the /validate/triggerchallenge endpoint. */
public $serviceAccountPass = ""; public $serviceAccountPass = "";
/* @var string If needed you can add it too. */
/* @var string Realm for a service account to the privacyIDEA server. This is required to use the /validate/triggerchallenge endpoint. This is optional. */
public $serviceAccountRealm = ""; public $serviceAccountRealm = "";
/* @var object This object will deliver PI debug and error messages to your plugin so you can log it wherever you want. */
/* @var object Implementation of the PILog interface. */
public $logger = null; public $logger = null;
/** /**
* PrivacyIDEA constructor. * PrivacyIDEA constructor.
* @param $userAgent string the user agent that should set in the http header * @param $userAgent string the user agent that should be used for the requests made
* @param $serverURL string the url of the privacyIDEA server * @param $serverURL string the url of the privacyIDEA server
*/ */
public function __construct($userAgent, $serverURL) public function __construct($userAgent, $serverURL)
...@@ -49,36 +57,12 @@ class PrivacyIDEA ...@@ -49,36 +57,12 @@ class PrivacyIDEA
} }
/** /**
* This function collect the debug messages and send it to PILog.php * Try to authenticate the user with the /validate/check endpoint.
* @param $message
*/
function debugLog($message)
{
if ($this->logger != null)
{
$this->logger->piDebug($message);
}
}
/**
* This function collect the error messages and send it to PILog.php
* @param $message
*/
function errorLog($message)
{
if ($this->logger != null)
{
$this->logger->piError($message);
}
}
/**
* Handle validateCheck using user's username, password and if challenge response - transaction_id.
* *
* @param $username string Must be set * @param $username string
* @param $pass string Must be set * @param $pass string this can be the OTP, but also the PIN to trigger a token or PIN+OTP depending on the configuration of the server.
* @param null $transactionID Optional transaction ID. Used to reference a challenge that was triggered beforehand. * @param null $transactionID Optional transaction ID. Used to reference a challenge that was triggered beforehand.
* @return PIResponse|null This method returns an PIResponse object which contains all the useful information from the PI server. In case of error returns null. * @return PIResponse|null null if response was empty or malformed, or parameter missing
* @throws PIBadRequestException * @throws PIBadRequestException
*/ */
public function validateCheck($username, $pass, $transactionID = null) public function validateCheck($username, $pass, $transactionID = null)
...@@ -86,17 +70,14 @@ class PrivacyIDEA ...@@ -86,17 +70,14 @@ class PrivacyIDEA
assert('string' === gettype($username)); assert('string' === gettype($username));
assert('string' === gettype($pass)); assert('string' === gettype($pass));
// Log entry of the validateCheck() // Check if parameters are set
$this->debugLog("validateCheck() with user=" . $username . ", pass=" . $pass . " and if is set transactionID " . $transactionID);
//Check if parameters are set
if (!empty($username) || !empty($pass)) if (!empty($username) || !empty($pass))
{ {
$params["user"] = $username; $params["user"] = $username;
$params["pass"] = $pass; $params["pass"] = $pass;
if (!empty($transactionID)) if (!empty($transactionID))
{ {
//Add transaction ID in case of challenge response // Add transaction ID in case of challenge response
$params["transaction_id"] = $transactionID; $params["transaction_id"] = $transactionID;
} }
if ($this->realm) if ($this->realm)
...@@ -104,20 +85,18 @@ class PrivacyIDEA ...@@ -104,20 +85,18 @@ class PrivacyIDEA
$params["realm"] = $this->realm; $params["realm"] = $this->realm;
} }
//Call send_request function to handle an API Request using $parameters and return it.
$response = $this->sendRequest($params, array(''), 'POST', '/validate/check'); $response = $this->sendRequest($params, array(''), 'POST', '/validate/check');
//Return the response from /validate/check as PIResponse object
$ret = PIResponse::fromJSON($response, $this); $ret = PIResponse::fromJSON($response, $this);
if ($ret == null) if ($ret == null)
{ {
$this->debugLog("privacyIDEA - Validate Check: no response from PI-server"); $this->debugLog("Server did not respond.");
} }
return $ret; return $ret;
} else }
else
{ {
//Handle debug message if $username is empty $this->debugLog("Missing username or pass for /validate/check.");
$this->debugLog("privacyIDEA - Validate Check: params incomplete!");
} }
return null; return null;
} }
...@@ -127,84 +106,69 @@ class PrivacyIDEA ...@@ -127,84 +106,69 @@ class PrivacyIDEA
* This function requires a service account to be set. * This function requires a service account to be set.
* *
* @param string $username * @param string $username
* @return PIResponse|null This method returns an PIResponse object which contains all the useful information from the PI server. * @return PIResponse|null null if response was empty or malformed, or parameter missing
* @throws PIBadRequestException * @throws PIBadRequestException
*/ */
public function triggerChallenge($username) public function triggerChallenge($username)
{ {
assert('string' === gettype($username)); assert('string' === gettype($username));
// Log entry of the pollTransaction()
$this->debugLog("triggerChallenge() with username=" . $username);
if ($username) if ($username)
{ {
$authToken = $this->getAuthToken(); $authToken = $this->getAuthToken();
// If error occurred in getAuthToken() - return this error in PIResponse object
$header = array("authorization:" . $authToken); $header = array("authorization:" . $authToken);
$parameter = array("user" => $username); $params = array("user" => $username);
//Call /validate/triggerchallenge with username as parameter and return it.
$response = $this->sendRequest($parameter, $header, 'POST', '/validate/triggerchallenge');
//Return the response from /validate/triggerchallenge as PIResponse object if ($this->realm)
$ret = PIResponse::fromJSON($response, $this);
if ($ret == null)
{ {
$this->debugLog("privacyIDEA - Trigger Challenge: no response from PI-server"); $params["realm"] = $this->realm;
} }
return $ret;
} else $response = $this->sendRequest($params, $header, 'POST', '/validate/triggerchallenge');
return PIResponse::fromJSON($response, $this);
}
else
{ {
//Handle debug message if empty $username $this->debugLog("Username missing!");
$this->debugLog("privacyIDEA - Trigger Challenge: no username");
} }
return null; return null;
} }
/** /**
* Call /validate/polltransaction using transaction_id * Poll for the status of a transaction (challenge).
* *
* @param $transactionID string An unique ID which is needed by some API requests. * @param $transactionID string transactionId of the push challenge that was triggered before
* @return bool Returns true if PUSH is accepted, false otherwise. * @return bool true if the Push request has been accepted, false otherwise.
* @throws PIBadRequestException * @throws PIBadRequestException
*/ */
public function pollTransaction($transactionID) public function pollTransaction($transactionID)
{ {
assert('string' === gettype($transactionID)); assert('string' === gettype($transactionID));
// Log entry of the pollTransaction()
$this->debugLog("pollTransaction() with transaction ID=" . $transactionID);
if (!empty($transactionID)) if (!empty($transactionID))
{ {
$params = array("transaction_id" => $transactionID); $params = array("transaction_id" => $transactionID);
// Call /validate/polltransaction using transactionID and decode it from JSON
$responseJSON = $this->sendRequest($params, array(''), 'GET', '/validate/polltransaction'); $responseJSON = $this->sendRequest($params, array(''), 'GET', '/validate/polltransaction');
$response = json_decode($responseJSON, true); $response = json_decode($responseJSON, true);
//Return the response from /validate/polltransaction
return $response['result']['value']; return $response['result']['value'];
}
} else else
{ {
//Handle debug message if $transactionID is empty $this->debugLog("TransactionID missing!");
$this->debugLog("privacyIDEA - Poll Transaction: No transaction ID");
} }
return false; return false;
} }
/** /**
* Check if user already has token * Check if user already has token and if not, enroll a new token
* Enroll a new token
* *
* @param string $username * @param string $username
* @param string $genkey * @param string $genkey
* @param string $type * @param string $type
* @param string $description * @param string $description
* @return mixed * @return mixed Object representing the response of the server or null if parameters are missing
* @throws PIBadRequestException * @throws PIBadRequestException
*/ */
public function enrollToken($username, $genkey, $type, $description = "") // No return type because mixed not allowed yet public function enrollToken($username, $genkey, $type, $description = "") // No return type because mixed not allowed yet
...@@ -217,14 +181,11 @@ class PrivacyIDEA ...@@ -217,14 +181,11 @@ class PrivacyIDEA
assert('string' === gettype($description)); assert('string' === gettype($description));
} }
// Log entry of the enrollToken()
$this->debugLog("privacyIDEA - enrollToken() with user=" . $username . ", genkey=" . $genkey . ", type=" . $type . ", description=" . $description);
// Check if parameters contain the required keys // Check if parameters contain the required keys
if (empty($username) || empty($type)) if (empty($username) || empty($type))
{ {
$this->debugLog("privacyIDEA - Enroll Token: Token enrollment not possible because params are not complete"); $this->debugLog("Token enrollment not possible because parameters are not complete");
return array(); return null;
} }
$params["user"] = $username; $params["user"] = $username;
...@@ -242,24 +203,24 @@ class PrivacyIDEA ...@@ -242,24 +203,24 @@ class PrivacyIDEA
if (!empty($tokenInfo->result->value->tokens)) if (!empty($tokenInfo->result->value->tokens))
{ {
$this->debugLog("privacyIDEA - Enroll Token: User already has a token. No need to enroll a new one."); $this->debugLog("enrollToken: User already has a token.");
return array(); return null;
}
} else else
{ {
// Call /token/init endpoint and return the PI response // Call /token/init endpoint and return the response
return json_decode($this->sendRequest($params, $header, 'POST', '/token/init')); return json_decode($this->sendRequest($params, $header, 'POST', '/token/init'));
} }
} }
/** /**
* Sends a request to /validate/check with the data required to authenticate a WebAuthn token. * Sends a request to /validate/check with the data required to authenticate with a WebAuthn token.
* *
* @param string $username * @param string $username
* @param string $transactionID * @param string $transactionID
* @param string $webAuthnSignResponse * @param string $webAuthnSignResponse
* @param string $origin * @param string $origin
* @return PIResponse|null * @return PIResponse|null returns null if the response was empty or malformed
* @throws PIBadRequestException * @throws PIBadRequestException
*/ */
public function validateCheckWebAuthn($username, $transactionID, $webAuthnSignResponse, $origin) public function validateCheckWebAuthn($username, $transactionID, $webAuthnSignResponse, $origin)
...@@ -269,13 +230,8 @@ class PrivacyIDEA ...@@ -269,13 +230,8 @@ class PrivacyIDEA
assert('string' === gettype($webAuthnSignResponse)); assert('string' === gettype($webAuthnSignResponse));
assert('string' === gettype($origin)); assert('string' === gettype($origin));
// Log entry of the validateCheckWebAuthn()
$this->debugLog("ValidateCheckWebAuthn with user=" . $username . ", transactionID=" . $transactionID . ", WebAuthnSignResponse=" . $webAuthnSignResponse . ", origin=" . $origin);
// Check if parameters are set
if (!empty($username) || !empty($transactionID)) if (!empty($username) || !empty($transactionID))
{ {
// Compose standard validate/check params // Compose standard validate/check params
$params["user"] = $username; $params["user"] = $username;
$params["pass"] = ""; $params["pass"] = "";
...@@ -307,25 +263,18 @@ class PrivacyIDEA ...@@ -307,25 +263,18 @@ class PrivacyIDEA
$response = $this->sendRequest($params, $header, 'POST', '/validate/check'); $response = $this->sendRequest($params, $header, 'POST', '/validate/check');
//Return the response from /validate/check as PIResponse object return PIResponse::fromJSON($response, $this);
$ret = PIResponse::fromJSON($response, $this); }
else
if ($ret == null)
{
$this->debugLog("privacyIDEA - WebAuthn: no response from PI-server");
}
return $ret;
} else
{ {
//Handle debug message if $username is empty // Handle debug message if $username is empty
$this->debugLog("privacyIDEA - WebAuthn: params incomplete!"); $this->debugLog("validateCheckWebAuthn: parameters are incomplete!");
} }
return null; return null;
} }
/** /**
* Sends a request to /validate/check with the data required to authenticate a U2F token. * Sends a request to /validate/check with the data required to authenticate with an U2F token.
* *
* @param string $username * @param string $username
* @param string $transactionID * @param string $transactionID
...@@ -339,13 +288,9 @@ class PrivacyIDEA ...@@ -339,13 +288,9 @@ class PrivacyIDEA
assert('string' === gettype($transactionID)); assert('string' === gettype($transactionID));
assert('string' === gettype($u2fSignResponse)); assert('string' === gettype($u2fSignResponse));
// Log entry of validateCheckU2F // Check if required parameters are set
$this->debugLog("ValidateCheckU2F with user=" . $username . ", transactionID=" . $transactionID . ", u2fSignResponse=" . $u2fSignResponse);
// Check if parameters are set
if (!empty($username) || !empty($transactionID) || !empty($u2fSignResponse)) if (!empty($username) || !empty($transactionID) || !empty($u2fSignResponse))
{ {
// Compose standard validate/check params // Compose standard validate/check params
$params["user"] = $username; $params["user"] = $username;
$params["pass"] = ""; $params["pass"] = "";
...@@ -363,19 +308,11 @@ class PrivacyIDEA ...@@ -363,19 +308,11 @@ class PrivacyIDEA
$response = $this->sendRequest($params, array(), 'POST', '/validate/check'); $response = $this->sendRequest($params, array(), 'POST', '/validate/check');
//Return the response from /validate/check as PIResponse object return PIResponse::fromJSON($response, $this);
$ret = PIResponse::fromJSON($response, $this); }
else
if ($ret == null)
{
$this->debugLog("privacyIDEA - U2F: no response from PI-server");
}
return $ret;
} else
{ {
//Handle debug message if $username is empty $this->debugLog("validateCheckU2F parameters are incomplete!");
$this->debugLog("privacyIDEA - U2F: params incomplete!");
} }
return null; return null;
} }
...@@ -390,21 +327,19 @@ class PrivacyIDEA ...@@ -390,21 +327,19 @@ class PrivacyIDEA
} }
/** /**
* Retrieves an auth token from the server using the service account. The auth token is required to make certain requests to privacyIDEA. * Retrieves an auth token from the server using the service account. An auth token is required for some requests to privacyIDEA.
* If no service account is set or an error occurred, this function returns false.
* *
* @return string|bool|PIResponse the auth token or false. * @return string the auth token or empty string if the response did not contain a token or no service account is configured.
* @throws PIBadRequestException * @throws PIBadRequestException if an error occurs during the request
*/ */
public function getAuthToken() public function getAuthToken()
{ {
if (!$this->serviceAccountAvailable()) if (!$this->serviceAccountAvailable())
{ {
$this->errorLog("Cannot retrieve auth token without service account"); $this->errorLog("Cannot retrieve auth token without service account!");
return false; return "";
} }
// To get auth token from server use API Request: /auth with added service account and service pass
$params = array( $params = array(
"username" => $this->serviceAccountName, "username" => $this->serviceAccountName,
"password" => $this->serviceAccountPass "password" => $this->serviceAccountPass
...@@ -415,29 +350,26 @@ class PrivacyIDEA ...@@ -415,29 +350,26 @@ class PrivacyIDEA
$params["realm"] = $this->serviceAccountRealm; $params["realm"] = $this->serviceAccountRealm;
} }
// Call /auth endpoint and decode the response from JSON to PHP
$response = json_decode($this->sendRequest($params, array(''), 'POST', '/auth'), true); $response = json_decode($this->sendRequest($params, array(''), 'POST', '/auth'), true);
if (!empty($response['result']['value'])) if (!empty($response['result']['value']))
{ {
// Get auth token from response->result->value->token and return the token return @$response['result']['value']['token'] ?: "";
return $response['result']['value']['token'];
} }
// If no response return false $this->debugLog("/auth response did not contain a auth token.");
$this->debugLog("privacyIDEA - getAuthToken: No response from PI-Server"); return "";
return false;
} }
/** /**
* Prepare send_request and make curl_init. * Send a request to an endpoint with the specified parameters and headers.
* *
* @param $params array request parameters in an array * @param $params array request parameters
* @param $headers array headers fields in array * @param $headers array headers fields
* @param $httpMethod string * @param $httpMethod string GET or POST
* @param $endpoint string endpoint of the privacyIDEA API (e.g. /validate/check) * @param $endpoint string endpoint of the privacyIDEA API (e.g. /validate/check)
* @return string returns string with response from server or an empty string if error occurs * @return string returns a string with the response from server
* @throws PIBadRequestException * @throws PIBadRequestException if an error occurres
*/ */
public function sendRequest(array $params, array $headers, $httpMethod, $endpoint) public function sendRequest(array $params, array $headers, $httpMethod, $endpoint)
{ {
...@@ -446,14 +378,11 @@ class PrivacyIDEA ...@@ -446,14 +378,11 @@ class PrivacyIDEA
assert('string' === gettype($httpMethod)); assert('string' === gettype($httpMethod));
assert('string' === gettype($endpoint)); assert('string' === gettype($endpoint));
$this->debugLog("Sending HEADER: " . http_build_query($headers, '', ', ') . ", with " . $httpMethod . " to " . $endpoint); $this->debugLog("Sending " . http_build_query($params, '', ', ') . " to " . $endpoint);
$this->debugLog("And PARAMS: " . http_build_query($params, '', ', '));
$curlInstance = curl_init();
// Compose an API Request using privacyIDEA's URL from config and endpoint created in function
$completeUrl = $this->serverURL . $endpoint; $completeUrl = $this->serverURL . $endpoint;
$curlInstance = curl_init();
curl_setopt($curlInstance, CURLOPT_URL, $completeUrl); curl_setopt($curlInstance, CURLOPT_URL, $completeUrl);
curl_setopt($curlInstance, CURLOPT_HEADER, true); curl_setopt($curlInstance, CURLOPT_HEADER, true);
if ($headers) if ($headers)
...@@ -466,8 +395,8 @@ class PrivacyIDEA ...@@ -466,8 +395,8 @@ class PrivacyIDEA
{ {
curl_setopt($curlInstance, CURLOPT_POST, true); curl_setopt($curlInstance, CURLOPT_POST, true);
curl_setopt($curlInstance, CURLOPT_POSTFIELDS, $params); curl_setopt($curlInstance, CURLOPT_POSTFIELDS, $params);
}
} elseif ($httpMethod === "GET") elseif ($httpMethod === "GET")
{ {
$paramsStr = '?'; $paramsStr = '?';
if (!empty($params)) if (!empty($params))
...@@ -480,12 +409,12 @@ class PrivacyIDEA ...@@ -480,12 +409,12 @@ class PrivacyIDEA
curl_setopt($curlInstance, CURLOPT_URL, $completeUrl . $paramsStr); curl_setopt($curlInstance, CURLOPT_URL, $completeUrl . $paramsStr);
} }
// Check if you should to verify privacyIDEA's SSL certificate in your config // Disable host and/or peer verification for SSL if configured.
// If true - do it, if false - don't verify
if ($this->sslVerifyHost === true) if ($this->sslVerifyHost === true)
{ {
curl_setopt($curlInstance, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($curlInstance, CURLOPT_SSL_VERIFYHOST, 2);
} else }
else
{ {
curl_setopt($curlInstance, CURLOPT_SSL_VERIFYHOST, 0); curl_setopt($curlInstance, CURLOPT_SSL_VERIFYHOST, 0);
} }
...@@ -493,35 +422,58 @@ class PrivacyIDEA ...@@ -493,35 +422,58 @@ class PrivacyIDEA
if ($this->sslVerifyPeer === true) if ($this->sslVerifyPeer === true)
{ {
curl_setopt($curlInstance, CURLOPT_SSL_VERIFYPEER, 2); curl_setopt($curlInstance, CURLOPT_SSL_VERIFYPEER, 2);
} else }
else
{ {
curl_setopt($curlInstance, CURLOPT_SSL_VERIFYPEER, 0); curl_setopt($curlInstance, CURLOPT_SSL_VERIFYPEER, 0);
} }
//Store response in the variable
$response = curl_exec($curlInstance); $response = curl_exec($curlInstance);
if (!$response) if (!$response)
{ {
//Handle error if no response and return an empty string // Handle error
$curlErrno = curl_errno($curlInstance); $curlErrno = curl_errno($curlInstance);
$this->errorLog("privacyIDEA-SDK: Bad request to PI server. " . curl_error($curlInstance) . " errno: " . $curlErrno); $this->errorLog("Bad request: " . curl_error($curlInstance) . " errno: " . $curlErrno);
throw new PIBadRequestException("Unable to reach the authentication server (" . $curlErrno . ")"); throw new PIBadRequestException("Unable to reach the authentication server (" . $curlErrno . ")");
} }
$headerSize = curl_getinfo($curlInstance, CURLINFO_HEADER_SIZE); $headerSize = curl_getinfo($curlInstance, CURLINFO_HEADER_SIZE);
$ret = substr($response, $headerSize); $ret = substr($response, $headerSize);
curl_close($curlInstance);
// Log the response // Log the response
if ($endpoint != "/auth") if ($endpoint != "/auth" && $this->logger != null)
{ {
$retJson = json_decode($ret, true); $retJson = json_decode($ret, true);
$this->debugLog($endpoint . " returned " . json_encode($retJson, JSON_PRETTY_PRINT)); $this->debugLog($endpoint . " returned " . json_encode($retJson, JSON_PRETTY_PRINT));
} }
curl_close($curlInstance); // Return decoded response
//Return decoded response from API Request
return $ret; return $ret;
} }
/**
* This function relays messages to the PILogger implementation
* @param $message
*/
function debugLog($message)
{
if ($this->logger != null)
{
$this->logger->piDebug("privacyIDEA-PHP-Client: " . $message);
}
}
/**
* This function relays messages to the PILogger implementation
* @param $message
*/
function errorLog($message)
{
if ($this->logger != null)
{
$this->logger->piError("privacyIDEA-PHP-Client: " . $message);
}
}
} }
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment