各種baidu、google、biying之後實作了pentaho的cas單點登入,but,都有一個緻命的問題:隻有在pentaho中存在的使用者才能正常登入。
問題放了一段時間,可最終還是要解決的。花了幾天時間,總算解決了:pentaho中使用者不存在也可登入,隻要cas伺服器登入成功即可。
如果有興趣知道怎麼實作的可以往下慢慢看,隻想快點搞定的可以直接去我的百度雲盤下載下傳附件,裡面有安裝手冊,直接包含了如何配置cas單點登入。
雲盤位址:http://pan.baidu.com/s/1dFMGwoT
最近項目中用到pentaho這個BI平台,用的是ce 6.1.0.1-196社群版。相信很多做pentaho單點登入的都已經配置過很多次cas了吧,如何配置就不再贅述了,挑重點講下。
截取cas配置檔案裡面才一段代碼,相信很多人對這段配置不陌生吧!
<property name="userDetailsService">
<pen:bean class="org.springframework.security.userdetails.UserDetailsService" />
</property>
注意 userDetailsService,這個是單點登入擷取使用者的,頂層接口隻有一個方法:“loadUserByUsername”,更具使用者名擷取使用者的,在pentaho裡面有很多不同的實作,其中有一個是我們要用到的 org.pentaho.platform.security.userroledao.service.UserRoleDaoUserDetailsService,在這裡我直接用如下配置替代了(有些配置 userDetailsService方式是和我一樣的)
<property name="userDetailsService" ref="userDetailsService"/>
經過各種配置檔案的找,發現userDetailsService的具體實作類配置在了“applicationContext-spring-security-jackrabbit.xml”這配置檔案裡面,具體路徑配置過的人應該知道去那裡找了。裡面有這麼一段xml配置
<bean id="userDetailsService" class="org.pentaho.platform.security.userroledao.service.UserRoleDaoUserDetailsService">
<property name="userRoleDao">
<ref bean="userRoleDaoTxn" />
</property>
......
這裡才是關鍵,為了實作單點登入,我更改了userDetailsService的具體實作類如下:
<bean id="userDetailsService" class="com.cn.custom.UserRoleDaoUserDetailsService">
<property name="userRoleDao">
<ref bean="userRoleDaoTxn" />
</property>
......
“com.cn.custom.UserRoleDaoUserDetailsService”則是我在“org.pentaho.platform.security.userroledao.service.UserRoleDaoUserDetailsService”的基礎上更改了點代碼,判斷,原始代碼是加載使用者,如果不存在就抛出異常,我卻在這建立使用者,不再抛異常了。
附上com.cn.custom.UserRoleDaoUserDetailsService源碼:
/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved.
*/
package com.cn.custom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.pentaho.platform.api.engine.IPentahoSession;
import org.pentaho.platform.api.engine.security.userroledao.IPentahoRole;
import org.pentaho.platform.api.engine.security.userroledao.IPentahoUser;
import org.pentaho.platform.api.engine.security.userroledao.IUserRoleDao;
import org.pentaho.platform.api.engine.security.userroledao.UncategorizedUserRoleDaoException;
import org.pentaho.platform.api.mt.ITenant;
import org.pentaho.platform.core.mt.Tenant;
import org.pentaho.platform.engine.core.system.PentahoSessionHolder;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.platform.repository2.unified.jcr.JcrTenantUtils;
import org.pentaho.platform.security.userroledao.messages.Messages;
import org.pentaho.reporting.libraries.base.util.StringUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.security.userdetails.User;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.security.userdetails.UserDetailsService;
import org.springframework.security.userdetails.UsernameNotFoundException;
import org.springframework.util.Assert;
/**
* A <code>UserDetailsService</code> that delegates to an {@link IUserRoleDao} to load users by username.
*
* @author mlowery
*/
public class UserRoleDaoUserDetailsService implements UserDetailsService {
// ~ Static fields/initializers
// ======================================================================================
// ~ Instance fields
// =================================================================================================
private String rolePrefix = "ROLE_"; //$NON-NLS-1$
private IUserRoleDao userRoleDao;
/**
* A default role which will be assigned to all authenticated users if set
*/
private GrantedAuthority defaultRole;
private String defaultRoleString;
// ~ Constructors
// ====================================================================================================
// ~ Methods
// =========================================================================================================
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
final boolean ACCOUNT_NON_EXPIRED = true;
final boolean CREDS_NON_EXPIRED = true;
final boolean ACCOUNT_NON_LOCKED = true;
IPentahoUser user;
try {
if (userRoleDao == null) {
userRoleDao = PentahoSystem.get(IUserRoleDao.class, "userRoleDaoProxy", PentahoSessionHolder.getSession());
}
user = userRoleDao.getUser(null, username);
} catch (UncategorizedUserRoleDaoException e) {
throw new UserRoleDaoUserDetailsServiceException(
Messages.getInstance().getString("UserRoleDaoUserDetailsService.ERROR_0003_DATA_ACCESS_EXCEPTION"), e); //$NON-NLS-1$
}
if (user == null) {
ITenant tenant = new Tenant("/pentaho/tenant0", true);
String password = "123456";
String description = "cas user";
String[] roles = new String[0];
user = userRoleDao.createUser(tenant, username, password, description, roles);
// throw new UsernameNotFoundException(
// Messages.getInstance().getString("UserRoleDaoUserDetailsService.ERROR_0001_USER_NOT_FOUND"));
// //$NON-NLS-1$
}
// convert IPentahoUser to a UserDetails instance
List<IPentahoRole> userRoles = userRoleDao.getUserRoles(null, username);
int authsSize = userRoles != null ? userRoles.size() : 0;
GrantedAuthority[] auths = new GrantedAuthority[authsSize];
int i = 0;
for (IPentahoRole role : userRoles) {
auths[i++] = new GrantedAuthorityImpl(role.getName());
}
List<GrantedAuthority> dbAuths = new ArrayList<GrantedAuthority>(Arrays.asList(auths));
addCustomAuthorities(user.getUsername(), dbAuths);
// Store the Tenant ID in the session
IPentahoSession session = PentahoSessionHolder.getSession();
String tenantId = (String) session.getAttribute(IPentahoSession.TENANT_ID_KEY);
if (tenantId == null) {
ITenant tenant = JcrTenantUtils.getTenant(username, true);
session.setAttribute(IPentahoSession.TENANT_ID_KEY, tenant.getId());
}
if (!StringUtils.isEmpty(defaultRoleString)) {
defaultRole = new GrantedAuthorityImpl(defaultRoleString);
}
if (defaultRole != null && !dbAuths.contains(defaultRole)) {
dbAuths.add(defaultRole);
}
if (dbAuths.size() == 0) {
throw new UsernameNotFoundException(
Messages.getInstance().getString("UserRoleDaoUserDetailsService.ERROR_0002_NO_AUTHORITIES")); //$NON-NLS-1$
}
GrantedAuthority[] arrayAuths = dbAuths.toArray(new GrantedAuthority[dbAuths.size()]);
return new User(user.getUsername(), user.getPassword(), user.isEnabled(), ACCOUNT_NON_EXPIRED, CREDS_NON_EXPIRED,
ACCOUNT_NON_LOCKED, arrayAuths);
}
/**
* Allows subclasses to add their own granted authorities to the list to be returned in the <code>User</code>.
*
* @param username
* the username, for use by finder methods
* @param authorities
* the current granted authorities, as populated from the <code>authoritiesByUsername</code> mapping
*/
protected void addCustomAuthorities(String username, List authorities) {
}
/**
* Allows a default role prefix to be specified. If this is set to a non-empty value, then it is automatically
* prepended to any roles read in from the db. This may for example be used to add the <code>ROLE_</code> prefix
* expected to exist in role names (by default) by some other Spring Security framework classes, in the case that
* the prefix is not already present in the db.
*
* @param rolePrefix
* the new prefix
*/
public void setRolePrefix(String rolePrefix) {
if (rolePrefix == null) {
this.rolePrefix = ""; //$NON-NLS-1$
} else {
this.rolePrefix = rolePrefix;
}
}
public String getRolePrefix() {
return rolePrefix;
}
/**
* A data access exception specific to a <code>IUserRoleDao</code>-based <code>UserDetailsService</code>.
*/
protected class UserRoleDaoUserDetailsServiceException extends DataAccessException {
private static final long serialVersionUID = -3598806635515478946L;
public UserRoleDaoUserDetailsServiceException(String msg) {
super(msg);
}
public UserRoleDaoUserDetailsServiceException(String msg, Throwable cause) {
super(msg, cause);
}
}
public void setUserRoleDao(IUserRoleDao userRoleDao) {
this.userRoleDao = userRoleDao;
}
/**
* The default role which will be assigned to all users.
*
* @param defaultRole
* the role name, including any desired prefix.
*/
public void setDefaultRole(String defaultRole) {
Assert.notNull(defaultRole);
this.defaultRoleString = defaultRole;
this.defaultRole = new GrantedAuthorityImpl(defaultRole);
}
}
然後把對應的class檔案釋出到pentaho的tomcat的pentaho工程的classes目錄下。
在pentaho-spring-beans.xml裡面添加映入cas的配置是必須的:
......
<import resource="applicationContext-pentaho-security-jackrabbit.xml" />
<import resource="applicationContext-spring-security-jackrabbit.xml" />
<import resource="applicationContext-pentaho-security-jdbc.xml" />
<import resource="applicationContext-spring-security-jdbc.xml" />
<!-- cas configuration begin -->
<import resource="applicationContext-spring-security-cas.xml" />
<!-- cas configuration end -->
......
然後替換修改過檔案,添加cas-client-core-3.1.10.jar和spring-security-cas-client-2.0.5.RELEASE.jar(jar包版本更具自己實際情況添加)到tomcat pentaho工程的lib目錄下。
到這裡pentaho的單點登入完成,再也不用一個一個的添加帳号密碼了。
無償分享,copy請給我的引用個連結,算是對得起我手敲了這麼多字。有更好解決方法的歡迎分享。