Skip to content

Commit

Permalink
Rewrite php-saml to use ZF naming conventions, PSR-0 structure, impro…
Browse files Browse the repository at this point in the history
…ve repo layout, add Metadata generation, improve tests
  • Loading branch information
Boy Baukema committed Apr 6, 2012
1 parent ef5e154 commit 3eee672
Show file tree
Hide file tree
Showing 13 changed files with 417 additions and 223 deletions.
2 changes: 1 addition & 1 deletion README
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
The files index.php, consume.php and settings.php are sample code to help
The files in demo are sample code to help
demonstrate how this library should work. In order to use them, you can
unpack this library in your website directory.

Expand Down
26 changes: 19 additions & 7 deletions demo/consume.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,32 @@

error_reporting(E_ALL);

$settings = NULL;
require 'settings.php';

require 'lib/onelogin/saml.php';

$samlResponse = new OneLogin_Saml_Response(saml_get_settings(), $_POST['SAMLResponse']);
$samlResponse = new OneLogin_Saml_Response($settings, $_POST['SAMLResponse']);

try {
if ($samlResponse->is_valid()) {
echo "You are: " . $samlResponse->get_nameid();
if ($samlResponse->isValid()) {
echo 'You are: ' . $samlResponse->getNameId() . '<br>';
$attributes = $samlResponse->getAttributes();
if (!empty($attributes)) {
echo 'You have the following attributes:<br>';
echo '<table><thead><th>Name</th><th>Values</th></thead><tbody>';
foreach ($attributes as $attributeName => $attributeValues) {
echo '<tr><td>' . htmlentities($attributeName) . '</td><td><ul>';
foreach ($attributeValues as $attributeValue) {
echo '<li>' . htmlentities($attributeValue) . '</li>';
}
echo '</ul></td></tr>';
}
echo '</tbody></table>';
}
}
else {
echo "Invalid SAML response.";
echo 'Invalid SAML response.';
}
}
catch (Exception $e) {
echo "Invalid SAML response: " . $e->getMessage();
echo 'Invalid SAML response: ' . $e->getMessage();
}
7 changes: 3 additions & 4 deletions demo/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@

error_reporting(E_ALL);

$settings = NULL;
require 'settings.php';

require 'lib/onelogin/saml.php';

$authrequest = new OneLogin_Saml_AuthRequest(saml_get_settings());
$url = $authrequest->create();
$authRequest = new OneLogin_Saml_AuthRequest($settings);
$url = $authRequest->getRedirectUrl();

header("Location: $url");
21 changes: 15 additions & 6 deletions demo/metadata.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
<?php
/**
* Created by JetBrains PhpStorm.
* User: boy
* Date: 4/6/12
* Time: 9:31 AM
* To change this template use File | Settings | File Templates.
*/
* SAMPLE Code to demonstrate how to handle a SAML assertion response.
*
* Your IdP will usually want your metadata, you can use this code to generate it once,
* or expose it on a URL so your IdP can check it periodically.
*/

error_reporting(E_ALL);

$settings = NULL;
require 'settings.php';

header('Content-Type: text/xml');

$samlMetadata = new OneLogin_Saml_Metadata($settings);
echo $samlMetadata->getXml();
57 changes: 27 additions & 30 deletions demo/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,38 @@
/**
* SAMPLE Code to demonstrate how provide SAML settings.
*
* The settings are contained within a SamlSettings object. You need to
* The settings are contained within a OneLogin_Saml_Settings object. You need to
* provide, at a minimum, the following things:
* - idp_sso_target_url: This is the URL to forward to for auth requests.
*
* - idpSingleSignOnUrl
* This is the URL to forward to for auth requests.
* It will be provided by your IdP.
* - x509certificate: This is a certificate required to authenticate your
* request. This certificate should be provided by your IdP.
* - assertion_consumer_service_url: The URL that the IdP should redirect
* to once the authorization is complete. You must provide this, and it
* should point to the consume.php script or its equivalent.
*
* - idpPublicCertificate
* This is a certificate required to authenticate your request.
* This certificate should be provided by your IdP.
*
* - spReturnUrl
* The URL that the IdP should redirect to once the authorization is complete.
* You must provide this, and it should point to the consume.php script or its equivalent.
*/

define('XMLSECLIB_DIR', './../src')
define('XMLSECLIBS_DIR', './../ext/xmlseclibs/');
require XMLSECLIBS_DIR . 'xmlseclibs.php';

define('ONELOGIN_SAML_DIR', './../src/OneLogin/Saml/');
require ONELOGIN_SAML_DIR . 'AuthRequest.php';
require ONELOGIN_SAML_DIR . 'Response.php';
require ONELOGIN_SAML_DIR . 'Settings.php';
require ONELOGIN_SAML_DIR . 'XmlSec.php';

/**
* Return a SamlSettings object with user settings.
*/
function saml_get_settings()
{
// This function should be modified to return the SAML settings for the current user

$settings = new OneLogin_Saml_Settings();
$settings = new OneLogin_Saml_Settings();

// When using Service Provider Initiated SSO (starting at index.php), this URL asks the IdP to authenticate the user.
$settings->idp_sso_target_url = "https://app.onelogin.com/saml/signon/6171";
// When using Service Provider Initiated SSO (starting at index.php), this URL asks the IdP to authenticate the user.
$settings->idpSingleSignOnUrl = 'https://app.onelogin.com/saml/signon/6171';

// The certificate for the users account in the IdP
$settings->x509certificate = <<<ENDCERTIFICATE
// The certificate for the users account in the IdP
$settings->idpPublicCertificate = <<<CERTIFICATE
-----BEGIN CERTIFICATE-----
MIIBrTCCAaGgAwIBAgIBATADBgEAMGcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApD
YWxpZm9ybmlhMRUwEwYDVQQHDAxTYW50YSBNb25pY2ExETAPBgNVBAoMCE9uZUxv
Expand All @@ -47,17 +46,15 @@ function saml_get_settings()
UhLFIXkGSCAIVfoR5S2ggdfpINKUWGsWS/lEzLNYMBkURXuVAgMBAAEwAwYBAAMB
AA==
-----END CERTIFICATE-----
ENDCERTIFICATE;

// The URL where to the SAML Response/SAML Assertion will be posted
$settings->assertion_consumer_service_url = "http://localhost/php-saml/consume.php";
CERTIFICATE;

// Name of this application
$settings->issuer = "php-saml";
// The URL where to the SAML Response/SAML Assertion will be posted
$settings->spReturnUrl = 'http://localhost/php-saml/consume.php';

// Tells the IdP to return the email address of the current user
$settings->name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress";
// Name of this application
$settings->spIssuer = 'php-saml';

// Tells the IdP to return the email address of the current user
$settings->requestedNameIdFormat = OneLogin_Saml_Settings::NAMEID_EMAIL_ADDRESS;

return $settings;
}
return $settings;
62 changes: 56 additions & 6 deletions src/OneLogin/Saml/Metadata.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,58 @@
<?php

/**
* Created by JetBrains PhpStorm.
* User: boy
* Date: 4/6/12
* Time: 9:22 AM
* To change this template use File | Settings | File Templates.
*/
* Create SAML2 Metadata documents
*/
class OneLogin_Saml_Metadata
{
/**
* How long should the metadata be valid?
*/
const VALIDITY_SECONDS = 604800; // 1 week

/**
* Service settings
* @var OneLogin_Saml_Settings
*/
private $_settings;

/**
* Create a new Metadata document
* @param OneLogin_Saml_Settings $settings
*/
public function __construct(OneLogin_Saml_Settings $settings)
{
$this->_settings = $settings;
}

/**
* @return string
*/
public function getXml()
{
$validUntil = $this->_getMetadataValidTimestamp();

return <<<METADATA_TEMPLATE
<?xml version="1.0"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
validUntil="$validUntil"
entityID="{$this->_settings->spIssuer}">
<md:SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:NameIDFormat>{$this->_settings->requestedNameIdFormat}</md:NameIDFormat>
<md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="{$this->_settings->spReturnUrl}"
index="1"/>
</md:SPSSODescriptor>
</md:EntityDescriptor>
METADATA_TEMPLATE;
}

private function _getMetadataValidTimestamp()
{
$timeZone = date_default_timezone_get();
date_default_timezone_set('UTC');
$time = strftime("%Y-%m-%dT%H:%M:%SZ", time() + self::VALIDITY_SECONDS);
date_default_timezone_set($timeZone);
return $time;
}
}
76 changes: 42 additions & 34 deletions src/onelogin/saml/authrequest.php
Original file line number Diff line number Diff line change
@@ -1,68 +1,76 @@
<?php

/**
* Create a SAML authorization request.
*/
class SamlAuthRequest
class OneLogin_Saml_AuthRequest
{
const ID_PREFIX = 'ONELOGIN';

/**
* A SamlResponse class provided to the constructor.
* @var OneLogin_Saml_Settings
*/
private $settings;
private $_settings;

/**
* Construct the response object.
*
* @param SamlResponse $settings
* @param OneLogin_Saml_Settings $settings
* A SamlResponse settings object containing the necessary
* x509 certicate to decode the XML.
*/
function __construct($settings)
public function __construct(OneLogin_Saml_Settings $settings)
{
$this->settings = $settings;
$this->_settings = $settings;
}

/**
* Generate the request.
*
* @return
* A fully qualified URL that can be redirected to in order to process
* the authorization request.
* @return string A fully qualified URL that can be redirected to in order to process the authorization request.
*/
public function create()
public function getRedirectUrl()
{
$id = $this->generateUniqueID(20);
$issue_instant = $this->getTimestamp();
$id = $this->_generateUniqueID();
$issueInstant = $this->_getTimestamp();

$request =
"<samlp:AuthnRequest xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" ID=\"$id\" Version=\"2.0\" IssueInstant=\"$issue_instant\" ProtocolBinding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" AssertionConsumerServiceURL=\"" . $this->settings->assertion_consumer_service_url . "\">" .
"<saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">" . $this->settings->issuer . "</saml:Issuer>\n" .
"<samlp:NameIDPolicy xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" Format=\"" . $this->settings->name_identifier_format . "\" AllowCreate=\"true\"></samlp:NameIDPolicy>\n" .
"<samlp:RequestedAuthnContext xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" Comparison=\"exact\">" .
"<saml:AuthnContextClassRef xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef></samlp:RequestedAuthnContext>\n" .
"</samlp:AuthnRequest>";
$request = <<<AUTHNREQUEST
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
ID="$id"
Version="2.0"
IssueInstant="$issueInstant"
ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
AssertionConsumerServiceURL="{$this->_settings->spReturnUrl}">
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">{$this->_settings->spIssuer}</saml:Issuer>
<samlp:NameIDPolicy xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
Format="{$this->_settings->requestedNameIdFormat}"
AllowCreate="true"></samlp:NameIDPolicy>
<samlp:RequestedAuthnContext xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Comparison="exact">
<saml:AuthnContextClassRef xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
</samlp:RequestedAuthnContext>
</samlp:AuthnRequest>";
AUTHNREQUEST;

$deflated_request = gzdeflate($request);
$base64_request = base64_encode($deflated_request);
$encoded_request = urlencode($base64_request);
$deflatedRequest = gzdeflate($request);
$base64Request = base64_encode($deflatedRequest);
$encodedRequest = urlencode($base64Request);

return $this->settings->idp_sso_target_url . "?SAMLRequest=" . $encoded_request;
return $this->_settings->idpSingleSignOnUrl . "?SAMLRequest=" . $encodedRequest;
}

private function generateUniqueID($length)
private function _generateUniqueID()
{
$chars = "abcdef0123456789";
$chars_len = strlen($chars);
$uniqueID = "";
for ($i = 0; $i < $length; $i++)
$uniqueID .= substr($chars, rand(0, 15), 1);
return "_" . $uniqueID;
return self::ID_PREFIX . sha1(uniqid(mt_rand(), TRUE));
}

private function getTimestamp()
private function _getTimestamp()
{
$defaultTimezone = date_default_timezone_get();
date_default_timezone_set('UTC');
return strftime("%Y-%m-%dT%H:%M:%SZ");
$timestamp = strftime("%Y-%m-%dT%H:%M:%SZ");
date_default_timezone_set($defaultTimezone);
return $timestamp;
}
}

;
}
Loading

0 comments on commit 3eee672

Please sign in to comment.