]> _ Git - fluidbook-hosting.git/commitdiff
wait #5074 @3
authorVincent Vanwaelscappel <vincent@cubedesigners.com>
Tue, 22 Mar 2022 17:24:02 +0000 (18:24 +0100)
committerVincent Vanwaelscappel <vincent@cubedesigners.com>
Tue, 22 Mar 2022 17:24:02 +0000 (18:24 +0100)
VacheronSSO/.htaccess
VacheronSSO/_checksso.php [new file with mode: 0644]
VacheronSSO/_secure.php [deleted file]
VacheronSSO/_sso.php [new file with mode: 0644]
VacheronSSO/composer.json
VacheronSSO/index.php [new file with mode: 0644]

index e021dea82a161797d74160fa6b96a88e75e50e95..27316133a53f6a85bd51f6dc5fdfcf3f7309aeb1 100644 (file)
@@ -1,6 +1,4 @@
 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
diff --git a/VacheronSSO/_checksso.php b/VacheronSSO/_checksso.php
new file mode 100644 (file)
index 0000000..9768254
--- /dev/null
@@ -0,0 +1,5 @@
+<?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)]]]));
diff --git a/VacheronSSO/_secure.php b/VacheronSSO/_secure.php
deleted file mode 100644 (file)
index 0f1816a..0000000
+++ /dev/null
@@ -1,275 +0,0 @@
-<?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
diff --git a/VacheronSSO/_sso.php b/VacheronSSO/_sso.php
new file mode 100644 (file)
index 0000000..ca2123f
--- /dev/null
@@ -0,0 +1,246 @@
+<?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
index 277fb9097f0d9786b578eaa7135f504cad8a5b41..087886032e359f28b073e0e642b26143bdae6e7a 100644 (file)
@@ -1,6 +1,6 @@
 {
   "require": {
-    "php": ">=7.0",
+    "php": ">=8.0",
     "ext-json": "*",
     "ext-xml": "*",
     "guzzlehttp/guzzle": "^7.0",
diff --git a/VacheronSSO/index.php b/VacheronSSO/index.php
new file mode 100644 (file)
index 0000000..88d4134
--- /dev/null
@@ -0,0 +1,7 @@
+<?php
+session_start();
+if(isset($_SESSION['return'])){
+    require_once "_sso.php";
+    exit;
+}
+header('Location: /EN/');
\ No newline at end of file