Table of Contents

SimpleSAMLphp Authentication Backend

This authentication backend deals with a single sign on web authentication system based on SimpleSAMLphp and SAML2.

Requirements

Code

Save this under …/dokuwiki/inc/auth/ssp.class.php:

<?php
/**
 * SSP. SimpleSAMLphp authentication backend
 * auth/ssp.class.php
 *
 * @author  Jorge Hervás <jordihv@gmail.com>, Lukas Slansky <lukas.slansky@upce.cz>
 * @license GPL2 http://www.gnu.org/licenses/gpl.html
 * @version 0.2
 * @date    April 2012
 */
 
class auth_ssp extends auth_basic {
  var $users = null;
  // declaration of the auth_simple object 
  var $as;
 
  /**
   * Constructor.
   * Sets additional capabilities and config strings
   */
  function auth_ssp() {
    // we set the features of our authentication backend to TRUE, the base class defaults to FALSE the rest
    $this->cando['external'] = true;
    $this->cando['logoff']   = true;
    $this->success = true;
  }
 
  /**
   * Return user info (copy from plain.class.php)
   *
   * Returns info about the given user needs to contain
   * at least these fields:
   *
   * name string  full name of the user
   * mail string  email addres of the user
   * grps array   list of groups the user is in
   *
   * @author  Lukas Slansky <lukas.slansky@upce.cz>
   */
  function getUserData($user){
 
    if($this->users === null) $this->_loadUserData();
    return isset($this->users[$user]) ? $this->users[$user] : false;
  }
 
  /**
   * Load all user data (modified copy from plain.class.php)
   *
   * loads the user file into a datastructure
   *
   * @author  Lukas Slansky <lukas.slansky@upce.cz>
   */
  function _loadUserData(){
    global $conf;
 
    $this->users = array();
 
    if(!@file_exists($conf['ssp_usersfile'])) return;
 
    $lines = file($conf['ssp_usersfile']);
    foreach($lines as $line){
      $line = preg_replace('/#.*$/','',$line); //ignore comments
      $line = trim($line);
      if(empty($line)) continue;
 
      $row    = explode(":",$line,5);
      $groups = array_values(array_filter(explode(",",$row[3])));
 
      $this->users[$row[0]]['name'] = urldecode($row[1]);
      $this->users[$row[0]]['mail'] = $row[2];
      $this->users[$row[0]]['grps'] = $groups;
    }
  }
 
  /**
   * Save user data
   *
   * saves the user file into a datastructure
   *
   * @author  Lukas Slansky <lukas.slansky@upce.cz>
   */
  function _saveUserData($username, $userinfo) {
    global $conf;
 
    if ($this->users === null) $this->_loadUserData();
    $pattern = '/^' . $username . ':/';
 
    // Delete old line from users file
    if (!io_deleteFromFile($conf['ssp_usersfile'], $pattern, true)) {
      msg('Error saving user data (1)', -1);
      return false;
    }
    $groups = join(',',$userinfo['grps']);
    $userline = join(':',array($username, $userinfo['name'], $userinfo['mail'], $groups))."\n";
    // Save new line into users file
    if (!io_saveFile($conf['ssp_usersfile'], $userline, true)) {
      msg('Error saving user data (2)', -1);
      return false;
    }
    $this->users[$username] = $userinfo;
    return true;
  }
 
  /**
   * Do external authentication (SSO)
   * Params are not used
   */
  function trustExternal($user,$pass,$sticky=false){
    global $USERINFO;
    global $conf;
 
    $sticky ? $sticky = true : $sticky = false; //sanity check
 
    // loading of simplesamlphp library
    require_once($conf['ssp_path'] . '/lib/_autoload.php');
 
    // create auth object and use api to require authentication and get attributes
    $this->as = new SimpleSAML_Auth_Simple('default-sp');
 
    // the next line should be discommented to enable guest users (not authenticated) enter DokuWiki, see also documentation
    # if ($this->as->isAuthenticated()) {

    $this->as->requireAuth();
    $attrs = $this->as->getAttributes();
 
    // check for valid attributes (not empty) and update USERINFO var from dokuwiki
    if (!isset($attrs[$conf['ssp_attr_name']][0])) {
      $this->exitMissingAttribute('Name');
    }
    $USERINFO['name'] = $attrs[$conf['ssp_attr_name']][0];
 
    if (!isset($attrs[$conf['ssp_attr_mail']][0])) {
      $this->exitMissingAttribute('Mail');
    }
    $USERINFO['mail'] = $attrs[$conf['ssp_attr_mail']][0];
 
    // groups may be empty (by default any user belongs to the user group) don't perform empty check
    $USERINFO['grps'] = $attrs[$conf['ssp_attr_grps']];
 
    if (!isset($attrs[$conf['ssp_attr_user']][0])) {
      $this->exitMissingAttribute('User');
    }
 
    // save user info
    if (!$this->_saveUserData($attrs[$conf['ssp_attr_user']][0], $USERINFO)) {
      return false;
    }
 
    // assign user id to the user global information
    $_SERVER['REMOTE_USER'] = $attrs[$conf['ssp_attr_user']][0];
 
    // assign user id and the data from USERINFO to the DokuWiki session cookie
    $_SESSION[DOKU_COOKIE]['auth']['user'] = $attrs[$conf['ssp_attr_user']][0];
    $_SESSION[DOKU_COOKIE]['auth']['info'] = $USERINFO;
 
    # } // end if_isAuthenticated()

    return true;
  }
 
  /**
   * exit printing info and logout link
   *
   */
  function exitMissingAttribute( $attribute ){
    // get logout link
    $url = $this->as->getLogoutURL();
    $logoutlink = '<a href="' . htmlspecialchars($url) . '">logout</a>';
    die( $attribute . ' attribute missing from IdP. Please ' . $logoutlink . ' to return to login form');
  }
 
  /**
   * Log off the current user from DokuWiki and IdP
   *
   */
  function logOff(){
    // use the simpleSAMLphp authentication object created in trustExternal to logout
    if ($this->as->isAuthenticated())
      $this->as->logout('/');
  }
 
}
 
//Setup VIM: ex: et ts=2 enc=utf-8 :

Configuration

1. For configuring the SimpleSAMLphp application look at the online documentation of the project

2. For installing the new backend just save the above code under …/dokuwiki/inc/auth/ssp.class.php

3. Add the following lines in your DokuWiki configuration file (local.php):

// use the SimpleSAMLphp backend
$conf['authtype']   = 'ssp';
$conf['useacl'] = 1;
 
// path for the simplesamlphp installation root
$conf['ssp_path'] = '/var/simplesamlphp';
 
// username to save user details
$conf['ssp_usersfile'] = $conf['savedir'] . '/users.ssp.php';
 
// configure attribute names to match the ones used by our authentication backend (IdP)
$conf['ssp_attr_name'] = 'cn';
$conf['ssp_attr_user'] = 'uid';
$conf['ssp_attr_mail'] = 'email';
$conf['ssp_attr_grps'] = 'eduPersonAffiliation';

4. Integrate SimpleSAMLphp and DokuWiki:

a) By changing SimpleSAMLphp in the default session store type in the config/config.php file: Change this line:

'store.type' => 'phpsession'

To this:

'store.type' => 'memcache'

b) OR by setting in the same file the value 'DokuWiki' to the php cookie name:

'session.phpsession.cookiename'  => 'DokuWiki',

and comment the lines that set the cookie params in the init.php file of DokuWiki,like this:

 if (version_compare(PHP_VERSION, '5.2.0', '>')) { 
        //session_set_cookie_params(0,DOKU_REL,'',($conf['securecookie'] && is_ssl()),true); 
    }else{ 
        //session_set_cookie_params(0,DOKU_REL,'',($conf['securecookie'] && is_ssl())); 

5. (optional) Uncomment the lines starting by '#' in the authentication backend to allow guest users visit the site without requiring user and password credentials

In this case you should also modify the inc/template.php file to correct the behaviour of the login button, redirecting it to the IdP login form

//   $out .= html_btn('login',$ID,'',array('do' => 'login', 'sectok' => getSecurityToken()));
$as = new SimpleSAML_Auth_Simple('default-sp');
$link_as = $as->getLoginURL();
$out .= '<form class="button btn_login" method="post" action="' . $link_as . '"><div class="no"><input type="submit" value="Login" class="button" title="Login" /></div></form>';