PrivilegedAction
任何实现PrivilegedAction接口的类都封装了一些代码Java客户端可以在由已填充的Subject定义的安全上下文中运行这些代码在这种安全上下文下调用已授权动作之前weblogicsecuritySecurityrunAs( )方法允许客户端把一个Subject与当前线程相关联
示例JAAS客户端
让我们考察一下如何构建一个能够为WebLogic对自身进行身份验证的JAAS客户端我们将使用从上至下的方法讲述这个例子从JAAS客户端需要实现的内容开始然后再细分为其实现的单个组件让我们从主类SimpleJAASClient开始采取以下步骤
它从命令行读取用户名密码和URL作为输入参数
它尝试连接到特定的URL然后使用所提供的用户名和密码对客户端进行身份验证
它在新获得的已验证对象下执行一个已授权的动作例列出了我们的JAAS客户端的源代码
例列出了我们的JAAS客户端的源代码
例示例JAAS客户端
package comoreillywlguidesecurityjaas;
import javaxsecurityauthSubject;
import javaxsecurityauthloginLoginContext;
public class SimpleJAASClient {
public static void main(String[] args) {
String username = args[];
String password = args[];
String url = args[];
LoginContext loginContext = null;
// Create a LoginContext using our own CallBackHander
try {
loginContext = new LoginContext(Simple
new SimpleCallbackHandler(username password url));
} catch (Exception e) {
// Can get a SecurityException or a LoginException
eprintStackTrace( );
Systemexit();
}
// Now authenticate If we dont get an exception we succeeded
try {
loginContextlogin( );
} catch (Exception e) {
// Can get FailedLoginException AccountExpiredException
// or CredentialExpiredException
eprintStackTrace( );
Systemexit();
}
// Retrieve authenticated subject and perform action using it
Subject subject = loginContextgetSubject( );
SimpleAction simpleAction = new SimpleAction(url);
weblogicsecuritySecurityrunAs(subject simpleAction);
}
}
注意我们是如何突出JAAS客户端的重点部分的我们的第一个关键步骤是建立LoginContext对象
loginContext = new LoginContext(Simplenew SimpleCallbackHandler(username password url));
LoginContext对象使用将在JAAS身份验证期间使用的CallBackHandler和LoginModule实例初始化了客户端构造器带的第二个参数是我们自己的CallBackHandler实例LoginModule将使用它来获得用户证书以及将对我们的客户端进行身份验证的WebLogic实例的URL
构造器带的第一个参数是Simple用于为客户端查找适当的LoginModuleJAAS客户端依赖于一个配置文件该配置文件把JAAS登录模块的名称映射为它们的实现而且还指定了另外的参数例列出了我们使用的JAAS配置文件
例 登录配置文件nfig
Simple {
weblogicsecurityauthloginUsernamePasswordLoginModule
required
};
我们的配置文件包含一个Simple入口在给定用户名和密码的基础上为身份验证指定了WebLogic的LoginModule weblogicsecurityauthloginUsernamePasswordLoginModule当运行JAAS客户端时必须使用一个系统属性指定该配置文件的位置下面说明了如何运行我们的示例JAAS客户端
java Djavasecnfig=nfig comoreillywlguidesecurityjaasSimpleJAASClient system pssst t://:
/
这样我们就可以配置LoginContext以使用WebLogic的 LoginModule它支持使用用户名-密码组合的身份验证稍后我们将看一看如何使用JAAS配置文件透明地使用LoginModule实现来代替这种方法
建立登录上下文之后我们调用了loginContextlogin( )方法来执行实际的登录我们的LoginContext将利用已配置的登录模块和回调处理对象并尝试借助服务器对客户端进行身份验证如果客户端成功通过身份验证可以从LoginContext获得已验证的主题
Subject subject = loginContextgetSubject( );
这个已验证Subject上的getPrincipals( )方法将获得与用户相关的所有主体例如如果我们的JAAS客户端使用系统管理员的证书进行身份验证已验证的Subject将具有两个主体代表用户的system和代表用户的组的Administrators现在我们可以使用这个主题来执行一个或多个已授权的操作换句话说这些操作是在这个已验证主题的上下文中执行的
weblogicsecuritySecurityrunAs(subject simpleAction);
这里给出一个忠告——客户端必须调用WebLogic的Security类上的runAs( )方法runAs( )方法带有两个参数已验证的Subject和一个PrivilegedAction对象后者包装了应用程序与服务器的特定交互例说明了我们的JAAS客户端希望执行的操作
例 一个非常简单的操作
package comoreillywlguidesecurityjaas;
import javasecurityPrivilegedAction;
import javasqlConnection;
import javautilHashtable;
import javaxnamingContext;
import javaxnamingInitialContext;
import javaxsqlDataSource;
public class SimpleAction implements PrivilegedAction {
private static final String JNDI_NAME = jdbcxpetstore;
private String url;
public SimpleAction(String url) {
thisurl = url;
}
public Object run( ) {
Object obj = null;
try {
Context ctx = null;
Hashtable ht = new Hashtable( );
htput(ContextINITIAL_CONTEXT_FACTORY
weblogicjndiWLInitialContextFactory);
htput(ContextPROVIDER_URL url);
// Get a context for the JNDI lookup
ctx = new InitialContext(ht);
// do any work here
DataSource ds =(javaxsqlDataSource) ctxlookup(JNDI_NAME);
//
} catch (Exception e) {
eprintStackTrace( );
}
return obj;
}
}
在这里需要考虑以下重点
类实现 javasecurityPrivilegedAction接口然后任何JAAS 客户端都可以在已验证Subject的上下文中调用这个类的一个实例
run( )方法封装了客户端与服务器的交互通常客户端将建立一个JNDI上下文使用它来获取绑定到JNDI树的资源然后调用/访问这些资源在前面的例子中我们使用了JNDI上下文来获得JDBC数据源
当我们在PrivilegedActionrun( )方法中建立JNDI上下文时我们没有为JNDI身份验证提供任何用户证书JAAS客户端提供已验证的Subject给runAs( )方法确保PrivilegedAction对象是在这个主题的上下文中调用的也就是说runAs( )方法负责把已验证的主题与当前线程关联起来
例列出了我们的CallBackHandler类的源代码通常回调处理程序将与客户端交互提示用户输入用于身份验证的用户名和密码在我们的简单JAAS客户端的例子中我们提供了必需的证书和URL给我们的回调处理程序的构造器这样回调便可容易地返回这些信息
例 一个简单的回调处理器
package comoreillywlguidesecurityjaas;
import javaxsecurityauthcallbackCallback;
import javaxsecurityauthcallbackCallbackHandler;
import javaxsecurityauthcallbackNameCallback;
import javaxsecurityauthcallbackPasswordCallback;
import javaxsecurityauthcallbackUnsupportedCallbackException;
import weblogicsecurityauthcallbackURLCallback;
public class SimpleCallbackHandler implements CallbackHandler {
private String username = null;
private String password = null;
private String url = null;
public SimpleCallbackHandler(String pUsername String pPassword String pUrl) {
username = pUsername; password = pPassword; url = pUrl;
}
public void handle(Callback[] callbacks)
throws javaioIOException UnsupportedCallbackException {
for (int i = ; i < callbackslength; i++) {
if (callbacks[i] instanceof NameCallback) {
NameCallback nc = (NameCallback) callbacks[i];
ncsetName(username);
} else if (callbacks[i] instanceof URLCallback) {
URLCallback uc = (URLCallback) callbacks[i];
ucsetURL(url);
} else if (callbacks[i] instanceof PasswordCallback) {
PasswordCallback pc = (Pa