| JavaTM Authentication and Authorization Service (JAAS)在JavaTM 2 SDK Standard Edition (J2SDK)1.3版本中是一个可选的包,而现在JAAS已经整合到J2SDK1.4中. |
|
1.用来鉴定用户,能够可靠并安全的确定谁在执行java代码,而不管执行的是一个应用程序或小程序或bean或java servlet; |
|
JAAS实现一个java版本的standard Pluggable Authentication Module (PAM)的框架.传统上java提供一个原代码的通路控制(通路控制基于代码来源和谁签名).它所缺乏的是基于谁在运行代码的强制通路控制能力.JAAS提供了一个框架增加了安全性来支持这种功能. |
|
JAAS是一种可插入的风格.这可以使应用程序对鉴定技术保持独立性.新的或更新的鉴定技术能够插入应用程序下面而不需要修改程序本身.应用程序可以例示一 个LoginContext对象依此提及一个确定鉴定技术的Configuration或用来执行鉴定的LoginModule来允许鉴定.LoginModule可以提示和检验用户名和用户密码.其他的也可以读出和检验一个声音或一个指纹. |
|
当用户或服务器执行的代码被鉴定以后,JAAS组件与java通路控制模式一起保护敏感资源的通路.不像J2SDK13或以上版本通路控制决定由代码位置和代码签名者,J2SDK14通路控制决定有运行代码的代码源和用户或服务器.假如鉴定成功,Subject被LoginModule用相关的Principals和信任书更新. |
|
从下一个例子中可以看出JAAS中Authentication的作用. |
|
import javax.security.auth.login.*; |
|
import javax.security.auth.*; |
|
import javax.security.auth.callback.*; |
|
//for a simple Authentication . |
|
public static void main(String[] args) { |
|
/*为了鉴别用户,首先需要一个javax.security.auth.login.LoginContext. |
|
1.参数"Sample"是JAAS注册配置文件的入口名字.一个入口指定实现了 鉴别技术的类,这个类必须实现LoginModule(在javax.security.auth.spi中)接口; |
|
2.CallbackHandler的实例化.当一个LoginModule需要与用户通信,如请求用户名 |
|
或用户密码,它需要保持独立性因为用户通信有许多方式.LoginModule调用javax.security.auth.callback.CallbackHandler |
|
去执行与用户通信和获得请求信息包括用户名用户密码. |
|
lc = new LoginContext("Sample", new MyCallbackHandler()); |
|
} catch (LoginException le) { |
|
System.err.println("Cannot create LoginContext. " |
|
} catch (SecurityException se) { |
|
System.err.println("Cannot create LoginContext. " |
|
for (i = 0; i < 3; i++) { |
|
* 调用LoginContext中login方法.LoginContext例式一个空的javax.security.auth.Subject对象, |
|
* (描述被鉴定的用户或服务器).login方法调用LoginModule中的方法执行注册和鉴定. |
|
* SampleLoginModule利用MyCallbackHandler获得用户名和用户密码.SampleLoginModule将 |
|
// if we return with no exception, authentication succeeded |
|
} catch (LoginException le) { |
|
System.err.println("Authentication failed:"); |
|
System.err.println(" " + le.getMessage()); |
|
Thread.currentThread().sleep(3000); |
|
// did they fail three times? |
|
System.out.println("Sorry"); |
|
System.out.println("Authentication succeeded!"); |
|
class MyCallbackHandler implements CallbackHandler { |
|
public void handle(Callback[] callbacks) |
|
throws IOException, UnsupportedCallbackException { |
|
for (int i = 0; i < callbacks.length; i++) { |
|
if (callbacks[i] instanceof TextOutputCallback) { |
|
// display the message according to the specified type |
|
TextOutputCallback toc = (TextOutputCallback)callbacks[i]; |
|
switch (toc.getMessageType()) { |
|
case TextOutputCallback.INFORMATION: |
|
System.out.println(toc.getMessage()); |
|
case TextOutputCallback.ERROR: |
|
System.out.println("ERROR: " + toc.getMessage()); |
|
case TextOutputCallback.WARNING: |
|
System.out.println("WARNING: " + toc.getMessage()); |
|
throw new IOException("Unsupported message type: " + |
|
} else if (callbacks[i] instanceof NameCallback) { |
|
// prompt the user for a username |
|
NameCallback nc = (NameCallback)callbacks[i]; |
|
System.err.print(nc.getPrompt()); |
|
nc.setName((new BufferedReader |
|
(new InputStreamReader(System.in))).readLine()); |
|
} else if (callbacks[i] instanceof PasswordCallback) { |
|
// prompt the user for sensitive information |
|
PasswordCallback pc = (PasswordCallback)callbacks[i]; |
|
System.err.print(pc.getPrompt()); |
|
pc.setPassword(readPassword(System.in)); |
|
throw new UnsupportedCallbackException |
|
(callbacks[i], "Unrecognized Callback"); |
|
private char[] readPassword(InputStream in) throws IOException { |
|
buf = lineBuffer = new char[128]; |
|
if ((c2 != '\n') && (c2 != -1)) { |
|
if (!(in instanceof PushbackInputStream)) { |
|
in = new PushbackInputStream(in); |
|
((PushbackInputStream)in).unread(c2); |
|
buf = new char[offset + 128]; |
|
room = buf.length - offset - 1; |
|
System.arraycopy(lineBuffer, 0, buf, 0, offset); |
|
Arrays.fill(lineBuffer, ' '); |
|
buf[offset++] = (char) c; |
|
char[] ret = new char[offset]; |
|
System.arraycopy(buf, 0, ret, 0, offset); |
|
2. SampleLoginModule.java |
|
import java.io.IOException; |
|
import javax.security.auth.*; |
|
import javax.security.auth.callback.*; |
|
import javax.security.auth.login.*; |
|
import javax.security.auth.spi.*; |
|
import sample.principal.SamplePrincipal; |
|
public class SampleLoginModule implements LoginModule { |
|
private CallbackHandler callbackHandler; |
|
private boolean debug = false; |
|
private boolean succeeded = false; |
|
private boolean commitSucceeded = false; |
|
private SamplePrincipal userPrincipal; |
|
public void initialize(Subject subject, CallbackHandler callbackHandler, |
|
Map sharedState, Map options) { |
|
this.callbackHandler = callbackHandler; |
|
this.sharedState = sharedState; |
|
// initialize any configured options |
|
debug = "true".equalsIgnoreCase((String)options.get("debug")); |
|
public boolean login() throws LoginException { |
|
if (callbackHandler == null) |
|
throw new LoginException("Error: no CallbackHandler available " + |
|
"to garner authentication information from the user"); |
|
Callback[] callbacks = new Callback[2]; |
|
callbacks[0] = new NameCallback("user name: "); |
|
callbacks[1] = new PasswordCallback("password: ", false); |
|
callbackHandler.handle(callbacks); |
|
username = ((NameCallback)callbacks[0]).getName(); |
|
char[] tmpPassword = ((PasswordCallback)callbacks[1]).getPassword(); |
|
if (tmpPassword == null) { |
|
// treat a NULL password as an empty password |
|
tmpPassword = new char[0]; |
|
password = new char[tmpPassword.length]; |
|
System.arraycopy(tmpPassword, 0, |
|
password, 0, tmpPassword.length); |
|
((PasswordCallback)callbacks[1]).clearPassword(); |
|
} catch (java.io.IOException ioe) { |
|
throw new LoginException(ioe.toString()); |
|
} catch (UnsupportedCallbackException uce) { |
|
throw new LoginException("Error: " + uce.getCallback().toString() + |
|
" not available to garner authentication information " + |
|
System.out.println("\t\t[SampleLoginModule] " + |
|
"user entered user name: " + |
|
System.out.print("\t\t[SampleLoginModule] " + |
|
"user entered password: "); |
|
for (int i = 0; i < password.length; i++) |
|
System.out.print(password[i]); |
|
//检验用户名和用户密码.默认是"testUser"和"testPassword" |
|
boolean usernameCorrect = false; |
|
boolean passwordCorrect = false; |
|
if (username.equals("testUser")) |
|
System.out.println("\t\t[SampleLoginModule] " + |
|
"authentication succeeded"); |
|
System.out.println("\t\t[SampleLoginModule] " + |
|
"authentication failed"); |
|
for (int i = 0; i < password.length; i++) |
|
throw new FailedLoginException("User Name Incorrect"); |
|
throw new FailedLoginException("Password Incorrect"); |
|
public boolean commit() throws LoginException { |
|
if (succeeded == false) { |
|
//假设我们鉴别的用户是SamplePrincipal. |
|
userPrincipal = new SamplePrincipal(username); |
|
if (!subject.getPrincipals().contains(userPrincipal)) |
|
subject.getPrincipals().add(userPrincipal); |
|
System.out.println("\t\t[SampleLoginModule] " + |
|
"added SamplePrincipal to Subject"); |
|
for (int i = 0; i < password.length; i++) |
|
public boolean abort() throws LoginException { |
|
if (succeeded == false) { |
|
} else if (succeeded == true && commitSucceeded == false) { |
|
// login succeeded but overall authentication failed |
|
for (int i = 0; i < password.length; i++) |
|
public boolean logout() throws LoginException { |
|
subject.getPrincipals().remove(userPrincipal); |
|
succeeded = commitSucceeded; |
|
for (int i = 0; i < password.length; i++) |
|
package sample.principal; |
|
import java.security.Principal; |
|
public class SamplePrincipal implements Principal, java.io.Serializable { |
|
public SamplePrincipal(String name) { |
|
throw new NullPointerException("illegal null input"); |
|
public String getName() { |
|
public String toString() { |
|
return("SamplePrincipal: " + name); |
|
public boolean equals(Object o) { |
|
if (!(o instanceof SamplePrincipal)) |
|
SamplePrincipal that = (SamplePrincipal)o; |
|
if (this.getName().equals(that.getName())) |
|
4. 配置文件:sample_jaas.config: |
|
sample.module.SampleLoginModule required debug=true; |
|
编译SampleAcn.java ,SampleLoginModule.java,SamplePrincipal.java 到d:\temp(如:javac -d d:\temp SampleAcn.java SampleLoginModule.java,SamplePrincipal.java),然后将sample_jaas_config放入d:\temp目录,然后运行java -Djava.security.auth.login.config==sample_jaas.config sample.SampleAcn |
|
系统要求输入用户名和密码,输入:testUser 和testPassword,如果鉴别成功,将输出: |
|
[SampleLoginModule] user entered user name: testUser |
|
[SampleLoginModule] user entered password: testPassword |
|
[SampleLoginModule] authentication succeeded |
|
[SampleLoginModule] added SamplePrincipal to Subject |
|
Authentication succeeded! |
| |
|