IBM WebSphere Application Server社区版V2.1.1.2(以下称为社区版)是基于Apache Geronimo 2.1.4的免费使用的Java平台,企业版5.0(Java EE 5)认证的应用程序服务器。 Community Edition使用Java身份验证和授权服务(JAAS)登录模块在Web应用程序中进行用户身份验证 ,并使用Java容器授权协议(JACC)进行授权 。
Kerberos是由麻省理工学院开发的身份验证协议。 Kerberos协议允许在非安全计算机网络上通信的计算机节点以安全方式相互认证。 Kerberos协议的最新版本是版本5。
Community Edition不提供Kerberos协议实现。 在本文中,您将利用IBM Java Platform提供的Kerberos协议实现对Community Edition中的用户进行身份验证和授权。 出于本文的目的,我们使用Microsoft®Active Directory服务器(以下称为Active Directory)作为用户存储库。 本文需要WebSphere Application Server社区版V2.1.1.2或更高版本。
Kerberos:工作原理
Kerberos使用对称密钥加密,并且需要一个称为密钥分发中心(KDC)的受信任第三方,该第三方由身份验证服务器(AS)和票证授予服务器(TGS)组成。 KDC维护一个秘密密钥数据库。 网络上的每个实体,无论是用户还是服务,都与KDC共享一个秘密密钥,并且秘密密钥仅对于KDC和该实体本身是已知的。 因此,该秘密密钥的知识提供了实体的标识。 Kerberos使用票证(称为Kerberos票证),这些票证带有时间戳并且是短期的。 因此,对于实体而言,保持同步时间很重要。
实体使用共享密码(通常是密码)向身份验证服务器进行身份验证,并接收票证授予票证(TGT)。 然后,它与票证授予服务器联系,使用TGT证明其身份,并请求服务。 TGS验证实体是否被授权使用服务并发送服务票证(ST)。 然后,该实体联系服务服务器(SS),使用ST证明它已被授权使用该服务并使用该服务。 实体可以重用TGT来获得与SS一起使用的其他ST,而不必再次与AS进行身份验证。 设计Kerberos协议,以便进行身份验证而不会在网络上传输共享密钥(例如,密码)。 使用Kerberos身份验证时,用户通常使用键盘等输入设备输入凭据,而服务使用Keytab文件存储和使用其凭据向KDC进行身份验证。
Kerberos和社区版
Community Edition 并不提供Kerberos协议的实现。 IBM Java Platform通过com.ibm.security.auth.module.Krb5LoginModule类提供Kerberos协议的实现。 为了利用Java平台提供的Kerberos实现,我们创建了一个LoginModule实现,该实现包装了Krb5LoginModule并将所有LoginModule API调用委托给Krb5LoginModule。 清单1显示了KerberosLoginModule的代码。
清单1. KerberosLoginModule.java
package org.apache.geronimo.security.realm.providers;
import java.security.Principal;
import java.util.HashMap;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class KerberosLoginModule implements LoginModule {
private static Log log = LogFactory.getLog(KerberosLoginModule.class);
private Subject subject;
private LoginModule krb5LoginModule;
private Subject krb5Subject;
private Principal addOnPrincipal;
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map sharedState, Map options) {
this.subject = subject;
String krb5LoginModuleClass = (String) options.get("krb5LoginModuleClass");
try {
krb5LoginModule = (LoginModule)Class.forName(krb5LoginModuleClass)
.newInstance();
} catch (Exception e) {
log.error("Initialization failed", e);
throw new IllegalArgumentException("Unable to configure
kerberos login module: " + e.getMessage(),e);
}
Map options1 = new HashMap();
for(Object key : options.keySet()) {
String key1 = (String) key;
if(key1.startsWith("krb_")) {
options1.put(key1.substring(4), options.get(key1));
}
}
krb5Subject = new Subject();
krb5LoginModule.initialize(krb5Subject, callbackHandler, sharedState,
options1);
String addOnPrincipalClass = (String) options.get("addOnPrincipalClass");
String addOnPrincipalName = (String) options.get("addOnPrincipalName");
if(addOnPrincipalClass != null && !addOnPrincipalClass.equals("")) {
try {
addOnPrincipal = (Principal) Class.forName(addOnPrincipalClass).getConstructor
(String.class).newInstance(addOnPrincipalName);
} catch (Exception e) {
log.error("Initialization failed", e);
throw new IllegalArgumentException("Unable to configure kerberos login
module: " + e.getMessage(), e);
}
}
}
public boolean login() throws LoginException {
return krb5LoginModule.login();
}
public boolean commit() throws LoginException {
boolean result = krb5LoginModule.commit();
if(result) {
if(addOnPrincipal != null) subject.getPrincipals().add(addOnPrincipal);
subject.getPrincipals().addAll(krb5Subject.getPrincipals());
subject.getPublicCredentials().addAll(krb5Subject.getPublicCredentials());
subject.getPrivateCredentials().addAll(krb5Subject.getPrivateCredentials());
}
return result;
}
public boolean abort() throws LoginException {
return krb5LoginModule.abort();
}
public boolean logout() throws LoginException {
if(!subject.isReadOnly()) {
// Remove principals and credentials added by this LoginModule
if(addOnPrincipal != null) subject.getPrincipals().remove(addOnPrincipal);
subject.getPrincipals().removeAll(krb5Subject.getPrincipals());
subject.getPublicCredentials().removeAll(krb5Subject.getPublicCredentials());
subject.getPrivateCredentials().removeAll(krb5Subject.getPrivateCredentials());
}
return krb5LoginModule.logout();
}
}
KerberosLoginModule具有以下LoginModule选项:
- krb5LoginModuleClass :指定Java平台提供的Kerberos协议实现类的完全限定名称。 此类必须实现
javax.security.auth.spi.LoginModule
接口。 由于我们将使用IBM Java Platform提供的Krb5LoginModule,因此该值为com.ibm.security.auth.module.Krb5LoginModule
。 - addOnPrincipalClass :如果登录成功,则指定要添加到主题的主体类的全限定名称。 除了使用krb5LoginModuleClass登录而产生的任何主体外,还将将此主体添加到主题中。 如果您不添加更多主体,请不要使用此选项。
- addOnPrincipalName :指定要添加到主题的主体的名称。 仅当指定了addOnPrincipalClass时,才使用此选项。
- krb_ * :传递给krb5LoginModuleClass的
initialize()
方法的任何选项都必须使用前缀“ krb_”来指定。 前缀“ krb_”将在传递给initialize()
方法之前从选项名称中删除。 例如,krb_debug=true
将作为debug=true
传递给initialize()
方法。
KerberosLoginModule.initialize()
方法创建使用krb5LoginModuleClass选项配置的类的实例,并仅使用名称以“ krb_”开头但从选项名称中删除该前缀的那些选项来初始化该实例。 它还会按照addOnPrincipalClass和addOnPrincipalName选项的配置来创建附加主体。 身份验证成功后, KerberosLoginModule.commit()
方法会将由于登录krb5LoginModuleClass和附加主体而产生的所有主体,公共凭证和专用凭证添加到主题。 KerberosLoginModule类用于创建安全领域,这些领域在使用Kerberos协议的Community Edition中执行身份验证。
在Microsoft Active Directory中设置用户
安装和配置Microsoft Active Directory服务器不在本文的讨论范围之内。 根据我们的配置,我们已经在端口88上启动了密钥分发中心(KDC)。请按照以下步骤将新用户添加到Active Directory服务器。
- 启动Active Directory用户和计算机,然后选择“ 用户” ,如图1所示。
图1. Active Directory用户和计算机
- 右键单击“ 用户”,然后选择“ 新建”>“用户 ”,如图2所示。
图2.创建新用户
- 在对话框中,填写名字,姓氏和用户登录名,然后单击下一步 ,如图3所示。
图3.创建新用户–用户详细信息
- 输入用户的密码,然后单击Next ,如图4所示。
图4.创建新用户-密码
- 单击Finish完成添加新用户,如图5所示。
图5.创建新用户-添加了新用户
您可以观察到新创建的用户在“用户”下列出。
设置客户端计算机
此步骤需要将Kerberos配置文件复制到预定义的位置。 在Windows客户端中,此文件称为“ krb5.ini”,位于“ C:/ winnt /”中。 对于Linux客户端,此文件称为“ krb5.conf”,位于“ / etc”中。 清单2中显示了我们在设置中使用的Kerberos配置文件。
清单2. Kerberos配置文件-krb5.ini
[libdefaults]
default_realm = AUSTIN.IBM.COM
default_tkt_enctypes = rc4-hmac,des-cbc-md5,des-cbc-crc
default_tgs_enctypes = rc4-hmac,des-cbc-md5,des-cbc-crc
[realms]
AUSTIN.IBM.COM = {
kdc = ad1ldap.austin.ibm.com:88
}
[domain_realm]
austin.ibm.com = AUSTIN.IBM.COM
.austin.ibm.com = AUSTIN.IBM.COM
现在让我们看一下该配置文件中的每个部分和条目。
第一部分是[libdefaults]
,它详细说明了Kerberos V5库使用的默认值。 本节中的不同字段描述如下:
- default_realm :这是在客户端和主机之间的通信中使用的默认领域。 如果使用主体名称“ ashish”,那么缺省情况下会将AUSTIN.IBM.COM附加到主体上,而最终主体将为ashish@AUSTIN.IBM.COM。
- default_tgs_enctypes :此字段标识KDC返回的会话密钥加密。 使用Microsoft Active Directory作为KDC时,请确保在此字段中指定rc4-hmac。
- default_tkt_enctypes :此字段标识客户端将请求的会话密钥加密类型的列表。
第二部分是[realms]
,它详细说明了领域和KDC服务器映射。 在清单2中,AUSTIN.IBM.COM已映射到ad1ldap.austin.ibm.com:88。 在这里,ad1ldap.austin.ibm.com是主机名,88是运行KDC服务器的端口。
第三部分是[domain_realm]
,它详细说明了子域和域名到Kerberos领域名称的映射。 给定主机的完全限定域名,这将确定主机所在的领域。
将自定义Kerberos登录模块JAR添加到存储库
当前版本的Community Edition没有KerberosLoginModule的实现。 本文提供了一个自定义登录模块JAR,其中包含KerberosLoginModule类(如清单1所示),它将帮助您在Community Edition中创建Kerberos安全领域。 该jar需要添加到Community Edition资源库中。 请按照以下步骤将登录模块jar添加到Community Edition存储库:
- 启动Community Edition,然后在浏览器中打开http:// localhost:8080 / console / 。
- 输入
system
作为用户名,manager
作为密码。 单击Login ,这将在管理控制台中弹出Welcome页面,如图6所示。图6.管理控制台–欢迎页面
- 点击下的控制台导航库启动在图7所示的库portlet中。
图7.仓库Portlet
- 浏览到下载定制登录模块jar的位置。 命名字段,如图7所示,然后单击Install 。 这会将登录模块jar安装到Community Edition存储库。
创建Kerberos领域
本节将描述使用Community Edition管理控制台创建Kerberos领域的步骤。 请按照以下步骤创建Kerberos领域:
- 单击控制台导航中“ 安全性”下的“ 安全领域”链接,如图8所示。
图8.启动安全领域portlet
- 在“安全领域” Portlet中,单击“ 添加新的安全领域 ”,如图9所示。
图9.启动新的安全领域页面
- 在下一页上,将领域命名为
kerberos-realm
然后选择领域类型为Other ,然后单击Next ,如图10所示。图10.创建新的安全领域
- 填写表单,如图11所示。从下拉框中选择登录模块jar。 这是先前已添加到资源库中的同一jar。 将登录模块类命名为
org.apache.geronimo.security.realm.providers.KerberosLoginModule
。 添加配置选项,如清单3所示。清单3.创建安全领域时的配置选项
addOnPrincipalName=admin addOnPrincipalClass=org.apache.geronimo.security.realm.providers. GeronimoGroupPrincipal krb_debug=true krb5LoginModuleClass= com.ibm.security.auth.module.Krb5LoginModule
图11.创建新的安全领域-配置
- 完成后,您可以浏览到页面底部。 您可以单击Show Plan ,如图12所示,以查看Kerberos领域计划。
图12.显示创建的安全领域计划
- 在下一个屏幕上,您可以找到创建的计划,该计划显示在一个文本框中,如图13所示。您还可以复制该计划以供参考。 单击“ 部署”将安全领域部署到Community Edition。
图13.部署安全领域计划
成功部署后,可以在Security Realms页面中看到“ kerberos-realm”,如图14所示。图14. Kerberos领域的成功部署
部署和测试示例应用程序
为了测试Kerberos领域,我们在本文中提供了一个示例应用程序 。 请按照以下步骤部署和测试此示例应用程序:
- 在Applications下的控制台导航中单击Deploy New ,如图15所示。
图15.启动部署新的Portlet
- 浏览到下载示例应用程序的位置。 相对于Archive选择SimpleWebApp-Subject.war ,相对于Plan选择SimpleWebApp- Subject-plan.xml ,如图16所示。
图16.安装应用程序
- 单击安装以部署示例应用程序。
- 完成后,启动URL http:// localhost:8080 / kerberos-realm-demo / admin / admin.jsp 。 这将显示一个提供登录凭据的屏幕(图17)。
图17. Simple Web App –登录屏幕
- 输入先前使用Microsoft Active Directory创建的用户名和密码,然后单击Login 。
- 成功认证后,您可以看到一个欢迎页面,其中列出了主体ashishjain@AUSTIN.IBM.COM已添加到管理组中。 它还列出了生成的Kerberos票证,如图18所示。
图18.成功认证时的欢迎页面和其他工件
注意,除了KerberosPrincipal外,主题还使用addOnPrincipal选项在领域中配置了GeronimoGroupPrincipal。
- 现在尝试使用错误的密码,您将看到登录失败消息,如图19所示。
图19.登录失败的结果
结论
本文介绍了如何通过创建KerberosLoginModule包装器来认证Community Edition中的用户,从而利用IBM Java Platform提供的Kerberos协议实现。 它还通过示例Web应用程序演示了使用Kerberos验证Microsoft Active Directory服务器中列出的用户的身份。
翻译自: https://www.ibm.com/developerworks/websphere/library/techarticles/0910_jain1/0910_jain1.html