前言
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沖突的問題了。此類問題可能随着功能的深入還會有,之後再記錄。