JAAS 备忘单¶
简介 - 什么是 JAAS 认证¶
验证用户或另一个系统身份的过程就是认证。
JAAS 作为一个认证框架,负责管理经过认证的用户从登录到注销的身份和凭证。
JAAS 认证生命周期
- 创建
LoginContext
。 - 从配置文件中读取一个或多个
LoginModule
以进行初始化。 - 为每个
LoginModule
调用LoginContext.initialize()
以进行初始化。 - 为每个
LoginModule
调用LoginContext.login()
。 - 如果登录成功则调用
LoginContext.commit()
,否则调用LoginContext.abort()
配置文件¶
JAAS 配置文件为每个可用于登录应用程序的 LoginModule
包含一个 LoginModule
节。
JAAS 配置文件中的一个节
Branches
{
USNavy.AppLoginModule required
debug=true
succeeded=true;
}
注意分号的位置,它们终止了 LoginModule
条目和节。
“required” 一词表示 LoginContext
的 login()
方法在用户登录时必须成功。LoginModule
特定的值 debug
和 succeeded
会传递给 LoginModule
。
它们由 LoginModule
定义,其用法在 LoginModule
内部进行管理。请注意,选项使用键值对(例如 debug="true"
)进行配置,键和值之间应以 =
符号分隔。
Main.java (客户端)¶
- 执行语法
Java –Djava.security.auth.login.config==packageName/packageName.config
packageName.Main Stanza1
Where:
packageName is the directory containing the config file.
packageName.config specifies the config file in the Java package, packageName.
packageName.Main specifies Main.java in the Java package, packageName.
Stanza1 is the name of the stanza Main() should read from the config file.
- 执行时,第一个命令行参数是配置文件的节。该节指定了要使用的
LoginModule
。第二个参数是CallbackHandler
。 - 使用传递给
Main.java
的参数创建一个新的LoginContext
。loginContext = new LoginContext (args[0], new AppCallbackHandler());
- 调用 LoginContext.Login 模块
loginContext.login();
- succeeded 选项中的值由
loginContext.login()
返回。 - 如果登录成功,则创建了一个主体 (Subject)。
LoginModule.java¶
LoginModule
必须具有以下认证方法
initialize()
login()
commit()
abort()
logout()
initialize()¶
在 Main()
中,当 LoginContext
从配置文件中读取正确的节后,LoginContext
会实例化该节中指定的 LoginModule
。
initialize()
方法签名Public void initialize (Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options)
- 以上参数应按如下方式保存
this.subject = subject;
this.callbackHandler = callbackHandler;
this.sharedState = sharedState;
this.options = options;
initialize()
方法的作用- 在
login()
成功后,构建一个Subject
类的对象。 - 设置
CallbackHandler
,它与用户交互以收集登录信息。 - 如果一个
LoginContext
指定了两个或更多LoginModule
(这是合法的),它们可以通过sharedState
映射共享信息。 - 将调试 (debug) 和成功 (succeeded) 等状态信息保存在 options 映射中。
- 在
login()¶
捕获用户提供的登录信息。以下代码片段声明了一个包含两个回调对象的数组,当它们传递给 callbackHandler.java
程序中的 callbackHandler.handle
方法时,将加载用户交互式提供的用户名和密码。
NameCallback nameCB = new NameCallback("Username");
PasswordCallback passwordCB = new PasswordCallback ("Password", false);
Callback[] callbacks = new Callback[] { nameCB, passwordCB };
callbackHandler.handle (callbacks);
- 认证用户
- 从回调对象中检索用户提供的信息
String ID = nameCallback.getName ();
char[] tempPW = passwordCallback.getPassword ();
- 将
name
和tempPW
与存储在 LDAP 等存储库中的值进行比较。 - 设置变量 succeeded 的值并返回到
Main()
。
commit()¶
在 login()
期间用户凭证成功验证后,JAAS 认证框架会根据需要将凭证与主体关联起来。
凭证有两种类型:公共和私有
- 公共凭证包括公钥。
- 私有凭证包括密码和公钥。
主体(即主体除了登录名之外的其他身份),例如员工编号或用户组中的成员 ID,会被添加到主体中。
下面是一个 commit()
方法的示例,首先,对于经过认证的用户所属的每个组,组名都会作为主体添加到主体中。然后,主体的用户名会添加到其公共凭证中。
设置并向主体添加任何主体(Principal)和公共凭证的代码片段
public boolean commit() {
If (userAuthenticated) {
Set groups = UserService.findGroups (username);
for (Iterator itr = groups.iterator (); itr.hasNext (); {
String groupName = (String) itr.next ();
UserGroupPrincipal group = new UserGroupPrincipal (GroupName);
subject.getPrincipals ().add (group);
}
UsernameCredential cred = new UsernameCredential (username);
subject.getPublicCredentials().add (cred);
}
}
abort()¶
当认证不成功时,会调用 abort()
方法。在 abort()
方法退出 LoginModule
之前,应注意重置状态,包括用户名和密码输入字段。
logout()¶
当调用 LoginContext.logout
时,释放用户的主体(principals)和凭证
public boolean logout() {
if (!subject.isReadOnly()) {
Set principals = subject.getPrincipals(UserGroupPrincipal.class);
subject.getPrincipals().removeAll(principals);
Set creds = subject.getPublicCredentials(UsernameCredential.class);
subject.getPublicCredentials().removeAll(creds);
return true;
} else {
return false;
}
}
CallbackHandler.java¶
callbackHandler
位于与任何单个 LoginModule
分离的源 (.java
) 文件中,以便它可以服务于具有不同回调对象的多种 LoginModule
- 创建
CallbackHandler
类的实例,并且只有一个方法handle()
。 - 一个服务于需要用户名和密码才能登录的 LoginModule 的
CallbackHandler
public void handle(Callback[] callbacks) {
for (int i = 0; i < callbacks.length; i++) {
Callback callback = callbacks[i];
if (callback instanceof NameCallback) {
NameCallback nameCallBack = (NameCallback) callback;
nameCallBack.setName(username);
} else if (callback instanceof PasswordCallback) {
PasswordCallback passwordCallBack = (PasswordCallback) callback;
passwordCallBack.setPassword(password.toCharArray());
}
}
}
相关文章¶
- JAAS 实战,Michael Coté,发布于2009年9月27日,URL 截至2012年5月14日。
- Pistoia Marco, Nagaratnam Nataraj, Koved Larry, Nadalin Anthony 摘自书籍 “企业 Java 安全” - Addison-Wesley, 2004。
披露¶
所附 JAAS 备忘单中的所有代码均逐字复制自此免费来源。