JAAS之Authentication
注:主要参考SUN的JAAS tutorial
Introduction(介绍)
使用JAAS有2个目的:
* 认证
for authentication of users, to reliably and securely determine who is currently executing Java code, regardless of whether the code is running as an application, an applet, a bean, or a servlet; and
* 授权
for authorization of users to ensure they have the access control rights (permissions) required to do the actions performed.
JAAS是一个可插拔的认证模块,不管使用何种认证技术,认证程序使用保持独立,也就是说新增或修改认证技术应用程序不用修改。应用认证是通过实例化一个LoginContext来实现的,并通过一个配置文件来决定使用哪种认证技术或者那些LoginModule去执行验证操作,典型的LoginModules是通过验证用户名和密码,也有可能是通过声音或者指纹来进行验证。
一旦用户或者服务通过认证,接着JAAS授权组件基于JAVA2访问控制模型(Java 2 access control model)保护敏感的资源。不同的是JDK1.3或更早的版本的访问控制是基于code的位置和code签名。JDK1.4是基于执行代码CodeSource和运行这个代码的用户或者服务(用Subject表示),验证成功以后这个Subject被修改,设置相关的Principals 和credentials
JAAS Authentication(JAAS认证)
JAAS认证的操作通俗一点讲,无非有三点:
1. 如何获取验证数据(这里的sample用用户名和密码)
2. 进行验证
3. 保存验证后的信息。
我们看一下client端调用的主要代码如下:
LoginContext lc = new LoginContext("Sample", new MyCallbackHandler(username,password));
lc.login()
lc.getSubject();;
这三 行代码里就包含了上面讲的三点,其中:
[a]“sample”是指属性文件中的信息,指出使用哪个登录的LoginModule和其它一些参数。比如:
Sample {
com.sample.SampleLoginModule required debug=true;
};
[b] MyCallbackHandler就是如何获取验证数据,其中传递了Username和password参数
public class MyCallbackHandler implements CallbackHandler {
private String username;
private String password;
public MyCallbackHandler(String username, String password) {
super();
this.username = username;
this. password = password;
}
public void handle(Callback callbacks[]) throws IOException,
UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
if (callbacks[i] instanceof NameCallback) {
((NameCallback) callbacks[i]).setName(username);
} else if (callbacks[i] instanceof PasswordCallback) {
((PasswordCallback) callbacks[i]).setPassword(password);
} else {
throw new UnsupportedCallbackException(callbacks[i]);
}
}
}
}
[c] 验证登录调用的是com.sample.SampleLoginModule的login方法
public boolean login() throws LoginException {
//.
Callback[] callbacks = new Callback[2];
callbacks[0] = new NameCallback("user name: ");
callbacks[1] = new PasswordCallback("password: ", false);
callbackHandler.handle(callbacks);
String username = ((NameCallback) callbacks[0]).getName();
String password = ((PasswordCallback) callbacks[1]).getPassword();
//利用回调获取用户名和密码后,怎么进行验证都可以.
//
[d] 最后保存信息调用的是commit方法,修改Subject
public boolean commit() throws LoginException {
if (succeeded == false) {
return false;
} else {
// add a Principal (authenticated identity)
// to the Subject
// assume the user we authenticated is the SamplePrincipal
userPrincipal = new SamplePrincipal(username);
if (!subject.getPrincipals().contains(userPrincipal))
subject.getPrincipals().add(userPrincipal);
//…………………………………………….
运行代码时,需要加入参数-Djava.security.auth.login.config==sample_jaas.config sample.SampleAzn制定confg的位置
如果需要完整的代码请参考sun网站的 jaas指南,详情见文章后的参考资源。
如果这些代码运行在Security Manager之下则涉及到JAAS授权,下篇文章再关注。
参考资源:
http://java.sun.com/j2se/1.5.0/docs/guide/security/jaas/tutorials/GeneralAcnOnly.html
附录:
LoginModule描述由身份验证技术提供程序实现的接口。LoginModule 插入到应用程序中以提供特定类型的身份验证。
当应用程序写入 LoginContext API 时,身份验证技术提供程序将实现 LoginModule接口。Configuration指定将与特定登录应用程序一起使用的 LoginModule(s)。因此可以将不同的 LoginModule 插入到应用程序中,而无需修改应用程序本身。
LoginContext负责读取 Configuration和实例化适当的 LoginModule。每个 LoginModule都是使用 Subject、CallbackHandler、共享的 LoginModule状态和特定于 LoginModule 的选项来实例化的。 Subject表示当前正进行身份验证的 Subject,如果身份验证成功,则使用相关的 Credential 更新它。LoginModule 使用CallbackHandler与用户进行通信。例如,CallbackHandler可以用于提示要求用户名和密码。注意, CallbackHandler可以为 null。确实需要一个 CallbackHandler来对 Subject进行身份验证的 LoginModule 可以抛出 LoginException。LoginModule 可以有选择地使用共享状态来共享它们之间的信息或数据。
特定于 LoginModule 的选项表示由管理员或用户在 Configuration中为此 LoginModule配置的选项。这些选项由 LoginModule自身定义,并在其中控制其行为。例如,LoginModule可以定义支持调试/测试功能的选项。这些选项是使用键-值语法定义的,例如 debug=true。LoginModule以 Map形式存储这些选项,因此可以使用键来检索这些值。注意,对 LoginModule选择定义的选项个数是没有限制的。
调用应用程序将身份验证过程视为单个操作。但是,LoginModule中的身份验证过程分两个不同的阶段进行。在第一个阶段,LoginModule 的 login方法由 LoginContext 的 login方法调用。LoginModule的 login方法执行实际的身份验证(例如,提示并验证密码),并将身份验证状态作为私有状态信息保存。一旦完成上述操作,LoginModule 的 login将返回 true(如果成功)或 false(如果应该忽略它),或抛出 LoginException来指示失败。在失败的情况下,LoginModule不必再尝试进行身份验证或者引入延迟。由应用程序完成这类任务。如果应用程序试图重新尝试身份验证,将会再次调用 LoginModule 的 login方法。
在第二个阶段,如果 LoginContext 的整个身份验证成功(相关的 REQUIRED、REQUISITE、SUFFICIENT 和 OPTIONAL LoginModule 成功),则调用 LoginModule的 commit方法。LoginModule的 commit方法检查其私有保存状态,以查看自己的身份验证是否成功。如果整个 LoginContext身份验证成功,并且 LoginModule 自己的身份验证也获得成功,则 commit方法会将相关的 Principal(已进行身份验证的身份)和 Credential(身份验证数据,如加密密钥)与位于 LoginModule中的 Subject联系在一起。
如果 LoginContext 的整个身份验证失败(相关的 REQUIRED、REQUISITE、SUFFICIENT 和 OPTIONAL LoginModule 没有成功),则调用每个 LoginModule的 abort方法。在这种情况下,LoginModule移除/销毁原先保存的任何状态。
注销 Subject只涉及一个阶段。LoginContext调用 LoginModule 的 logout方法。然后 LoginModule的 logout方法执行注销过程,例如从 Subject中移除 Principal 或 Credential,或者记录会话信息。
LoginModule实现必须有一个无参数的构造方法。这允许加载 LoginModule的类对其进行实例化
。