我们有j_securtiy_check
工作的基于Web的表单登录身份验证。我们想通过程序化登录身份验证来更改它。让servlet验证传递给它的用户名和密码的正确方法是什么? servlet显然没有受到保护。
我们一直在试验这个server.xml Realm:
<Realm className="org.apache.catalina.realm.DataSourceRealm"
dataSourceName="UserDatabase"
userTable="app_user" userNameCol="login_name" userCredCol="password_value"
userRoleTable="user_perm" roleNameCol="permission_name"
allRolesMode="authOnly" digest="MD5"
/>
原因是我们有一个java webstart客户端,它将登录信息发送到不受保护的loginServlet。此servlet当前针对JOSSO单点登录服务进行身份验证,但我希望将其删除并对初学者使用简单的tomcat7身份验证。然后最终迁移到OpenAM。如果我可以以编程方式生成JSSESSIONIDSSO值并将其填充到cookie中。
这是我发现的一些代码。这是调用身份验证的正确方法吗?
ApplicationContextFacade acf = (ApplicationContextFacade) this.getServletContext();
Field privateField = ApplicationContextFacade.class.getDeclaredField("context");
privateField.setAccessible(true);
ApplicationContext appContext = (ApplicationContext) privateField.get(acf);
Field privateField2 = ApplicationContext.class.getDeclaredField("context");
privateField2.setAccessible(true);
StandardContext stdContext = (StandardContext) privateField2.get(appContext);
Realm realm = stdContext.getRealm();
Principal principal = realm.authenticate(loginBean.getUsername(), loginBean.getPassword());
if (principal == null)
{
return 0;
}
GenericPrincipal genericPrincipal = (GenericPrincipal) principal;
System.out.println ("genericPrincipal=" + genericPrincipal.toString());
答案 0 :(得分:5)
如果您已经使用Servlet 3.0或更高版本,则对于编程身份验证,请使用login()
的{{1}}方法。
HttpServletRequest
答案 1 :(得分:1)
我认为在Java webstart客户端应用程序中,当您需要请求身份验证时,您只需使用任何HTTP客户端使用POST方法将userName,密码发送到您的LoginServer。在loginServlet中,使用request.login(userName,password),然后以任何格式(XML,JSON)返回身份验证结果。在客户端,您还必须从响应头解析身份验证结果(POST结果)和JSESSIONID cookie。对于后续请求,您可能必须发送之前解析过的JSESSIONID。
答案 2 :(得分:1)
我想跟进这个。
真的没有一个简单的答案。
最后的代码使用纯反射来尝试在域内调用authenticate方法。问题在于,这实际上取决于所附的领域。
例如,JOSSO(org.josso.tc55.agent.jaas.CatalinaJAASRealm)没有这种方法。相反,它有一个叫做createPrincipal(String username,Subject subject)的东西。他们建议的这样做的过程(至少josso 1.5)是使用这样的代码: impl = getIdentityProvider(endpoint);
String assertion = impl.assertIdentityWithSimpleAuthentication(username,password);
sessionID = impl.resolveAuthenticationAssertion(assertion);
如果你使用OpenAM(这是我试图转移的)作为你的单一登录提供者而不是JOSSO,那就完全不同了。我目前的想法是使用他们直接从webstart客户端提供的RESTful服务。
我的第一个问题是 - 试图找到一个可以从webstart java客户端使用的API,1)没有巨大的jar文件大小,2)与tomee + CXF 2.6.4版一起使用。 (我对此不太了解,“是的,只需使用CXF 3.0客户端jar,因为它们可以与tomee +的CXF版本一起使用......”)
无论如何,如果您使用Tomcat7的固定数据源机制来设置领域,那么“应该”的代码可以工作。
Class c = Class.forName("org.apache.catalina.core.ApplicationContextFacade");
Object o = this.getServletContext();
System.out.println ("servletContext is really:" + o.getClass().getCanonicalName());
Field privateField = o.getClass().getDeclaredField("context");
privateField.setAccessible(true);
Object appContext = privateField.get(o);
Field privateField2 = appContext.getClass().getDeclaredField("context");
privateField2.setAccessible(true);
Object stdContext = privateField2.get(appContext);
Method getRealm = stdContext.getClass().getMethod("getRealm");
Object realm = getRealm.invoke(stdContext);
Principal principal = null;
try
{
Method authenticate = realm.getClass().getMethod("authenticate");
principal = (Principal)authenticate.invoke(realm, loginBean.getUsername(), loginBean.getPassword());
if (principal == null)
{
return 0;
}
}
catch (Exception e2)
{
// The authenticate method doesn't exist within the configured server.xml realm
e2.printStackTrace();
}
同样,如果您发现自己试图从不受保护的servlet中验证用户。
丹尼斯
答案 3 :(得分:0)
我注意到这已不再是最新的了。最终的解决方案是使用OpenAM提供的Java SDK。
这是起点:http://openam.forgerock.org/openam-documentation/openam-doc-source/doc/dev-guide/index/chap-jdk.html
1)将此SDK附带的所有jar文件添加到Web应用程序中。 2)将您的servlet(或重客户端)更改为具有以下代码:
private void addLoginCallbackMessage(LoginCredentialsBean loginBean, Callback [] callbacks)
throws UnsupportedCallbackException
{
int i = 0;
try
{
for (i = 0; i < callbacks.length; i++)
{
if (callbacks[i] instanceof TextOutputCallback)
{
handleTextOutputCallback((TextOutputCallback) callbacks[i]);
}
else if (callbacks[i] instanceof NameCallback)
{
handleNameCallback(loginBean.getUsername(), (NameCallback) callbacks[i]);
}
else if (callbacks[i] instanceof PasswordCallback)
{
handlePasswordCallback(loginBean.getPassword(), (PasswordCallback) callbacks[i]);
}
else if (callbacks[i] instanceof TextInputCallback)
{
handleTextInputCallback((TextInputCallback) callbacks[i]);
}
else if (callbacks[i] instanceof ChoiceCallback)
{
handleChoiceCallback((ChoiceCallback) callbacks[i]);
}
}
}
catch (IOException e)
{
e.printStackTrace();
throw new UnsupportedCallbackException(callbacks[i], e.getMessage());
}
}
private void handleTextOutputCallback(TextOutputCallback toc)
{
System.out.println("Got TextOutputCallback");
// display the message according to the specified type
switch (toc.getMessageType())
{
case TextOutputCallback.INFORMATION:
System.out.println(toc.getMessage());
break;
case TextOutputCallback.ERROR:
System.out.println("ERROR: " + toc.getMessage());
break;
case TextOutputCallback.WARNING:
System.out.println("WARNING: " + toc.getMessage());
break;
default:
System.out.println("Unsupported message type: " +
toc.getMessageType());
}
}
private void handleNameCallback(String name, NameCallback nc)
throws IOException
{
nc.setName(name);
}
private void handleTextInputCallback(TextInputCallback tic)
throws IOException
{
// not supported for server side
// prompt for text input
}
private void handlePasswordCallback(String password, PasswordCallback pc)
throws IOException
{
// prompt the user for sensitive information
pc.setPassword(password.toCharArray());
}
private void handleChoiceCallback(ChoiceCallback cc)
throws IOException
{
// not supported for server side
// ignore the provided defaultValue
/*
System.out.print(cc.getPrompt());
String [] strChoices = cc.getChoices();
for (int j = 0; j < strChoices.length; j++)
{
System.out.print("choice[" + j + "] : " + strChoices[j]);
}
System.out.flush();
cc.setSelectedIndex(Integer.parseInt((new BufferedReader
(new InputStreamReader(System.in))).readLine()));
*/
}
private void doLogin ()
{
// ... lots of other logic here
// TODO: Make this into modules with this one being for OpenAM
if (_useOpenAM)
{
String orgName = "/";
String moduleName = "DataStore";
String locale = "en_US";
AuthContext lc = new AuthContext(orgName);
AuthContext.IndexType indexType = AuthContext.IndexType.MODULE_INSTANCE;
lc.login(indexType, moduleName, locale);
boolean succeed = false;
Callback [] callbacks = null;
// get information requested from module
while (lc.hasMoreRequirements())
{
callbacks = lc.getRequirements();
if (callbacks != null)
{
addLoginCallbackMessage(loginBean, callbacks);
lc.submitRequirements(callbacks);
}
}
if (lc.getStatus() == AuthContext.Status.SUCCESS)
{
try
{
System.out.println("Login succeeded.");
openAMSessionId = lc.getAuthIdentifier();
System.out.println("lc.getAuthIdentifier()=" + openAMSessionId);
System.out.println("lc.getSuccessURL()=" + lc.getSuccessURL());
System.out.println("lc.getSSOToken().getAuthLevel()=" + lc.getSSOToken().getAuthLevel());
System.out.println("lc.getSSOToken().getAuthType()=" + lc.getSSOToken().getAuthType());
System.out.println("lc.getSSOToken().getHostName()=" + lc.getSSOToken().getHostName());
System.out.println("lc.getSSOToken().getIdleTime()=" + lc.getSSOToken().getIdleTime());
System.out.println("lc.getSSOToken().getMaxIdleTime()=" + lc.getSSOToken().getMaxIdleTime());
System.out.println("lc.getSSOToken().getMaxSessionTime()=" + lc.getSSOToken().getMaxSessionTime());
System.out.println("lc.getSSOToken().getTimeLeft()=" + lc.getSSOToken().getTimeLeft());
System.out.println("lc.getSSOToken().getIPAddress()=" + lc.getSSOToken().getIPAddress());
System.out.println("lc.getSSOToken().getTokenID()=" + lc.getSSOToken().getTokenID().toString());
System.out.println("lc.getSSOToken().getPrincipal()=" + lc.getSSOToken().getPrincipal().toString());
}
catch (Exception e)
{
e.printStackTrace();
}
succeed = true;
}
else if (lc.getStatus() == AuthContext.Status.FAILED)
{
System.out.println("Login failed.");
}
else
{
System.out.println("Unknown status: " + lc.getStatus());
}
System.out.println( "OpenAM login success=" + succeed);
}
}
上面代码中重要的是变量openAMSessionId。最终会有新的OpenAM单点登录会话ID,您可以将其传递给所有受保护的客户端应用程序,以便用户不会因登录而受到质疑。
我希望这会有所帮助。
-dklotz