RewriteEngine on
RewriteBase /
-RewriteCond %{HTTP_HOST} hosting.fluidbook.com
-RewriteRule ^(.*)$ https://cabinotiers.vacheron-constantin.com/$1 [R=301,L]
-RewriteRule ^_secure.php$ - [L]
-RewriteRule ^.*$ _secure.php [L,QSA]
\ No newline at end of file
+RewriteCond %{HTTP_HOST} "^hosting.fluidbook.com"
+RewriteRule ^(.*)$ https://cabinotiers.vacheron-constantin.com/$1 [R=301,L]
\ No newline at end of file
--- /dev/null
+<?php
+session_start();
+$needsAuth = !(isset($_SESSION['samlOK']) && $_SESSION['samlOK']);
+header('Content-Type: application/json');
+die(json_encode(['data' => [['logged-in' => !$needsAuth,'session'=>print_r($_SESSION,true)]]]));
+++ /dev/null
-<?php
-
-use GuzzleHttp\Client;
-
-$logdir = __DIR__ . '/log/';
-
-if (!file_exists($logdir)) {
- mkdir($logdir, 0777, true);
-}
-
-$t = md5(rand(0, 10000000));
-if (isset($_POST) && count($_POST)) {
- file_put_contents($logdir . 'log.' . $t . '.log', print_r($_POST, true));
-}
-
-$basedir = '/';
-$base = 'https://cabinotiers.vacheron-constantin.com' . $basedir;
-//$metadata = 'https://login.microsoftonline.com/10c68b76-5682-4564-a75d-9ef796a2f318/federationmetadata/2007-06/federationmetadata.xml?appid=48b8e0f9-effd-41e9-b35e-6511459dee30';
-$metadata = 'https://login.microsoftonline.com/94b3f1b2-8b3a-49e3-ba33-8b8fb6d18361/federationmetadata/2007-06/federationmetadata.xml?appid=fd419245-db40-4031-856e-de24fbe41d13';
-
-$forbiddenext = ['php', 'htaccess', '_metadata'];
-foreach ($forbiddenext as $ext) {
-
- if (stripos($_SERVER['SCRIPT_URL'], "." . $ext) !== false) {
- http_response_code(403);
- exit;
- }
-}
-require_once "vendor/autoload.php";
-
-session_start();
-$needsAuth = !(isset($_SESSION['samlOK']) && $_SESSION['samlOK']);
-
-$file = $_SERVER['CONTEXT_DOCUMENT_ROOT'] . $_SERVER['SCRIPT_URL'];
-if (is_dir($file)) {
- $file .= '/index.html';
-}
-$index = strpos($file, 'index.html') !== false;
-
-if ($needsAuth) {
- $metadata = getMetadata();
-
- $url = $base;
- // put SAML settings into an array to avoid placing files in the
- // composer vendor/ directories
- $samlsettings = [
- 'sp' => [
- // Identifier of the SP entity (must be a URI)
- 'entityId' => $base,
- // Specifies info about where and how the <AuthnResponse> message MUST be
- // returned to the requester, in this case our SP.
- 'assertionConsumerService' => array(
- // URL Location where the <Response> from the IdP will be returned
- 'url' => $url,
- // SAML protocol binding to be used when returning the <Response>
- // message. Onelogin Toolkit supports for this endpoint the
- // HTTP-POST binding only
- 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',
- ),
-// // If you need to specify requested attributes, set a
-// // attributeConsumingService. nameFormat, attributeValue and
-// // friendlyName can be omitted. Otherwise remove this section.
-// "attributeConsumingService" => array(
-// "serviceName" => "SP test",
-// "serviceDescription" => "Test Service",
-// "requestedAttributes" => array(
-// array(
-// "name" => "",
-// "isRequired" => false,
-// "nameFormat" => "",
-// "friendlyName" => "",
-// "attributeValue" => ""
-// )
-// )
-// ),
-// // Specifies info about where and how the <Logout Response> message MUST be
-// // returned to the requester, in this case our SP.
-// 'singleLogoutService' => array(
-// // URL Location where the <Response> from the IdP will be returned
-// 'url' => '',
-// // SAML protocol binding to be used when returning the <Response>
-// // message. Onelogin Toolkit supports for this endpoint the
-// // HTTP-Redirect binding only
-// 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
-// ),
-// // Specifies constraints on the name identifier to be used to
-// // represent the requested subject.
-// // Take a look on lib/Saml2/Constants.php to see the NameIdFormat supported
-// 'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified',
-//
-// // Usually x509cert and privateKey of the SP are provided by files placed at
-// // the certs folder. But we can also provide them with the following parameters
-// 'x509cert' => '',
-// 'privateKey' => '',
-//
-// /*
-// * Key rollover
-// * If you plan to update the SP x509cert and privateKey
-// * you can define here the new x509cert and it will be
-// * published on the SP metadata so Identity Providers can
-// * read them and get ready for rollover.
-// */
-// // 'x509certNew' => '',
- ],
- 'idp' => [
- 'entityId' => $metadata['EntityDescriptor']['@entityID'],
- 'singleSignOnService' => [
- 'url' => $metadata['EntityDescriptor']['IDPSSODescriptor']['SingleSignOnService'][0]['@Location'],
- ],
- 'x509cert' => $metadata['EntityDescriptor']['IDPSSODescriptor']['KeyDescriptor']['KeyInfo']['X509Data']['X509Certificate'],
- ]];
-
- try {
- $auth = new \OneLogin\Saml2\Auth($samlsettings);
- } catch (Exception $e) {
- http_response_code(500);
- print_r($e);
- die('an error occured');
- }
-
- if (!empty($_POST['SAMLResponse']) && !empty($_POST['RelayState'])) {
- $auth->processResponse(null);
-
- $errors = $auth->getErrors();
- if (empty($errors)) {
- // user has authenticated successfully
- $needsAuth = false;
- $_SESSION['samlUserdata'] = $auth->getAttributes();
- $_SESSION['samlOK'] = true;
- session_write_close();
- file_put_contents($logdir.'ok.' . $t . '.log', print_r($_SESSION, true));
- file_put_contents($logdir. 'xml.' . $t . '.log', $auth->getLastResponseXML());
-
- if ($_POST['RelayState'] !== $base) {
- header('Location: ' . $_POST['RelayState'], true);
- exit;
- }
-
- } else {
- file_put_contents($logdir.'err.' . $t . '.log', print_r($errors, true) . "\n\n--\n\n" . print_r($auth->getLastErrorReason(), true) . "\n\n--\n\n" . print_r($auth->getLastErrorException(), true));
- }
- }
-
- if ($needsAuth) {
- if ($index) {
- $auth->login();
- } else {
- http_response_code(403);
- }
- exit;
- }
-}
-
-
-if (!file_exists($file)) {
- http_response_code(404);
- exit;
-}
-
-$e = explode('.', $file);
-$ext = mb_strtolower(array_pop($e));
-require_once "_mime.php";
-if (isset($mimes['mimes'][$ext])) {
- $mime = $mimes['mimes'][$ext][0];
-} else {
- $mime = mime_content_type($file);
-}
-
-header('Content-Type: ' . $mime);
-header('Content-Length: ' . filesize($file));
-header("X-Sendfile: $file");
-
-function xmlToArray($xml, $options = array())
-{
- $defaults = array(
- 'namespaceSeparator' => ':',//you may want this to be something other than a colon
- 'attributePrefix' => '@', //to distinguish between attributes and nodes with the same name
- 'alwaysArray' => array(), //array of xml tag names which should always become arrays
- 'autoArray' => true, //only create arrays for tags which appear more than once
- 'textContent' => '$', //key used for the text content of elements
- 'autoText' => true, //skip textContent key if node has no attributes or child nodes
- 'keySearch' => false, //optional search and replace on tag and attribute names
- 'keyReplace' => false //replace values for above search values (as passed to str_replace())
- );
- $options = array_merge($defaults, $options);
- $namespaces = $xml->getDocNamespaces(true);
- $namespaces[''] = null; //add base (empty) namespace
-
- //get attributes from all namespaces
- $attributesArray = array();
- foreach ($namespaces as $prefix => $namespace) {
- foreach ($xml->attributes($namespace) as $attributeName => $attribute) {
- //replace characters in attribute name
- if ($options['keySearch']) $attributeName =
- str_replace($options['keySearch'], $options['keyReplace'], $attributeName);
- $attributeKey = $options['attributePrefix']
- . ($prefix ? $prefix . $options['namespaceSeparator'] : '')
- . $attributeName;
- $attributesArray[$attributeKey] = (string)$attribute;
- }
- }
-
- //get child nodes from all namespaces
- $tagsArray = array();
- foreach ($namespaces as $prefix => $namespace) {
- foreach ($xml->children($namespace) as $childXml) {
- //recurse into child nodes
- $childArray = xmlToArray($childXml, $options);
- list($childTagName, $childProperties) = each($childArray);
-
- //replace characters in tag name
- if ($options['keySearch']) $childTagName =
- str_replace($options['keySearch'], $options['keyReplace'], $childTagName);
- //add namespace prefix, if any
- if ($prefix) $childTagName = $prefix . $options['namespaceSeparator'] . $childTagName;
-
- if (!isset($tagsArray[$childTagName])) {
- //only entry with this key
- //test if tags of this type should always be arrays, no matter the element count
- $tagsArray[$childTagName] =
- in_array($childTagName, $options['alwaysArray']) || !$options['autoArray']
- ? array($childProperties) : $childProperties;
- } elseif (
- is_array($tagsArray[$childTagName]) && array_keys($tagsArray[$childTagName])
- === range(0, count($tagsArray[$childTagName]) - 1)
- ) {
- //key already exists and is integer indexed array
- $tagsArray[$childTagName][] = $childProperties;
- } else {
- //key exists so convert to integer indexed array with previous value in position 0
- $tagsArray[$childTagName] = array($tagsArray[$childTagName], $childProperties);
- }
- }
- }
-
- //get text content of node
- $textContentArray = array();
- $plainText = trim((string)$xml);
- if ($plainText !== '') $textContentArray[$options['textContent']] = $plainText;
-
- //stick it all together
- $propertiesArray = !$options['autoText'] || $attributesArray || $tagsArray || ($plainText === '')
- ? array_merge($attributesArray, $tagsArray, $textContentArray) : $plainText;
-
- //return node as array
- return array(
- $xml->getName() => $propertiesArray
- );
-}
-
-function getMetadata()
-{
- global $metadata;
- $limit = time() - 14400;
- $cachefile = __DIR__ . '/_metadata';
-
- if (!file_exists($cachefile) || filesize($cachefile) <= 20 || filemtime($cachefile) < $limit) {
- $client = new Client();
- $response = $client->get($metadata, ['timeout' => 30]);
- $c = $response->getBody()->getContents();
-
- if (!$c) {
- return json_decode(file_get_contents($cachefile), true);
- }
-
- $xml = simplexml_load_string($c);
-
- $metadata = xmlToArray($xml);
- file_put_contents($cachefile, json_encode($metadata));
- return $metadata;
- } else {
- return json_decode(file_get_contents($cachefile), true);
- }
-
-}
\ No newline at end of file
--- /dev/null
+<?php
+ini_set('display_errors', true);
+error_reporting(E_ALL);
+require_once "vendor/autoload.php";
+
+use GuzzleHttp\Client;
+use OneLogin\Saml2\Auth;
+
+$logdir = __DIR__ . '/log/';
+
+if (!file_exists($logdir)) {
+ mkdir($logdir, 0777, true);
+}
+
+$t = md5(rand(0, 10000000));
+if (isset($_POST) && count($_POST)) {
+ file_put_contents($logdir . 'log.' . $t . '.log', print_r($_POST, true));
+}
+
+
+$basedir = '/';
+$base = 'https://' . $_SERVER['HTTP_HOST'] . $basedir;
+if ($_SERVER['HTTP_HOST'] === 'cabinotiers.vacheron-constantin.com') {
+ $metadata = 'https://login.microsoftonline.com/94b3f1b2-8b3a-49e3-ba33-8b8fb6d18361/federationmetadata/2007-06/federationmetadata.xml?appid=fd419245-db40-4031-856e-de24fbe41d13';
+} else if ($_SERVER['HTTP_HOST'] === 'vacheron.hosting.fluidbook.com') {
+ $metadata = 'https://login.microsoftonline.com/10c68b76-5682-4564-a75d-9ef796a2f318/federationmetadata/2007-06/federationmetadata.xml?appid=48b8e0f9-effd-41e9-b35e-6511459dee30';
+}
+
+session_start();
+$needsAuth = !(isset($_SESSION['samlOK']) && $_SESSION['samlOK']);
+
+if (isset($_GET['return'])) {
+ $_SESSION['return'] = $_GET['return'];
+}
+
+
+if ($needsAuth) {
+ $metadata = getMetadata();
+
+ $url = $base;
+ // put SAML settings into an array to avoid placing files in the
+ // composer vendor/ directories
+ $samlsettings = [
+ 'sp' => [
+ // Identifier of the SP entity (must be a URI)
+ 'entityId' => $base,
+ // Specifies info about where and how the <AuthnResponse> message MUST be
+ // returned to the requester, in this case our SP.
+ 'assertionConsumerService' => array(
+ // URL Location where the <Response> from the IdP will be returned
+ 'url' => $url,
+ // SAML protocol binding to be used when returning the <Response>
+ // message. Onelogin Toolkit supports for this endpoint the
+ // HTTP-POST binding only
+ 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',
+ ),
+// // If you need to specify requested attributes, set a
+// // attributeConsumingService. nameFormat, attributeValue and
+// // friendlyName can be omitted. Otherwise remove this section.
+// "attributeConsumingService" => array(
+// "serviceName" => "SP test",
+// "serviceDescription" => "Test Service",
+// "requestedAttributes" => array(
+// array(
+// "name" => "",
+// "isRequired" => false,
+// "nameFormat" => "",
+// "friendlyName" => "",
+// "attributeValue" => ""
+// )
+// )
+// ),
+// // Specifies info about where and how the <Logout Response> message MUST be
+// // returned to the requester, in this case our SP.
+// 'singleLogoutService' => array(
+// // URL Location where the <Response> from the IdP will be returned
+// 'url' => '',
+// // SAML protocol binding to be used when returning the <Response>
+// // message. Onelogin Toolkit supports for this endpoint the
+// // HTTP-Redirect binding only
+// 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
+// ),
+// // Specifies constraints on the name identifier to be used to
+// // represent the requested subject.
+// // Take a look on lib/Saml2/Constants.php to see the NameIdFormat supported
+// 'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified',
+//
+// // Usually x509cert and privateKey of the SP are provided by files placed at
+// // the certs folder. But we can also provide them with the following parameters
+// 'x509cert' => '',
+// 'privateKey' => '',
+//
+// /*
+// * Key rollover
+// * If you plan to update the SP x509cert and privateKey
+// * you can define here the new x509cert and it will be
+// * published on the SP metadata so Identity Providers can
+// * read them and get ready for rollover.
+// */
+// // 'x509certNew' => '',
+ ],
+ 'idp' => [
+ 'entityId' => $metadata['EntityDescriptor']['@entityID'],
+ 'singleSignOnService' => [
+ 'url' => $metadata['EntityDescriptor']['IDPSSODescriptor']['SingleSignOnService'][0]['@Location'],
+ ],
+ 'x509cert' => $metadata['EntityDescriptor']['IDPSSODescriptor']['KeyDescriptor']['KeyInfo']['X509Data']['X509Certificate'],
+ ]];
+
+ try {
+ $auth = new Auth($samlsettings);
+ } catch (Exception $e) {
+ http_response_code(500);
+ print_r($e);
+ die('an error occured');
+ }
+
+ if (!empty($_POST['SAMLResponse']) && !empty($_POST['RelayState'])) {
+ $auth->processResponse(null);
+
+ $errors = $auth->getErrors();
+ if (empty($errors)) {
+ // user has authenticated successfully
+ $needsAuth = false;
+ $_SESSION['samlUserdata'] = $auth->getAttributes();
+ $_SESSION['samlOK'] = true;
+ header('Location: ' . $_SESSION['return']);
+ unset($_SESSION['return']);
+ session_write_close();
+ file_put_contents($logdir . 'ok.' . $t . '.log', print_r($_SESSION, true));
+ file_put_contents($logdir . 'xml.' . $t . '.log', $auth->getLastResponseXML());
+ } else {
+ file_put_contents($logdir . 'err.' . $t . '.log', print_r($errors, true) . "\n\n--\n\n" . print_r($auth->getLastErrorReason(), true) . "\n\n--\n\n" . print_r($auth->getLastErrorException(), true));
+ }
+ } else {
+ $auth->login();
+ }
+}
+
+
+function xmlToArray($xml, $options = array())
+{
+ $defaults = array(
+ 'namespaceSeparator' => ':',//you may want this to be something other than a colon
+ 'attributePrefix' => '@', //to distinguish between attributes and nodes with the same name
+ 'alwaysArray' => array(), //array of xml tag names which should always become arrays
+ 'autoArray' => true, //only create arrays for tags which appear more than once
+ 'textContent' => '$', //key used for the text content of elements
+ 'autoText' => true, //skip textContent key if node has no attributes or child nodes
+ 'keySearch' => false, //optional search and replace on tag and attribute names
+ 'keyReplace' => false //replace values for above search values (as passed to str_replace())
+ );
+ $options = array_merge($defaults, $options);
+ $namespaces = $xml->getDocNamespaces(true);
+ $namespaces[''] = null; //add base (empty) namespace
+
+ //get attributes from all namespaces
+ $attributesArray = array();
+ foreach ($namespaces as $prefix => $namespace) {
+ foreach ($xml->attributes($namespace) as $attributeName => $attribute) {
+ //replace characters in attribute name
+ if ($options['keySearch']) $attributeName =
+ str_replace($options['keySearch'], $options['keyReplace'], $attributeName);
+ $attributeKey = $options['attributePrefix']
+ . ($prefix ? $prefix . $options['namespaceSeparator'] : '')
+ . $attributeName;
+ $attributesArray[$attributeKey] = (string)$attribute;
+ }
+ }
+
+ //get child nodes from all namespaces
+ $tagsArray = array();
+ foreach ($namespaces as $prefix => $namespace) {
+ foreach ($xml->children($namespace) as $childXml) {
+ //recurse into child nodes
+ $childArray = xmlToArray($childXml, $options);
+ foreach ($childArray as $childTagName => $childProperties) {
+ break;
+ }
+ //list($childTagName, $childProperties) = each($childArray);
+
+ //replace characters in tag name
+ if ($options['keySearch']) $childTagName =
+ str_replace($options['keySearch'], $options['keyReplace'], $childTagName);
+ //add namespace prefix, if any
+ if ($prefix) $childTagName = $prefix . $options['namespaceSeparator'] . $childTagName;
+
+ if (!isset($tagsArray[$childTagName])) {
+ //only entry with this key
+ //test if tags of this type should always be arrays, no matter the element count
+ $tagsArray[$childTagName] =
+ in_array($childTagName, $options['alwaysArray']) || !$options['autoArray']
+ ? array($childProperties) : $childProperties;
+ } elseif (
+ is_array($tagsArray[$childTagName]) && array_keys($tagsArray[$childTagName])
+ === range(0, count($tagsArray[$childTagName]) - 1)
+ ) {
+ //key already exists and is integer indexed array
+ $tagsArray[$childTagName][] = $childProperties;
+ } else {
+ //key exists so convert to integer indexed array with previous value in position 0
+ $tagsArray[$childTagName] = array($tagsArray[$childTagName], $childProperties);
+ }
+ }
+ }
+
+ //get text content of node
+ $textContentArray = array();
+ $plainText = trim((string)$xml);
+ if ($plainText !== '') $textContentArray[$options['textContent']] = $plainText;
+
+ //stick it all together
+ $propertiesArray = !$options['autoText'] || $attributesArray || $tagsArray || ($plainText === '')
+ ? array_merge($attributesArray, $tagsArray, $textContentArray) : $plainText;
+
+ //return node as array
+ return array(
+ $xml->getName() => $propertiesArray
+ );
+}
+
+function getMetadata()
+{
+ global $metadata;
+ $limit = time() - 14400;
+ $cachefile = __DIR__ . '/_metadata';
+
+ if (!file_exists($cachefile) || filesize($cachefile) <= 20 || filemtime($cachefile) < $limit) {
+ $client = new Client();
+ $response = $client->get($metadata, ['timeout' => 30]);
+ $c = $response->getBody()->getContents();
+
+ if (!$c) {
+ return json_decode(file_get_contents($cachefile), true);
+ }
+
+ $xml = simplexml_load_string($c);
+
+ $metadata = xmlToArray($xml);
+ file_put_contents($cachefile, json_encode($metadata));
+ return $metadata;
+ } else {
+ return json_decode(file_get_contents($cachefile), true);
+ }
+
+}
\ No newline at end of file
{
"require": {
- "php": ">=7.0",
+ "php": ">=8.0",
"ext-json": "*",
"ext-xml": "*",
"guzzlehttp/guzzle": "^7.0",
--- /dev/null
+<?php
+session_start();
+if(isset($_SESSION['return'])){
+ require_once "_sso.php";
+ exit;
+}
+header('Location: /EN/');
\ No newline at end of file