前言
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。
正文
- pm是用php实现的,所以要先下载cas的php客户端,可在此处下载;
- php客户端解压后放在$pm/gulliver/thirdparty/下,才能在php代码中引入cas库;
- 修改$pm/workflow/engine/methods/login/authentication.php,在代码最上面加入:
这样可以使pm原本的登录认证操作转移到cas里进行,在登录成功后统一将password设置为True;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/workflow/engine/xmlform/login/login.xml,在函数bsClick的最后一行加上:
这样可以试pm原本的登录页面自动提交,也就能自动跳转到cas的登录页面了。document.login.submit();
- 修改$pm/rbac/engine/classes/model/RbacUsers.php,在verifyLogin()函数中将:替换为:即与步骤3中相对应;
- 修改$pm/workflow/engine/methods/login/login.php,在代码最前面加入:
这是为了处理用户在退出pm时也能从cas中退出登录。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(); }
- 为了实现cas退出登录功能,除了6,还要在$pm/workflow/engine/skinEngine/skinEngine.php的第391、394、663、666行,分别将“/login/login” 改为 “/login/login?logout=1”,与6中的修改配合实现。
- 就是需要在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时候总报错:密码错误。 所以需要调整一下流程。
- 在$pm/rbca/engine/classes/model/RbacUsers.php中加入函数 noSSOVerifyLogin(即上面第5步中修改前的login函数):
这样就是增加了一个函数来完成使用传统用户名/密码方式来认证的渠道(因为跟cas用的都是同一个数据源,所以这类查询操作不会破坏 SSO 特性)/** * 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; }
- 修改$pm/gulliver/system/class.rbac.php,在其中加入一个函数 NoSSOVerifyLogin:
即在函数执行的最后阶段,只把login函数最后的userObj->VerifyLogin改为userObj->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; } }
- 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冲突的问题了。此类问题可能随着功能的深入还会有,之后再记录。