What is the best way to connect TYPO3 fe_users from an Azure AD with SAML 2?

Viewed 1315

I need to implement SSO on a TYPO3 intranet, where the fe_users are synchronized from an Azure AD. the platform will be in V9. Is there a compatible extension that I haven't found yet ? If no, what would be the best way to implement the automatic authentication with SAML 2.0 ? thanks in advance, Rachel

2 Answers

Thanks to @Rakel (and others) I managed to finally solve my SAML authentication requirement. Still I used a slightly different and more direct approach then described in her solution.

I used an Authentication Service to implement the SAML Login Process. For handling the SAML login itself I used the library SimpleSamlPHP, which I can truly recommend. Its really simple and the provided frontend to test the SAML configuration comes really handy to test the Identity Provider (Idp) configuration without dealing with TYPO3.

For details please look into this: https://docs.typo3.org/m/typo3/reference-coreapi/master/en-us/ApiOverview/Authentication/Index.html

First you need to create a class which extends TYPO3\CMS\Core\Authentication\AuthenticationService. This class must implement the methods "getUser" and "authUser".

namespace Vendor\Extension\Service;

use SimpleSAML\Auth\Simple;
use TYPO3\CMS\Core\Authentication\AuthenticationService;
class SamlAuth extends AuthenticationService
{

    public function getUser() {
        // Create new Simple Auth with SimpleSamlPHP
        $as = new Simple($config['sp']);
        // Require authentication, this redirects you to the Idp and then comes back
        $as->requireAuth();
        // Get the attributes provides by your Idp
        $attributes = $as->getAttributes();
        // Please consult the API for details on fetchUserRecord
        // Also the SAML attributes may vary depending on your Idp implementation
        $user = $this->fetchUserRecord($attributes['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name'];
    }

    public function authUser(array $user): int {
        return is_array($user) ? 200 : 0;
    }
}

Then you need to register the service in your extensions "ext_localconf.php".

...
TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addService(
      'my_extension',
      'auth',
      Vendor\Extension\Service\SamlAuth::class,
      [
          'title' => 'Saml Authentication for Frontend Users',
          'description' => 'Authenticates FeUsers via Saml',
          'subtype' => 'authUserFE,getUserFE',
          'available' => true,
          'priority' => 80,
          'quality' => 80,
          'os' => '',
          'exec' => '',
          'className' => Vendor\Extension\Service\SamlAuth::class
      ]
    );
...

Please note:

  • This is just a over simplified version of my final code. Just to get you started on the idea.
  • Also you need to configure SimpleSamlPHP correctly. Please look at their documentation for details.

The method "getUser" is supposed to return an array holding the to be logged in FeUser with all its parameters.

The method "authUser" is only to return 200 or 0. Take a look at this link to understand which number are there to return: https://docs.typo3.org/m/typo3/reference-services/7.6/en-us/Authentication/Index.html#authentication-service-chain After returning "200" the FeUser object is created and the user is logged in. No need to fiddle around with $GLOBALS['TSFE'] by yourself. This is a huge benefit, as it makes your code shorter and easier to read.

Nethertheless I learned a lot from reading through all the documentations and responses here and on Slacks TYPO3 channel. Thanks to everybody who helped me. Greatly appreciated.

Yes we solved that requirements. We used SimpleSAMLphp to implement the authentication, following this great tutorial : https://www.lewisroberts.com/2015/09/05/single-sign-on-to-azure-ad-using-simplesamlphp/.

When you are able to connect then you just have to implement a process to auto connect a fe_user when you get the saml user attributes.

Here is a simplified summary of the process:

if we reach a TYPO3 site url without being authenticated then redirection to a script like this :

// SimpleSamlPHP library
require_once (dirname(__FILE__) . /../../../../../../simplesamlphp/lib/_autoload.php');

//instanciation of a simple authentication
$as = new SimpleSAML_Auth_Simple('default-sp');

//requires authentication from Office 365
$as->requireAuth();

//retrieving information from the logged-in user
$attributes = $as->getAttributes();

//retrieve original url
$returnURL = $_GET['returnURL'];

//if a user is well connected
if($attributes){

    //redirection to the TYPO3 site with the username
    header('Location: /auth/?samlUident='.$attributes['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name'][0].'&recupURL='.$returnURL);
}

and here's a simplified summary of what the auth page does:

//if a get saml is in the url
if(\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('samlUident')){

    //recovering username for TYPO3 authentication
    $loginData = array(
        'uname' => \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('samlUident'), //username
        'status' => 'login'
    );

    //TYPO3 session creation
    $frontendUserAuthentication = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Authentication\\FrontendUserAuthentication');
    $frontendUserAuthentication->checkPid = false;
    $info = $frontendUserAuthentication->getAuthInfoArray();

    $user_db = $frontendUserAuthentication->fetchUserRecord($info['db_user'], $loginData['uname']);

    //if a user exists
    if ($user_db){

        //authentication
        $GLOBALS['TSFE']->fe_user->forceSetCookie = TRUE;
        $GLOBALS['TSFE']->fe_user->dontSetCookie = false;
        $GLOBALS['TSFE']->fe_user->start();
        $GLOBALS['TSFE']->fe_user->createUserSession($user_db);
        $GLOBALS['TSFE']->fe_user->user = $user_db;
        $GLOBALS['TSFE']->fe_user->setAndSaveSessionData('dummy', TRUE);
        $GLOBALS['TSFE']->fe_user->loginUser = 1;

    }
}

Cheers, Rachel

Related