设为首页 收藏本站
查看: 576|回复: 0

[经验分享] 基于CAS 实现与容器(Tomcat 或者 JBoss)的SSO

[复制链接]

尚未签到

发表于 2017-2-5 10:41:28 | 显示全部楼层 |阅读模式
需求描述1:大家知道J2EE应用程序都可以用类型以下形式进行保护:
   <login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/failure.jsp</form-error-page>
</form-login-config>
<realm-name>Security Realm</realm-name>
</login-config>
<security-constraint>
<display-name>Tomcat security constraint</display-name>
<web-resource-collection>
<web-resource-name>Protected Resources</web-resource-name>
<url-pattern>/security/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>manager</role-name>
</auth-constraint>
</security-constraint>
<security-role>
<role-name>manager</role-name>
</security-role>
而使用CAS实现SSO之后,我们又不想容器保护去掉,该怎么办才能真正把这个CAS验证过的用户和角色传给Tomcat容器,而不至于重新登录,或者出现403错误呢?
需求描述2: 在有EJB资源的时候,我们通常都会用JAAS来实现保护EJB资源,以限制EJB资源的访问。在调用EJB的时候,需要输入用户名和密码并且此用户具有相应的角色才能调用EJB。而在实现SSO之后,如果真正实现与EJB容器进行SSO呢?

下面基于Tomcat容器实现需求1.

1.Tomcat窗口提供了一个叫Valve的接口,还提供一个基本实现ValveBase,我们解决方案就是基于实现一个自己的Valve, 在Valve里把经过CAS验证的用户传给Tomcat。以下就是自定义的Valve:
package edu.extcas.valve;
import java.io.*;
import java.security.Principal;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.catalina.Container;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.realm.GenericPrincipal;
import org.apache.catalina.valves.ValveBase;
//import com.ttg.customagent.jboss.SimplePrincipal;
public class ExtCASValve extends ValveBase {
public final static String CAS_FILTER_USER = "edu.yale.its.tp.cas.client.filter.user";
public void setContainer(Container container) {
super.setContainer(container);
}
public void invoke(Request request, Response response) throws IOException,
ServletException {
HttpSession session = ((HttpServletRequest) request).getSession();
if (session != null) {
String username = (String) session.getAttribute(CAS_FILTER_USER);
if (null != username) {
List roleList = getRolesFromUserStore(username);
Principal principal = new GenericPrincipal(request.getContext()
.getRealm(), username, "", roleList);
request.setUserPrincipal(principal);
}
//SecurityAssociation类是在登录EJB的时候使用的。
//SecurityAssociation.setPrincipal(new SimplePrincipal(username.trim()));
//SecurityAssociation.setCredential("password".trim().toCharArray());
getNext().invoke(request, response);
return;
} else {
getNext().invoke(request, response);
return;
}
}
//此方法是为在用户存储里取到相应的角色。自已根据实际情况实现
private List getRolesFromUserStore(String username) {
List roleList = new ArrayList();
roleList.add("admin");
roleList.add("manager");
return roleList;
}
}
2.实现好自己的Valve,在server.xml里配置一下。然后就可以测试了。

下面讲实现需求2实现的思路:
1.如果是EJB容器是JBoss,而Web容器是Tomcat, 也可以在Valve里用SecurityAssociation类(或者其他的方法)把CAS验证过的用户传到EJB容器里。这里同时需要传递密码。
2.要实现一个LoginModule, 类似以下代码:
package edu.extcas.loginmodule;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.security.Principal;
import java.security.cert.X509Certificate;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import org.apache.catalina.realm.GenericPrincipal;
public class ExtCasLoginModule  implements LoginModule {
private CallbackHandler callbackHandler;
private Principal unauthenticatedIdentity;
private String userName = null;
private String password = null;
protected Subject subject;
protected boolean loginOk;
protected Principal identity;
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map sharedState, Map options) {
this.subject = subject;
this.callbackHandler = callbackHandler;
try {
String name = (String) options.get("unauthenticatedIdentity");
if (name != null) {
unauthenticatedIdentity = createIdentity(name, "", null);
}
}
catch (Exception e) {
}
}
public boolean login() throws LoginException {
loginOk = false;
if (userName == null && password == null) {
identity = unauthenticatedIdentity;
}
if ((identity == null) && (password != null)) {
if ("password".equals(password)) {
identity = createIdentity(userName, "", null);
loginOk = true;
return true;
}
}
}
public boolean abort() throws LoginException {
subject.getPrincipals().clear();
return true;
}
public boolean logout() throws LoginException {
Principal identity = getIdentity();
Set principals = subject.getPrincipals();
if (principals.contains(identity) == true)
principals.remove(identity);
return true;
}
private Principal getIdentity() {
return identity;
}
private Principal createIdentity(String username) throws Exception {
return new CustomPrincipal(username);
}   
public boolean commit() throws LoginException {
if (loginOk == false)
return false;
StringBuffer sb = new StringBuffer();
List roles = getRolesFromUserStore(userName);
Set principals = subject.getPrincipals();
if (!principals.contains(identity))
principals.add(identity);
Group jbossroles = new SimpleGroup("Roles");      
for (Iterator i = roles.iterator(); i.hasNext();) {        
String roleStr = (String) i.next();
jbossroles.addMember(new SimplePrincipal(roleStr));
}
principals.add(jbossroles);
return true;
}
private List getRolesFromUserStore(String username) {
List roleList = new ArrayList();
roleList.add("admin");
roleList.add("manager");
return roleList;
}   
}
这里面最重要的就是commit方法了。由于这是个有点麻烦,只是在产品里的代码改了一下。不保证这个LoginModule能运行正确,不过思路和基本方法都是正确的。
3.然后在JBoss里的配置使用这个LoginModule, 并且让它来保护EJB资源。这样就可以了。至于怎么设置这个,非常繁琐,这里就不讲了。
重要注意:这里为了演示,把密码写作“password”, 在实现应用中,用这么简单的密码不合适,这谁都知道。但是是否使用真正的密码,也是要考虑的。如果使用真正的密码,在loginmodule还要验证一次。如果使用一定逻辑来实现密码验证(如使用CAS的Ticket),同时也支持真正密码登录,这样适应性更强,性能也更好。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-337712-1-1.html 上篇帖子: 【转】Tomcat 的JVM 内存溢出问题的解决 下篇帖子: Tomcat服务器下解决乱码的解决方案
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表