Java 使用已配置的JAAS主体对HttpURLConnection进行身份验证?

Java 使用已配置的JAAS主体对HttpURLConnection进行身份验证?,java,authentication,servlets,websphere,jaas,Java,Authentication,Servlets,Websphere,Jaas,过去有几次,我不得不在WebSphere Application Server上运行的应用程序中建立经过身份验证的HTTP或HTTPS连接。 我通常创建了一些自定义的方式来存储连接的用户名和密码——使用文本或XML文件,或者,为了测试,只是硬编码——并将这些详细信息添加到HttpURLConnection中的授权头中,以执行HTTP基本身份验证 我最近认为WAS Integrated Solutions控制台有一种配置用户名和密码的方法(在安全->Java身份验证和授权服务->J2C身份验证数据

过去有几次,我不得不在WebSphere Application Server上运行的应用程序中建立经过身份验证的HTTP或HTTPS连接。
我通常创建了一些自定义的方式来存储连接的用户名和密码——使用文本或XML文件,或者,为了测试,只是硬编码——并将这些详细信息添加到HttpURLConnection中的授权头中,以执行HTTP基本身份验证

我最近认为WAS Integrated Solutions控制台有一种配置用户名和密码的方法(在安全->Java身份验证和授权服务->J2C身份验证数据下),使用内置功能(如果可能)而不是总是以自定义方式进行配置是有意义的,但是,经过一个小时左右的搜索,我还没有弄明白如何做到这一点

那么,有人知道使用配置好的WAS J2C身份验证数据对任意HTTP或HTTPS连接进行身份验证是否可能,以及如何做到这一点吗

我假设它需要WebSphere API来:

  • 通过别名检索表示J2C身份验证条目的对象;及
  • 执行以下操作之一:
    • 从JAAS/J2C对象获取经过身份验证的HttpURLConnection或HttpsURLConnection对象
    • 获取纯文本用户名和密码,以便将其添加到授权标头中;或
    • 如果连接到同一域中的IBM平台:从JAAS/J2C对象获取LTPA令牌,然后可以将其添加到连接中的cookie中。
另外:如果ApacheHttpClient可以使这变得更容易,我可以使用它,但是仍然需要适当的WebSphereAPI

我发现了一个可能对WebSpherePortal有用的类(
com.ibm.wps.portletservice.credentialvault.credentials.LtpaTokenCredential
),但我需要在非门户环境中这样做,所以我不能使用任何特定于门户的类或接口


至少在以下类型的应用程序中,我也需要这样做:servlet和WebSphere Trust Association拦截器。

我刚刚在servlet中尝试了以下()方法,它可以抓取auth alias user/pwd

import com.ibm.websphere.security.NotImplementedException;
import com.ibm.wsspi.security.auth.callback.Constants;
import com.ibm.wsspi.security.auth.callback.WSMappingCallbackHandlerFactory;
import javax.resource.spi.security.PasswordCredential;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;

Map map = new HashMap();
map.put(Constants.MAPPING_ALIAS, "REPLACE_WITH_YOUR_AUTH_ALIAS");
CallbackHandler callbackHandler = null;
try {
    callbackHandler = WSMappingCallbackHandlerFactory.getInstance().getCallbackHandler(map, null);
} catch (NotImplementedException e) {
}

LoginContext loginContext = null;
try {
loginContext = new LoginContext("DefaultPrincipalMapping", callbackHandler);
    loginContext.login();
} catch (LoginException e) {
}

Subject subject = loginContext.getSubject();
Set credentials = subject.getPrivateCredentials();

PasswordCredential passwordCredential = (PasswordCredential) credentials.iterator().next();

String user = passwordCredential.getUserName();
String password = new String(passwordCredential.getPassword());

response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<h1>User: " + user + " --- Password: " + password+"</h1>");
import com.ibm.websphere.security.NotImplementedException;
导入com.ibm.wsspi.security.auth.callback.Constants;
导入com.ibm.wsspi.security.auth.callback.WSMappingCallbackHandlerFactory;
导入javax.resource.spi.security.PasswordCredential;
导入javax.security.auth.Subject;
导入javax.security.auth.callback.CallbackHandler;
导入javax.security.auth.login.LoginContext;
导入javax.security.auth.login.LoginException;
Map Map=newhashmap();
map.put(Constants.MAPPING_ALIAS,“将_替换为您的_AUTH_ALIAS”);
CallbackHandler CallbackHandler=null;
试一试{
callbackHandler=WSMappingCallbackHandlerFactory.getInstance().getCallbackHandler(映射,null);
}捕获(未实现异常e){
}
LoginContext LoginContext=null;
试一试{
loginContext=新的loginContext(“DefaultPrincipalMapping”,callbackHandler);
loginContext.login();
}捕获(LoginException e){
}
Subject Subject=loginContext.getSubject();
Set credentials=subject.getPrivateCidentifications();
PasswordCredential PasswordCredential=(PasswordCredential)credentials.iterator().next();
字符串user=passwordCredential.getUserName();
字符串密码=新字符串(passwordCredential.getPassword());
response.setContentType(“text/html”);
PrintWriter out=response.getWriter();
out.println(“用户:+User+”---密码:+Password+”);

如果验证是在WAS服务器之间进行的,则无需进行这些长度的验证;只要参与的WAS服务器构成同一安全域的一部分并相互信任,LTPA令牌就应该足够了

如果您的想法是从非WAS服务器转到WAS服务器,则可以查看TAI选项,但仍然不需要使用身份验证别名

当我们从一个服务到下游服务进行身份验证时,我们只需传入LTPA令牌,如下所示(LTPA令牌不是门户,而是WAS)。假设有人已经在您的服务上进行了身份验证,例如从门户或WAS登录,我们希望调用另一个WAS服务器上的下游REST服务

/** For call to a REST client, use apache wink that comes with WAS:
* This method shows how to pass in the available LTPA token to create
* a RestClient
private org.apache.wink.client.RestClient getRestClient() {
  if (restClient == null) {
    org.apache.wink.client.ClientConfig config = new ClientConfig();    
    config.handlers(new org.apache.wink.client.handlers.LtpaAuthSecurityHandler());
    restClient = new RestClient(config);
  }
  return restClient;
}

有一种更安全的方法可以获取
密码凭据
。是否有一个
iterator()
方法接受
Class
参数?不确定引用的是什么。迭代器在Java 8之前没有任何方法可以获取参数,Java 8只引入了ForEachLeving,这需要一个消费者。我自己有机会测试这一点还需要几天,但它看起来不错。当我能够成功地测试它时,我会将其标记为应答。我有一个特定的案例,我需要调用IBM Connections REST API,在对任何用户进行身份验证之前,这些API需要管理员访问(用于创建连接用户配置文件)。我确信那时不会有任何LTPA代币。100%;然后,它将把系统用户的凭据存储为身份验证别名,按照描述获取它,并使用REST客户端添加基本身份验证头。