Tomcat认证授权与简单的SSO

开发 前端
在前几天,我使用apache+tomcat搭建了一个集群,有一个简单的网站应用。http://my.oschina.net/xpbug/blog/197680。

回顾

在前几天,我使用apache+tomcat搭建了一个集群,有一个简单的网站应用。http://my.oschina.net/xpbug/blog/197680

今天在此基础上,我要为其开发一个登录页面,并开启网站的认证和授权。

基本概念

在动手之前,我需要先了解网站认证和授权的几个基本组成部分的概念。是什么构成了网站应用的认证和授权?

  1. Realm - 翻译过来叫做“域”。Realm是web容器所持有的用户集合。无论tomcat, glassfish,jboss还是websphere,均是符合j2ee规范或最佳实现。Realm是需要网站系统管理员进行配置的。常见的Realm 有三种:数据库,LDAP和文件系统。数据库realm是指用户信息都存在数据库中,Ldap则存放在ldap中,文件系统的realm则是用户信息按照 一定的格式,存放于文件中。Realm是认证的关键,web容器会将用户输入的用户名和密码跟realm中的用户信息进行比对。当比对成功的时候,认证也 就成功了。
  2. Role - 角色。 这是授权的部分。当Realm被配好以后,系统管理员可以为realm中的用户分配角色。建立用户role-mapping. 每次用户通过web容器的认证以后,web容器会将其role信息也查询出来,放入用户信息中。
  3. security-constraint。 这是web应用web.xml中的配置。 一个web应用将在web.xml中声明其受保护的资源,并声明某种角色可以访问受保护的资源。
  4. 认证方式。 一般认证方式分为Basic Authentication(BA)和Form-based Authentication(FBA)。
  5. 密码加密。一旦黑客黑了服务器,明文密码就会全部暴露了。所以,需要对密码进行加密存放。一般使用MD5 SHA算法对密码进行加密。

以上1,2,5是由网站管理员来配置开发。3,4是由网站开发人员来配置和开发的。

本实验简介

在前篇实验结果的基础上,为网站开启ldap认证,并制作一个login页面。实验所用的ldap软件为开源的openLDAP for windows版本。

OpenLDAP安装配置

  1. 下载并安装软件 http://sourceforge.net/projects/openldapwindows/ OpenLDAP会被安装成windows service.
  2. 修改slapd.conf,声明自己的后缀和管理员. 重启service.
  1. database    bdb 
  2. suffix      "dc=mycompany,dc=com
  3. rootdn      "cn=admin,dc=mycompany,dc=com
  4. rootpw    admin
  1. 创建my.ldif文件,借用tomcat文档中的案例,文件内容如下。其中定义了两个用户,和两个角色。
  1. # Define top-level entry 
  2. dn: dc=mycompany,dc=com 
  3. objectClass: dcObject 
  4. objectClass: organization 
  5. o: mycompany 
  6. dc:mycompany 
  7.  
  8. # Define an entry to contain people 
  9. # searches for users are based on this entry 
  10. dn: ou=people,dc=mycompany,dc=com 
  11. objectClass: organizationalUnit 
  12. ou: people 
  13.  
  14. # Define a user entry 
  15. dn: uid=jjones,ou=people,dc=mycompany,dc=com 
  16. objectClass: inetOrgPerson 
  17. uid: jjones 
  18. sn: jones 
  19. cn: janet jones 
  20. mail: j.jones@mycompany.com 
  21. userPassword: janet 
  22.  
  23. # Define a user entry for Fred Bloggs 
  24. dn: uid=fbloggs,ou=people,dc=mycompany,dc=com 
  25. objectClass: inetOrgPerson 
  26. uid: fbloggs 
  27. sn: bloggs 
  28. cn: fred bloggs 
  29. mail: f.bloggs@mycompany.com 
  30. userPassword: fred 
  31.  
  32. # Define an entry to contain LDAP groups 
  33. # searches for roles are based on this entry 
  34. dn: ou=groups,dc=mycompany,dc=com 
  35. objectClass: organizationalUnit 
  36. ou: groups 
  37.  
  38. # Define an entry for the "red" role 
  39. dn: cn=red,ou=groups,dc=mycompany,dc=com 
  40. objectClass: groupOfUniqueNames 
  41. cn: red 
  42. uniqueMember: uid=jjones,ou=people,dc=mycompany,dc=com 
  43. uniqueMember: uid=fbloggs,ou=people,dc=mycompany,dc=com 
  44.  
  45. # Define an entry for the "black" role 
  46. dn: cn=black,ou=groups,dc=mycompany,dc=com 
  47. objectClass: groupOfUniqueNames 
  48. cn: black 
  49. uniqueMember: uid=fbloggs,ou=people,dc=mycompany,dc=com 
  1. 运行命令 slapadd.exe -l my.ldif

  2. 验证条目添加成功,运行查询命令 ldapsearch.exe -x -b "dc=mycompany,dc=com" "objectClass=*"

OpenLDAP安装配置成功,我有了下面两个用户:

  • uid\group
  • red
  • black
  • jjones
  • Y
  • Y
  • fbloggs
  •  
  • Y

 

#p#

为Tomcat配置Realm

tomcat的realm可以配置在server.xml中的<engine>, <host>和<context>下面。分别表示realm的作用范围。我抱着从简的态度,将realm配置 在<engine>下面,这样,整个tomcat上的application都可以使用此realm. 在server.xml的<engine>下面替换老的realm,添加如下代码:

  1. <!-- <Realm className="org.apache.catalina.realm.UserDatabaseRealm" 
  2.                resourceName="UserDatabase"/> 
  3.         --> 
  4. <Realm   className="org.apache.catalina.realm.JNDIRealm" 
  5.     connectionName="cn=admin,dc=mycompany,dc=com" 
  6.     connectionPassword="admin" 
  7.      connectionURL="ldap://localhost:389" 
  8.       userPassword="userPassword" 
  9.        userPattern="uid={0},ou=people,dc=mycompany,dc=com" 
  10.        <!--userRoleName="memberOf"--> 
  11.           roleBase="ou=groups,dc=mycompany,dc=com" 
  12.           roleName="cn" 
  13.         roleSearch="(uniqueMember={0})" 
  14. /> 

重启tomcat集群。

为Web应用配置Basic Authentication

我要为https://www.test0.com/sessiontest/successful.jsp配置BA,只有role=red才可以访问此页面。

修改web应用的web.xml,添加如下代码:

  1. <security-constraint> 
  2.   <web-resource-collection> 
  3.     <web-resource-name>result</web-resource-name> 
  4.     <url-pattern>/successful.jsp</url-pattern> 
  5.   </web-resource-collection> 
  6.   <auth-constraint> 
  7.     <role-name>red</role-name> 
  8.   </auth-constraint> 
  9. </security-constraint> 
  10. <login-config>  
  11.     <auth-method>BASIC</auth-method>  
  12.     <realm-name>tomcat</realm-name>  
  13. </login-config> 
  14. <security-role> 
  15.   <role-name>red</role-name> 
  16. </security-role> 
  17. <security-role> 
  18.   <role-name>black</role-name> 
  19. </security-role> 

然后重新打包部署sessiontest.war. 对网站进行测试,select.jsp是可以任意访问的,当点击submit以后,必须对浏览器弹出的BA认证框输入用户名和密码才能post成功。

为Web应用配置Form-based Authentication

这次,我们要设计一个登录页面。用户可以随意浏览购物车,选择想要的东西,但当用户点击submit的时候,我们需要用户必须登录,才能提交订单。所以,我们需要对页面https://www.test0.com/sessiontest/successful.jsp进行FBA保护。

首先设计一个登录页面login.html

  1. <form action="j_security_check" method="post"> 
  2.     Username<input type="text" name="j_username" /><br /> 
  3.     Password<input type="password" name="j_password" /><br /> 
  4.     <input type="submit" value="login" /> 
  5. </form> 

注意form中的action已经user和password的input的name属 性,“j_security_check","j_username"和"j_password"这些事固定的,严格遵循J2EE规范。将 login.html放入select.jsp同级目录下。

关于logout,我就不做设计了,很简单,只需要执行session.invalidate(),然后跳转到登出页面即可。

接下来,我们修改web.xml,配置FBA. 这里只需要替换之前BA中的的<login-config>:

  1. <login-config>  
  2.     <auth-method>FORM</auth-method>  
  3.     <form-login-config> 
  4.         <form-login-page>/login.html</form-login-page> 
  5.         <form-error-page>/login.html</form-error-page> 
  6.     </form-login-config> 
  7. </login-config> 

将web应用重新打包部署。重启tomcat。

注意:使用mod_proxy_balancer +mod_ajp+ AJP的方式连接tomcat,存在着一个未知错误。当用户没有登录,访问被保护资源的时候,按照常理,浏览器会显示我们配置好的login form。但AJP和tomcat之间的通信会在此断掉。这可能是windows版本的问题,也可能是mod_ajp和tomcat存在缺陷。总之,花了 一天的时间,也没研究出成果。google上面类似的问题挺多,可惜都没答案。我会开启tomcat的log再仔细研究到底发生了什么。

根据以往老版本,大部分使用mod_jk+ajp的方式行的通,有时间的同学可以尝试mod_jk.

mod_ajp+ajp的方式只是卡在了FBA上,其它的任何资源访问,都没问题,为了让FBA工作起来,不得已,我将balancer修改成了http模式。

  1. <Proxy balancer://mycluster> 
  2.       BalancerMember http://127.0.0.1:8080 loadfactor=1 route=node1 
  3.       BalancerMember http://127.0.0.1:8081 loadfactor=1 route=node2 
  4.       ProxySet stickysession=JSESSIONID 
  5.       ProxySet lbmethod=byrequests 
  6.    </Proxy> 

此外,还有一个陷阱。tomcat在做完j_security_check以后,会重定向到http,无论之前是https. 当然我们可以通过配置server.xml和web.xml使其重定向到Https,但一般不推荐这样做,因为这很可能导致循环重定向。

一般的做法是在web中添加一个filter,专门负责http和https的切换。又或者在apache中配置重定向。在http-vhosts.conf中添加:

  1. <VirtualHost *:80> 
  2.    ServerAdmin joey 
  3.    ServerName www.test0.com 
  4.    ErrorLog "logs/errlog" 
  5.    CustomLog "logs/accesslog" common 
  6.    RewriteEngine on 
  7.    RewriteRule ^/?sessiontest/(.*) https://%{SERVER_NAME}/sessiontest/$1 [R,L] 
  8. </VirtualHost> 

到此,网站可以在FBA的模式下正常运行了。

#p#

FBA的缺陷

在J2EE的规范中,FBA存在着很大的缺陷。列举如下:

  1. login的过程无法被干预。我们无法通过添加filter的形式进行干预。login完全交给web容器处理,页面也是有web容器负责展示。

  2. 没有login地址,用户无法bookmark一个Login页面。直接访问login.html是无法提交form的。login只能在访问受保护资源的时候才会被触发。

很不幸的是,tomcat完全遵循了J2EE关于FBA的规范,这使得FBA很不实用。 WebSphere Application Server则对规范进行了变通,使得以上2个缺陷都被除去了。 Jboss, Glassfish和weblogic则不是很清楚,需要了解的同学可以去查看其文档。

Tomcat build-in SSO

Tomcat本身集成SSO(Single Sign On)解决方案。如果一个tomcat上,部署了多个应用,这时候可以使用tomcat自身的SSO解决方案。如果系统跨JVM甚至跨平台,则需要一套复 杂的SSO解决方案。复杂的SSO解决方案需要自己开发,或者使用第三方框架,如CAS, OPENSSO等。

这次的实验,仅仅关注tomcat自带的SSO方案。首先需要说明,tomcat自带的SSO的必要前提是:

  1. 必须是Tomcat自带的认证方式:BA, FBA, Degist,client-cert
  2. 必须是在同一个tomcat vhost下。
  3. 同一个JVM中。
  4. 所有的应用必须使用同一个domain。
  5. 需要cookie支持。cookie中会被插入JSESSIONIDSSO
  6. 所有应用必须使用形同的realm。

接下来,我将重新复制一份新的tomcat, 取名tomcat3. 在tomcat3\webApps下面,tomcat自带一个web应用,叫做examples,其下/examples/jsp/security /protected/index.jsp是受FBA保护的。

修改server.xml,添加realm

  1. <Realm className="org.apache.catalina.realm.UserDatabaseRealm" 
  2.                resourceName="UserDatabase"/>--> 
  3.                <Realm   className="org.apache.catalina.realm.JNDIRealm" 
  4.     connectionName="cn=admin,dc=mycompany,dc=com" 
  5.     connectionPassword="admin" 
  6.      connectionURL="ldap://localhost:389" 
  7.       userPassword="userPassword" 
  8.        userPattern="uid={0},ou=people,dc=mycompany,dc=com" 
  9.           roleBase="ou=groups,dc=mycompany,dc=com" 
  10.           roleName="cn" 
  11.         roleSearch="(uniqueMember={0})" 
  12. /> 

继续修改server.xml, 打来host下面的SSO配置:

  1. <Valve className="org.apache.catalina.authenticator.SingleSignOn" /> 

然后修改examples下面的web.xml, 将受保护的资源的允许访问角色修改成:

  1. <auth-constraint> 
  2.     <role-name>red</role-name> 
  3. </auth-constraint> 

这样,tomcat3下面就有一个使用OpenLDAP认证的应用examples了。接下来,我将examples复制一份,取名叫 examples2,放在相同目录下。现在tomcat3下面存在两个应用examples和examples2,它们使用同一个realm认证。

启动tomcat3, 访问http://localhost:8080/examples/jsp/security/protected/index.jsp和http://localhost:8080/examples2/jsp/security/protected/index.jsp, 发现只需要登录其中一个,另一个不再需要登录。

接下来

由于FBA的缺陷,我们需要自己制作login机制。实际上很多互联网网站都是自己的login机制。我将借助第三方认证工具,比如SecurityFilter或Spring来重新制作login。链接稍后贴上。

原文链接:http://my.oschina.net/xpbug/blog/198765

 

责任编辑:陈四芳 来源: 开源中国博客
相关推荐

2023-06-16 08:13:57

2024-09-11 08:37:39

2014-04-22 10:15:38

vCenter SSO身份认证

2013-03-28 09:35:31

企业级系统

2022-05-12 07:37:51

单点登录微服务开源

2014-02-25 10:37:16

自动化运维SSO单点登录

2024-06-05 06:43:20

2019-03-27 15:51:51

API 认证授权

2021-10-29 13:26:54

单点登录SSO

2021-09-17 09:00:00

安全身份认证OAuth 2.0

2021-09-28 10:48:07

开源双因素认证单点登录

2019-05-20 14:57:35

Tomcat容器安全

2009-06-15 14:16:17

JBoss与Tomca

2021-07-12 07:08:53

OAuth 2.0授权协议

2021-07-07 07:33:49

开源Keycloak平台

2022-09-22 10:01:47

微服务授权认证

2009-10-22 16:38:09

Oracle用户

2009-07-06 17:49:02

Apache的配置JBoss的配置

2009-07-09 14:02:58

Tomcat JDK

2010-08-19 11:47:28

点赞
收藏

51CTO技术栈公众号