Skip to content

Commit

Permalink
Provide better support to NameIdFormat
Browse files Browse the repository at this point in the history
  • Loading branch information
pitbulk committed Oct 28, 2016
1 parent a728538 commit 7d0dc69
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 10 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1131,6 +1131,7 @@ SAML 2 Authentication Response class
* `getNameIdData` - Gets the NameID Data provided by the SAML response from the
IdP.
* `getNameId` - Gets the NameID provided by the SAML response from the IdP.
* `getNameIdFormat` - Gets the NameID Format provided by the SAML response from the IdP.
* `getSessionNotOnOrAfter` - Gets the SessionNotOnOrAfter from the
AuthnStatement
* `getSessionIndex` - Gets the SessionIndex from the AuthnStatement.
Expand Down
8 changes: 7 additions & 1 deletion demo1/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,19 @@
$paramters = array();
$nameId = null;
$sessionIndex = null;
$nameIdFormat = null;

if (isset($_SESSION['samlNameId'])) {
$nameId = $_SESSION['samlNameId'];
}
if (isset($_SESSION['samlSessionIndex'])) {
$sessionIndex = $_SESSION['samlSessionIndex'];
}
if (isset($_SESSION['samlNameIdFormat'])) {
$nameIdFormat = $_SESSION['samlNameIdFormat'];
}

$auth->logout($returnTo, $paramters, $nameId, $sessionIndex);
$auth->logout($returnTo, $paramters, $nameId, $sessionIndex, false, $nameIdFormat);

# If LogoutRequest ID need to be saved in order to later validate it, do instead
# $sloBuiltUrl = $auth->logout(null, $paramters, $nameId, $sessionIndex, true);
Expand Down Expand Up @@ -70,6 +75,7 @@

$_SESSION['samlUserdata'] = $auth->getAttributes();
$_SESSION['samlNameId'] = $auth->getNameId();
$_SESSION['samlNameIdFormat'] = $auth->getNameIdFormat();
$_SESSION['samlSessionIndex'] = $auth->getSessionIndex();
unset($_SESSION['AuthNRequestID']);
if (isset($_POST['RelayState']) && OneLogin_Saml2_Utils::getSelfURL() != $_POST['RelayState']) {
Expand Down
23 changes: 21 additions & 2 deletions lib/Saml2/Auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ class OneLogin_Saml2_Auth
*/
private $_nameid;

/**
* NameID Format
*
* @var string
*/
private $_nameidFormat;

/**
* If user is authenticated.
*
Expand Down Expand Up @@ -126,6 +133,7 @@ public function processResponse($requestId = null)
if ($response->isValid($requestId)) {
$this->_attributes = $response->getAttributes();
$this->_nameid = $response->getNameId();
$this->_nameidFormat = $response->getNameIdFormat();
$this->_authenticated = true;
$this->_sessionIndex = $response->getSessionIndex();
$this->_sessionExpiration = $response->getSessionNotOnOrAfter();
Expand Down Expand Up @@ -265,6 +273,16 @@ public function getNameId()
return $this->_nameid;
}

/**
* Returns the nameID Format
*
* @return string The nameID Format of the assertion
*/
public function getNameIdFormat()
{
return $this->_nameidFormat;
}

/**
* Returns the SessionIndex
*
Expand Down Expand Up @@ -369,12 +387,13 @@ public function login($returnTo = null, $parameters = array(), $forceAuthn = fal
* @param string|null $nameId The NameID that will be set in the LogoutRequest.
* @param string|null $sessionIndex The SessionIndex (taken from the SAML Response in the SSO process).
* @param bool $stay True if we want to stay (returns the url string) False to redirect
* @param string|null $nameIdFormat The NameID Format will be set in the LogoutRequest.
*
* @return If $stay is True, it return a string with the SLO URL + LogoutRequest + parameters
*
* @throws OneLogin_Saml2_Error
*/
public function logout($returnTo = null, $parameters = array(), $nameId = null, $sessionIndex = null, $stay=false)
public function logout($returnTo = null, $parameters = array(), $nameId = null, $sessionIndex = null, $stay=false, $nameIdFormat = null)
{
assert('is_array($parameters)');

Expand All @@ -390,7 +409,7 @@ public function logout($returnTo = null, $parameters = array(), $nameId = null,
$nameId = $this->_nameid;
}

$logoutRequest = new OneLogin_Saml2_LogoutRequest($this->_settings, null, $nameId, $sessionIndex);
$logoutRequest = new OneLogin_Saml2_LogoutRequest($this->_settings, null, $nameId, $sessionIndex, $nameIdFormat);

$this->_lastRequestID = $logoutRequest->id;

Expand Down
15 changes: 9 additions & 6 deletions lib/Saml2/LogoutRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,13 @@ class OneLogin_Saml2_LogoutRequest
/**
* Constructs the Logout Request object.
*
* @param OneLogin_Saml2_Settings $settings Settings
* @param string|null $request A UUEncoded Logout Request.
* @param string|null $nameId The NameID that will be set in the LogoutRequest.
* @param string|null $sessionIndex The SessionIndex (taken from the SAML Response in the SSO process).
* @param OneLogin_Saml2_Settings $settings Settings
* @param string|null $request A UUEncoded Logout Request.
* @param string|null $nameId The NameID that will be set in the LogoutRequest.
* @param string|null $sessionIndex The SessionIndex (taken from the SAML Response in the SSO process).
* @param string|null $nameIdFormat The NameID Format will be set in the LogoutRequest.
*/
public function __construct(OneLogin_Saml2_Settings $settings, $request = null, $nameId = null, $sessionIndex = null)
public function __construct(OneLogin_Saml2_Settings $settings, $request = null, $nameId = null, $sessionIndex = null, $nameIdFormat = null)
{

$this->_settings = $settings;
Expand All @@ -62,7 +63,9 @@ public function __construct(OneLogin_Saml2_Settings $settings, $request = null,
}

if (!empty($nameId)) {
$nameIdFormat = $spData['NameIDFormat'];
if (empty($nameIdFormat)) {
$nameIdFormat = $spData['NameIDFormat'];
}
$spNameQualifier = null;
} else {
$nameId = $idpData['entityId'];
Expand Down
15 changes: 15 additions & 0 deletions lib/Saml2/Response.php
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,21 @@ public function getNameId()
return $nameIdvalue;
}

/**
* Gets the NameID Format provided by the SAML response from the IdP.
*
* @return string Name ID Format
*/
public function getNameIdFormat()
{
$nameIdFormat = null;
$nameIdData = $this->getNameIdData();
if (!empty($nameIdData) && isset($nameIdData['Format'])) {
$nameIdFormat = $nameIdData['Format'];
}
return $nameIdFormat;
}

/**
* Gets the SessionNotOnOrAfter from the AuthnStatement.
* Could be used to set the local session expiration
Expand Down
4 changes: 4 additions & 0 deletions tests/src/OneLogin/Saml2/AuthTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ public function testProcessNoResponse()
* @covers OneLogin_Saml2_Auth::getAttributes
* @covers OneLogin_Saml2_Auth::getAttribute
* @covers OneLogin_Saml2_Auth::getNameId
* @covers OneLogin_Saml2_Auth::getNameIdFormat
* @covers OneLogin_Saml2_Auth::getErrors
* @covers OneLogin_Saml2_Auth::getSessionIndex
* @covers OneLogin_Saml2_Auth::getSessionExpiration
Expand All @@ -105,6 +106,7 @@ public function testProcessResponseInvalid()
$this->assertFalse($this->_auth->isAuthenticated());
$this->assertEmpty($this->_auth->getAttributes());
$this->assertNull($this->_auth->getNameId());
$this->assertNull($this->_auth->getNameIdFormat());
$this->assertNull($this->_auth->getSessionIndex());
$this->assertNull($this->_auth->getSessionExpiration());
$this->assertNull($this->_auth->getAttribute('uid'));
Expand Down Expand Up @@ -153,6 +155,7 @@ public function testProcessResponseInvalidRequestId()
* @covers OneLogin_Saml2_Auth::getAttributes
* @covers OneLogin_Saml2_Auth::getAttribute
* @covers OneLogin_Saml2_Auth::getNameId
* @covers OneLogin_Saml2_Auth::getNameIdFormat
* @covers OneLogin_Saml2_Auth::getSessionIndex
* @covers OneLogin_Saml2_Auth::getSessionExpiration
* @covers OneLogin_Saml2_Auth::getErrors
Expand All @@ -165,6 +168,7 @@ public function testProcessResponseValid()
$this->_auth->processResponse();
$this->assertTrue($this->_auth->isAuthenticated());
$this->assertEquals('492882615acf31c8096b627245d76ae53036c090', $this->_auth->getNameId());
$this->assertEquals('urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress', $this->_auth->getNameIdFormat());
$attributes = $this->_auth->getAttributes();
$this->assertNotEmpty($attributes);
$this->assertEquals($this->_auth->getAttribute('mail'), $attributes['mail']);
Expand Down
34 changes: 33 additions & 1 deletion tests/src/OneLogin/Saml2/LogoutRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ public function testConstructorWithSessionIndex()
$sessionIndex = '_51be37965feb5579d803141076936dc2e9d1d98ebf';
$settings = new OneLogin_Saml2_Settings($settingsInfo);


$logoutRequest = new OneLogin_Saml2_LogoutRequest($settings, null, null, $sessionIndex);

$parameters = array('SAMLRequest' => $logoutRequest->getRequest());
Expand All @@ -104,6 +103,39 @@ public function testConstructorWithSessionIndex()
$this->assertEquals(array($sessionIndex), $sessionIndexes);
}

/**
* Tests the OneLogin_Saml2_LogoutRequest Constructor.
*
* @covers OneLogin_Saml2_LogoutRequest
*/
public function testConstructorWithNameIdFormat()
{
$settingsDir = TEST_ROOT .'/settings/';
include $settingsDir.'settings1.php';

$nameId = 'test@example.com';
$nameIdFormat = 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient';
$settings = new OneLogin_Saml2_Settings($settingsInfo);

$logoutRequest = new OneLogin_Saml2_LogoutRequest($settings, null, $nameId, null, $nameIdFormat);

$parameters = array('SAMLRequest' => $logoutRequest->getRequest());
$logoutUrl = OneLogin_Saml2_Utils::redirect('http://idp.example.com/SingleLogoutService.php', $parameters, true);
$this->assertRegExp('#^http://idp\.example\.com\/SingleLogoutService\.php\?SAMLRequest=#', $logoutUrl);
parse_str(parse_url($logoutUrl, PHP_URL_QUERY), $exploded);
// parse_url already urldecode de params so is not required.
$payload = $exploded['SAMLRequest'];
$decoded = base64_decode($payload);
$inflated = gzinflate($decoded);
$this->assertRegExp('#^<samlp:LogoutRequest#', $inflated);

$logoutNameId = OneLogin_Saml2_LogoutRequest::getNameId($inflated);
$this->assertEquals($nameId, $logoutNameId);

$logoutNameIdData = OneLogin_Saml2_LogoutRequest::getNameIdData($inflated);
$this->assertEquals($nameIdFormat, $logoutNameIdData['Format']);
}

/**
* Tests the OneLogin_Saml2_LogoutRequest Constructor.
* The creation of a deflated SAML Logout Request
Expand Down
29 changes: 29 additions & 0 deletions tests/src/OneLogin/Saml2/ResponseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,35 @@ public function testReturnNameId()
}
}

/**
* Tests the getNameIdFormat method of the OneLogin_Saml2_Response
*
* @covers OneLogin_Saml2_Response::getNameIdFormat
*/
public function testGetNameIdFormat()
{
$xml = file_get_contents(TEST_ROOT . '/data/responses/response1.xml.base64');
$response = new OneLogin_Saml2_Response($this->_settings, $xml);
$this->assertEquals('urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress', $response->getNameIdFormat());

$xml2 = file_get_contents(TEST_ROOT . '/data/responses/response_encrypted_nameid.xml.base64');
$response2 = new OneLogin_Saml2_Response($this->_settings, $xml2);
$this->assertEquals('urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified', $response2->getNameIdFormat());

$xml3 = file_get_contents(TEST_ROOT . '/data/responses/valid_encrypted_assertion.xml.base64');
$response3 = new OneLogin_Saml2_Response($this->_settings, $xml3);
$this->assertEquals('urn:oasis:names:tc:SAML:2.0:nameid-format:transient', $response3->getNameIdFormat());

$xml4 = file_get_contents(TEST_ROOT . '/data/responses/invalids/no_nameid.xml.base64');
$response4 = new OneLogin_Saml2_Response($this->_settings, $xml4);

try {
$nameId4 = $response4->getNameIdFormat();
} catch (Exception $e) {
$this->assertContains('Not NameID found in the assertion of the Response', $e->getMessage());
}
}

/**
* Tests the getNameIdData method of the OneLogin_Saml2_Response
*
Expand Down

0 comments on commit 7d0dc69

Please sign in to comment.