176 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			176 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
namespace Jahnke\DjDiscourseSso\Controller;
 | 
						|
 | 
						|
/***************************************************************
 | 
						|
 *  Copyright notice
 | 
						|
 *
 | 
						|
 *  (c) 2016 Dirk Jahnke <dirk.jahnke@mailbox.org>
 | 
						|
 *
 | 
						|
 *  All rights reserved
 | 
						|
 *
 | 
						|
 *  This script is part of the TYPO3 project. The TYPO3 project is
 | 
						|
 *  free software; you can redistribute it and/or modify
 | 
						|
 *  it under the terms of the GNU General Public License as published by
 | 
						|
 *  the Free Software Foundation; either version 3 of the License, or
 | 
						|
 *  (at your option) any later version.
 | 
						|
 *
 | 
						|
 *  The GNU General Public License can be found at
 | 
						|
 *  http://www.gnu.org/copyleft/gpl.html.
 | 
						|
 *
 | 
						|
 *  This script is distributed in the hope that it will be useful,
 | 
						|
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
 *  GNU General Public License for more details.
 | 
						|
 *
 | 
						|
 *  This copyright notice MUST APPEAR in all copies of the script!
 | 
						|
 ***************************************************************/
 | 
						|
 | 
						|
use TYPO3\CMS\Core\Utility\GeneralUtility;
 | 
						|
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
 | 
						|
use \TYPO3\CMS\Extensionmanager\Utility\ConfigurationUtility;
 | 
						|
 | 
						|
/**
 | 
						|
 * Controller for the Member object
 | 
						|
 */
 | 
						|
class SsoController extends ActionController
 | 
						|
{
 | 
						|
 | 
						|
 | 
						|
    /**
 | 
						|
     * Compare if signed data matches given signature.
 | 
						|
     *
 | 
						|
     * @param string $data Signed data to be compared with.
 | 
						|
     * @param string $sig  Signature to be compared with.
 | 
						|
     *
 | 
						|
     * @return boolean
 | 
						|
     */
 | 
						|
    private function _hashsAreEqual($data, $sig)
 | 
						|
    {
 | 
						|
        if ($data === null || $sig === null || is_string($data) === false || is_string($sig) === false) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        if (strlen($data) !== strlen($sig)) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        if (strcmp($data, $sig) === 0) {
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
 | 
						|
        return false;
 | 
						|
 | 
						|
    }//end _hashsAreEqual()
 | 
						|
 | 
						|
 | 
						|
    /**
 | 
						|
     * Authenticate action.
 | 
						|
     *
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    public function authenticateAction()
 | 
						|
    {
 | 
						|
        $extKey = 'dj_discourse_sso';
 | 
						|
 | 
						|
        /** @var \TYPO3\CMS\Extensionmanager\Utility\ConfigurationUtility $configurationUtility */
 | 
						|
        $configurationUtility   = $this->objectManager->get(ConfigurationUtility::class);
 | 
						|
        $extensionConfiguration = $configurationUtility->getCurrentConfiguration($extKey);
 | 
						|
 | 
						|
        // GeneralUtility::devLog('authenticateAction-0', $extKey, 0, array('extKey' => $extKey));
 | 
						|
        // GeneralUtility::devLog('authenticateAction-1', $extKey, 0, array('config' => $extensionConfiguration));
 | 
						|
        // Check mandatory settings.
 | 
						|
        if (is_array($extensionConfiguration['redirect_url']) === false) {
 | 
						|
            $errorText = '<div><b>ERROR!</b> '
 | 
						|
                .'You should not see this message!<br />'
 | 
						|
                .'Could not find extension configuration for parameter redirect_url! '
 | 
						|
                .'Please configure the plugin.';
 | 
						|
            return $errorText;
 | 
						|
        } else {
 | 
						|
            $redirectUrlRoot = $extensionConfiguration['redirect_url']['value'];
 | 
						|
        }
 | 
						|
 | 
						|
        if (is_array($extensionConfiguration['shared_key']) === false) {
 | 
						|
            $errorText = '<div><b>ERROR!</b> '
 | 
						|
                .'You should not see this message!<br />'
 | 
						|
                .'Could not find extension configuration for parameter shared_key! '
 | 
						|
                .'Please configure the plugin.';
 | 
						|
            return $errorText;
 | 
						|
        } else {
 | 
						|
            $sharedKey = $extensionConfiguration['shared_key']['value'];
 | 
						|
        }
 | 
						|
 | 
						|
        // Set redirect status.
 | 
						|
        $redirectStatus = false;
 | 
						|
        if (is_array($extensionConfiguration['redirect_status']) === true) {
 | 
						|
            $redirectStatus = intval($extensionConfiguration['redirect_status']['value']);
 | 
						|
        }
 | 
						|
 | 
						|
        if ($redirectStatus === false || ($redirectStatus < 300 || $redirectStatus > 308)) {
 | 
						|
            // Set default.
 | 
						|
            $redirectStatus = 303;
 | 
						|
        }
 | 
						|
 | 
						|
        $sso  = urldecode(GeneralUtility::_GP('sso'));
 | 
						|
        $sig  = GeneralUtility::_GP('sig');
 | 
						|
        $hmac = hash_hmac('sha256', $sso, $sharedKey);
 | 
						|
        if ($this->_hashsAreEqual($hmac, $sig) === false) {
 | 
						|
            GeneralUtility::devLog('authenticateAction bad request', $extKey, 2, array('sso' => $sso, 'sig' => $sig, 'expected sig' => $hmac));
 | 
						|
            header('HTTP/1.1 403 Forbidden');
 | 
						|
            $this->throwStatus(403, 'Bad SSO request');
 | 
						|
        } else {
 | 
						|
            // Valid $sso string available, convert it.
 | 
						|
            parse_str(base64_decode($sso), $receivedPayload);
 | 
						|
            // Identify server entry in configuration.
 | 
						|
            $returnSsoUrl = $receivedPayload['return_sso_url'];
 | 
						|
 | 
						|
            // GeneralUtility::devLog('authenticateAction valid sso request', $extKey, 0, array('payload' => $receivedPayload));
 | 
						|
            $user = null;
 | 
						|
            if (isset($GLOBALS['TSFE']) === true
 | 
						|
                && isset($GLOBALS['TSFE']->fe_user) === true
 | 
						|
                && isset($GLOBALS['TSFE']->fe_user->user) === true
 | 
						|
            ) {
 | 
						|
                $user = $GLOBALS['TSFE']->fe_user->user;
 | 
						|
            }
 | 
						|
 | 
						|
            if (is_array($user) === true) {
 | 
						|
                if (is_null($user['email']) || strlen($user['email']) < 4) {
 | 
						|
                    $errorText = '<div><b>ERROR!</b><br>' .
 | 
						|
                                 'You did not enter your email address to your personal properties.<br>' .
 | 
						|
                                 'The forum cannot be used without a valid email address.<br>';
 | 
						|
                    GeneralUtility::devLog('authenticateAction: email address not available', $extKey, 2, array('error' => $errorText));
 | 
						|
                    return $errorText;
 | 
						|
                }
 | 
						|
                $userId      = $user['uid'];
 | 
						|
                $userEmail   = $user['email'];
 | 
						|
                $userName    = $user['username'];
 | 
						|
                $name        = $user['name'];
 | 
						|
                $nonce       = $receivedPayload['nonce'];
 | 
						|
                $parameters  = array(
 | 
						|
                                'nonce'       => $nonce,
 | 
						|
                                'external_id' => $userId,
 | 
						|
                                'email'       => $userEmail,
 | 
						|
                                'username'    => $userName,
 | 
						|
                                'name'        => $name,
 | 
						|
                               );
 | 
						|
                $payload     = base64_encode(http_build_query($parameters));
 | 
						|
                $signature   = hash_hmac('sha256', $payload, $sharedKey);
 | 
						|
                $query       = http_build_query(array('sso' => $payload, 'sig' => $signature));
 | 
						|
                $redirectUrl = $returnSsoUrl.'?'.$query;
 | 
						|
 | 
						|
                // GeneralUtility::devLog('authenticateAction successful, redirecting', $extKey, 0, array('redirectUrl' => $redirectUrl, 'status' => $redirectStatus, 'payload' => $payload, 'parameter' => $parameters));
 | 
						|
                $this->redirectToUri($redirectUrl, 0, $redirectStatus);
 | 
						|
            } else {
 | 
						|
                // No user logged in.
 | 
						|
                // Wrong setup! This plugin should be enabled only, if a user login exists.
 | 
						|
                $errorText = '<div><b>ERROR!</b> '
 | 
						|
                    .'You should not see this message!<br />'
 | 
						|
                    .'This plugin should be made available only, if a Frontend User is logged in.<br />'
 | 
						|
                    .'Please change this in the setup of this content element.';
 | 
						|
                GeneralUtility::devLog('authenticateAction: bad configuration', $extKey, 2, array('error' => $errorText));
 | 
						|
                return $errorText;
 | 
						|
            }//end if
 | 
						|
        }//end if
 | 
						|
        return '<div><b>Internal Error!</b><br>Unreachable code.</div>';
 | 
						|
    }//end authenticateAction()
 | 
						|
}
 |