各种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请给我的引用个链接,算是对得起我手敲了这么多字。有更好解决方法的欢迎分享。