<?php
/**
 *  SSO.php
 *
 *  PHP versions 4 and 5
 *
 *  @package    Auth
 *  @author     Kaoru Sekiguchi <sekiguchi.kaoru@secioss.co.jp>
 *  @copyright  2010 SECIOSS CORPORATION
 *  @version    CVS: $Id$
 */
require_once('Secioss/AutoLogin/Container.php');
require_once('Config.php');

/**
 *  AutoLogin_Container_SSO
 *
 *  @package    Auth
 *  @author     Kaoru Sekiguchi <sekiguchi.kaoru@secioss.co.jp>
 *  @copyright  2010 SECIOSS CORPORATION
 *  @version    CVS: $Id$
 */
class AutoLogin_Container_SSO extends AutoLogin_Container
{
    // {{{ AutoLogin_Container_SSO
    /**
     *  AutoLogin_Container_SSOクラスのコンストラクタ
     *
     *  @access public
     *  @param  mixed   $options        SSOの設定
     *  @return mixed   0:正常終了 PEAR_Error:エラー
     */
    function AutoLogin_Container_SSO($options)
    {
        parent::AutoLogin_Container($options);

        return 0;
    }
    // }}}

    // {{{ fetchData()
    /**
     * ユーザ情報を取得する
     *
     * @param  string username
     * @return mixed
     */
    function fetchData($username)
    {
        if (!$username || strlen($username) > 255) {
            return PEAR::raiseError("Invalid user id", AUTO_LOGIN_INVALID_VALUE);
        }

        if ($username != $_SERVER['REMOTE_USER']) {
            return PEAR::raiseError("User doesn't exist", AUTO_LOGIN_NO_USER);
        }

        $this->id = $username;

        $this->prop = array();
        if (array_key_exists('REMOTE_USER_DATA', $_SERVER)) {
            foreach (preg_split('/#/', $_SERVER['REMOTE_USER_DATA']) as $elt) {
                list($attr, $values) = preg_split('/=/', $elt);
                $v = preg_split('/,/', $values);
                if (count($v) == 1) {
                    $this->prop[$attr] = $v[0];
                } else {
                    $this->prop[$attr] = $v;
                }
            }
        }

        if (isset($this->prop[$this->options['loginattr']])) {
            $this->loginid = $this->prop[$this->options['loginattr']];
        } else {
            $this->loginid = $this->id;
        }
    }
    // }}}

    // {{{ getPassword()
    /**
     *  暗号化されているパスワードを復号化して取得する
     *
     *  @access public
     *  @return string   パスワード
     */
    function getPassword()
    {
        if (isset($this->prop[$this->options['encryptpwdattr']])) {
            return $this->decrypt($this->prop[$this->options['encryptpwdattr']]);
        } else {
            return '';
        }
    }
    // }}}

    // {{{ setPassword()
    /**
     *  パスワードを暗号化してLDAPに格納する
     *
     *  @access public
     *  @param  string   パスワード
     *  @return mixed    true:正常終了 PEAR_Error:エラー
     */
    function setPassword($password = null, $app = null, $init = false)
    {
        if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
            $path = file_exists("/Perl64") ? "/Perl64/bin" : "/Perl/bin";
            $loginattr = $this->options['loginattr'] ? $this->options['loginattr'] : 'uid';
            $output = system("$path/perl /opt/secioss/sbin/pwsync ".$this->loginid." $password $loginattr 2>&1", $rc);
            if ($rc) {
                return PEAR::raiseError("pwsync command failed: ".join(' ', $output));
            }

            return true;
        }

        $file = '/opt/secioss/var/www/conf/'.$this->options['soappath'].'lismapi.conf';
        if (!file_exists($file)) {
            return PEAR::raiseError("Can't find config file", AUTO_LOGIN_ERROR);
        }

        $conf = new Config;
        $root =& $conf->parseConfig($file, 'apache');
        if (PEAR::isError($root)) {
            return PEAR::raiseError("Can't read config file", AUTO_LOGIN_ERROR);
        }

        $params = $root->toArray();
        if (!isset($params['root']['admin']) || !isset($params['root']['adminpw'])) {
            return PEAR::raiseError("Invalid configuration", AUTO_LOGIN_ERROR);
        }
        $url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ? 'https' : 'http').'://localhost:'.$_SERVER['SERVER_PORT'];
        try {
            $soap = new SoapClient(null, array('uri' => "$url/SoapLism", 'location' => "$url/api/".$this->options['soappath']."lism.cgi", 'trace' => 1));
            $result = $soap->__soapCall('bind', array('cn='.$params['root']['admin'].',o=lism', $params['root']['adminpw']));
        } catch (SoapFault $exception) {
            $error = $exception->getMessage()." ".preg_replace("/[\r\n]/", " ", $soap->__getLastResponse());
            return PEAR::raiseError($error);
        }
        if (!$result) {
            return PEAR::raiseError("Can't connect LISM", 80);
        } else if ($result[0]) {
            return PEAR::raiseError(ldap_err2str($result[0]), $result[0]);
        }

        $sessid = $result[2];
        $loginattr = $this->options['loginattr'] ? $this->options['loginattr'] : 'uid';
        $result = $soap->__soapCall('search', array($sessid, 'o=lism', 2, 0, 0, 0, "($loginattr=".$this->loginid.")", 0, array($loginattr)));
        if (!$result) {
            return PEAR::raiseError("Can't connect LISM", 80);
        } else if ($result[0]) {
            return PEAR::raiseError(ldap_err2str($result[0]), $result[0]);
        } else if (!preg_match('/^dn: (.+)/', $result[2][0], $matches)) {
            return PEAR::raiseError("No user", 32);
        }
        $dn = $matches[1];

        $result = $soap->__soapCall('bind', array($dn, $password));
        if ($result[0] === 0) {
            return true;
        }

        $result = $soap->__soapCall('modify', array('sessid' => $sessid, 'dn' => $dn, 'modifyRequest' => array('REPLACE' => array('userpassword' => array($password)))));
        if (!$result) {
            return PEAR::raiseError("Can't connect LISM", 80);
        } else if ($result[0]) {
            return PEAR::raiseError(ldap_err2str($result[0]), $result[0]);
        }

        return true;
    }
    // }}}

    // {{{ _setDefaults()
    /**
     * optionsにデフォルト値を設定する
     *
     * @access private
     */
    function _setDefaults()
    {
        parent::_setDefaults();

        $this->options['loginattr']     = '';
        $this->options['encryptpwdattr']  = 'seciossencryptedpassword';
        $this->options['soappath'] = '';
    }
    // }}}
}

?>
