天天看点

processmaker在与cas做SSO集成时需要做的修改

前言

processmaker是目前开源的最好的工作流系统,cas是知名的单点登录server。网络上关于这两个系统的集成文章很少,有价值的仅有一篇,http://forum.processmaker.com/viewtopic.php?f=9&t=930,但该文章中介绍的processmaker版本较低(修改的位置不对)和部分功能未实现。本文部分借鉴该文章,以pm2.5.0为例,主要介绍processmaker在与cas集成时要做的工作,所以cas的相关配置请移步http://www.blogjava.net/tufanshu/archive/2011/01/21/343290.html。

正文

  1. pm是用php实现的,所以要先下载cas的php客户端,可在此处下载;
  2. php客户端解压后放在$pm/gulliver/thirdparty/下,才能在php代码中引入cas库;
  3. 修改$pm/workflow/engine/methods/login/authentication.php,在代码最上面加入:
    require_once ("CAS-1.3.2/CAS.php");
    // Uncomment to enable./ debugging
    phpCAS::setDebug();
    // version, host, port, context, session
    phpCAS::client(CAS_VERSION_2_0, "localhost", 8443, 'cas', false); //我的cas server访问地址是:https://localhost:443/cas
    phpCAS::setNoCasServerValidation();
    phpCAS::forceAuthentication();
    
    // logout if desired
    if (isset($_REQUEST['logout'])) {
      phpCAS::logout();
    }
    
    if ( phpCAS::isAuthenticated() == true )
      $casAuth = CASAuthIsTrue;
    
    $_POST['form']['USR_USERNAME'] = phpCAS::getUser();
    $_POST['form']['USR_PASSWORD'] = $casAuth;
               
    这样可以使pm原本的登录认证操作转移到cas里进行,在登录成功后统一将password设置为True;
  4. 修改$pm/workflow/engine/xmlform/login/login.xml,在函数bsClick的最后一行加上:
    document.login.submit();
               
    这样可以试pm原本的登录页面自动提交,也就能自动跳转到cas的登录页面了。
  5. 修改$pm/rbac/engine/classes/model/RbacUsers.php,在verifyLogin()函数中将:替换为:即与步骤3中相对应;
  6. 修改$pm/workflow/engine/methods/login/login.php,在代码最前面加入:
    require_once ("CAS-1.3.2/CAS.php");
    
    phpCAS::client(CAS_VERSION_2_0, 'localhost', 8443, 'cas', false);
    
    // logout if desired
    if (isset($_REQUEST['logout'])) {
      phpCAS::logout();
    }
               
    这是为了处理用户在退出pm时也能从cas中退出登录。
  7. 为了实现cas退出登录功能,除了6,还要在$pm/workflow/engine/skinEngine/skinEngine.php的第391、394、663、666行,分别将“/login/login” 改为 “/login/login?logout=1”,与6中的修改配合实现。
  8. 就是需要在CAS server的数据源配置中引用pm的库rb_workflow中的USERS表,配置的sql是“select USR_PASSWORD from USERS where USR_USERNAME=?”,passwordEncoder用MD5。

Extra

       如果只是日常使用,上面的8条修改已经足够了。但。。。

解决process的new web entry 与 CAS-SSO 用户认证冲突的问题       

在使用process的new web entry时,需要填入用户名和密码,这是在RbacUsers.verify_login()函数中验证的,但之前咱们已经在第5步修改了verify_login的代码,从之前的用户名/密码改为仅看密码是否等于CASAuthIsTrue来判断了,就 会导致在new web entry时候总报错:密码错误。 所以需要调整一下流程。

  1. 在$pm/rbca/engine/classes/model/RbacUsers.php中加入函数  noSSOVerifyLogin(即上面第5步中修改前的login函数):
    /**
       * Autentificacion derb un usuario a traves de la clase RBAC_user
       *
       * verifica que un usuario tiene derechos de iniciar una aplicacion
       *
       * @author Fernando Ontiveros Lira <[email protected]>
       * access public
       * Function verifyLogin
       *
       * @param  string $strUser    UserId  (login) de usuario
       * @param  string $strPass    Password
       * @return
       *  -1: no existe usuario
       *  -2: password errado
       *  -3: usuario inactivo
       *  -4: usuario vencido
       *  n : uid de usuario
       */
      function noSSOVerifyLogin($sUsername, $sPassword )
      {
        //invalid user
        if ( $sUsername == '' ) return -1;
    
        //invalid password
        if ( $sPassword == '' ) return -2;
    
        $con = Propel::getConnection(RbacUsersPeer::DATABASE_NAME);
        try {
          $c = new Criteria( 'rbac' );
          $c->add ( RbacUsersPeer::USR_USERNAME, $sUsername );
          $rs = RbacUsersPeer::doSelect( $c );
          if ( is_array($rs) && isset( $rs[0] ) && is_object($rs[0]) && get_class ( $rs[0] ) == 'RbacUsers' ) {
            $aFields = $rs[0]->toArray(BasePeer::TYPE_FIELDNAME);
            //verify password with md5, and md5 format
            //if ( $aFields['USR_PASSWORD'] == md5 ($sPassword ) ) {
            if ( $aFields['USR_PASSWORD'] == md5 ($sPassword ) || 'md5:'.$aFields['USR_PASSWORD'] === $sPassword) {
              if ($aFields['USR_DUE_DATE'] < date('Y-m-d') )
                return -4;
              if ($aFields['USR_STATUS'] != 1 )
                return -3;
              return $aFields['USR_UID'];
            }
            else
              return -2;
          }
          else {
            return -1;
          }
        }
        catch (Exception $oError) {
          throw($oError);
        }
        return -1;
      }
               
    这样就是增加了一个函数来完成使用传统用户名/密码方式来认证的渠道(因为跟cas用的都是同一个数据源,所以这类查询操作不会破坏 SSO 特性)
  2. 修改$pm/gulliver/system/class.rbac.php,在其中加入一个函数 NoSSOVerifyLogin:
    /**
      * authentication of an user through of class RBAC_user
      *
      * checking that an user has right to start an applicaton
      *
      * @author Fernando Ontiveros Lira <[email protected]>
      * @access public
    
      * @param  string $strUser    UserId  (login) an user
      * @param  string $strPass    Password
      * @return
      *  -1: no user
      *  -2: wrong password
      *  -3: inactive usuario
      *  -4: due date
      *  -5: invalid authentication source   ( **new )
      *  n : uid of user
      */
      function NoSSOVerifyLogin( $strUser, $strPass)
      {
        if ( strlen($strPass) == 0) return -2;
        //check if the user exists in the table RB_WORKFLOW.USERS
        $this->initRBAC();
        //if the user exists, the VerifyUser function will return the user properties
        if ( $this->userObj->verifyUser($strUser) == 0 ) {
          //here we are checking if the automatic user Register is enabled, ioc return -1
          $res = $this->checkAutomaticRegister( $strUser, $strPass);
          if ( $res == 1 )
            $this->userObj->verifyUser($strUser);
          else
            return $res;
        }
    
        //default values
        $sAuthType = 'mysql';
        if ( isset($this->userObj->fields['USR_AUTH_TYPE']) ) $sAuthType = strtolower ( $this->userObj->fields['USR_AUTH_TYPE'] );
    
        //hook for RBAC plugins
        if ( $sAuthType != 'mysql' && $sAuthType != '' ) {
          $sAuthSource = $this->userObj->fields['UID_AUTH_SOURCE'];
          $sAuthUserDn = $this->userObj->fields['USR_AUTH_USER_DN'];
          $res = $this->VerifyWithOtherAuthenticationSource( $sAuthType, $sAuthSource, $this->userObj->fields, $sAuthUserDn, $strPass);
    
          return $res;
        }
        else {
          $this->userObj->reuseUserFields = true;
          $res = $this->userObj->NoSSOVerifyLogin($strUser, $strPass);
          return $res;
        }
      }
               
    即在函数执行的最后阶段,只把login函数最后的userObj->VerifyLogin改为userObj->NoSSOVerifyLogin,来充当新函数了。
  3. new web entry使用的是pm的web service实现的login操作,首先修改$pm/workflow/engine/classes/class.wsBase.php中的login函数,将第三行的:
    $uid = $RBAC->VerifyLogin($userid , $password);
               
    改为:
    $uid = $RBAC->NoSSOVerifyLogin($userid , $password);
               

    这样就实现了在new web entry时的内部验证与SSO冲突的问题了。此类问题可能随着功能的深入还会有,之后再记录。

继续阅读