jcifs包实现域认证的单点登录带来了个奇怪的问题
先简述一下系统使用的技术,框架是struts1.2,action继承LookupDispatchAction,页面的验证使用validation,应用服务器为jboss4.2
问题描述:
在web.xml配置文件中配置了实现域登录的Servlet后出现如下问题:
点击系统的“增加”按钮弹出的页面中的“保存”按钮无法调用action中对应的方法;
“修改”按钮弹出页面的“保存”则出现如下错误
WARN [RequestProcessor] Unhandled Exception thrown: classjavax.servlet.ServletException
INFO [[/]] Request[/doc/docmanagedetailaction] does not contain handlerparameter named 'act'. This may be caused by whitespace in the label text.
jsp页面中的“保存”按钮代码
<html:submit styleClass="button" property="act"onclick="return chkpagecount();">
<bean:message key="button.save" />
</html:submit>
实现域登录的Java文件(http://www.jcifs.com/可以下载相应的jar包)
/**
* 本java文件来自于jcifs.http.NtlmHttpFilter.java
*/
@SuppressWarnings({"serial","unused"})
public class ADServlet extends HttpServlet {
private static LogStream log = LogStream.getInstance();
private String defaultDomain;
private String domainController;
private boolean loadBalance;
private boolean enableBasic;
private boolean insecureBasic;
private String realm;
private Map map;
/**
* Initialize this servlet.
*
* @exception ServletException
* if we cannot configure ourselves correctly
*/
public void init(ServletConfig config) throws ServletException {
map=new HashMap();
Config.setProperty("jcifs.smb.client.soTimeout","1800000");
Config.setProperty("jcifs.netbios.cachePolicy","1200");
Config.setProperty("jcifs.smb.lmCompatibility","0");
Config.setProperty("jcifs.smb.client.useExtendedSecurity","false");
Enumeration e = config.getInitParameterNames();
do {
if (!e.hasMoreElements()) {
break;
}
String name = (String) e.nextElement();
if (name.startsWith("jcifs.")) {
Config.setProperty(name, config.getInitParameter(name));
}
} while (true);
defaultDomain = Config.getProperty("jcifs.smb.client.domain");
domainController =Config.getProperty("jcifs.http.domainController");
if (domainController == null) {
domainController = defaultDomain;
loadBalance = Config.getBoolean("jcifs.http.loadBalance",true);
}
enableBasic =Boolean.valueOf(Config.getProperty("jcifs.http.enableBasic")).booleanValue();
insecureBasic =Boolean.valueOf(Config.getProperty("jcifs.http.insecureBasic")).booleanValue();
realm = Config.getProperty("jcifs.http.basicRealm");
if (realm == null) {
realm = "jCIFS";
}
int level;
if ((level = Config.getInt("jcifs.util.loglevel", -1)) != -1){
LogStream.setLevel(level);
}
LogStream _tmp = log;
if (LogStream.level > 2) {
try {
Config.store(log, "JCIFS PROPERTIES");
} catch (IOException ioe) {
}
}
}
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws IOException, ServletException {
NtlmPasswordAuthentication ntlm;
try{
if ((ntlm = negotiate(request, response, false)) == null) {
return;
} else {
String uuname=(String)map.get("adremoteuser");
System.out.println("\t\t域登陆用户名:"+uuname);
uuname=uuname.substring(uuname.indexOf("\\")+1,uuname.length());response.sendRedirect(request.getContextPath()+"/loginaction.do?act=login&companycode=test&username="+uuname+"&password=***");
return;
}
}catch (Exception e) {
e.printStackTrace();
}
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws IOException, ServletException {
doGet(request, response);
}
public void destroy() {
map=null;
}
protected NtlmPasswordAuthentication negotiate(HttpServletRequest req,HttpServletResponse resp,
boolean skipAuthentication) throws IOException, ServletException {
NtlmPasswordAuthentication ntlm = null;
String msg = req.getHeader("Authorization");
boolean offerBasic = enableBasic && (insecureBasic ||req.isSecure());
if (msg != null && (msg.startsWith("NTLM ") ||offerBasic && msg.startsWith("Basic "))) {
UniAddress dc;
if (msg.startsWith("NTLM ")) {
HttpSession ssn = req.getSession();
byte challenge[];
if (loadBalance) {
NtlmChallenge chal = (NtlmChallenge) ssn.getAttribute("NtlmHttpChal");
if (chal == null) {
chal = SmbSession.getChallengeForDomain();
ssn.setAttribute("NtlmHttpChal", chal);
}
dc = chal.dc;
challenge = chal.challenge;
} else {
dc = UniAddress.getByName(domainController, true);
challenge = SmbSession.getChallenge(dc);
}
if ((ntlm = NtlmSsp.authenticate(req, resp, challenge)) == null) {
return null;
}
ssn.removeAttribute("NtlmHttpChal");
} else {
String auth = new String(Base64.decode(msg.substring(6)),"US-ASCII");
int index = auth.indexOf(':');
String user = index == -1 ? auth : auth.substring(0, index);
String password = index == -1 ? "" : auth.substring(index +1);
index = user.indexOf('\\');
if (index == -1) {
index = user.indexOf('/');
}
String domain = index == -1 ? defaultDomain : user.substring(0,index);
user = index == -1 ? user : user.substring(index + 1);
ntlm = new NtlmPasswordAuthentication(domain, user, password);
dc = UniAddress.getByName(domainController, true);
}
map.put("adremoteuser", ntlm.getName());
try {
SmbSession.logon(dc, ntlm);
LogStream _tmp = log;
if (LogStream.level > 2) {
log.println("NtlmHttpFilter: " + ntlm + " successfullyauthenticated against " + dc);
}
} catch (SmbAuthException sae) {
LogStream _tmp1 = log;
if (LogStream.level > 1) {
log.println("NtlmHttpFilter: " + ntlm.getName() + ":0x" + Hexdump.toHexString(sae.getNtStatus(), 8) + ": " + sae);
}
SmbAuthException _tmp2 = sae;
if (sae.getNtStatus() == 0xc0000005) {
HttpSession ssn = req.getSession(false);
if (ssn != null) {
ssn.removeAttribute("NtlmHttpAuth");
}
}
resp.setHeader("WWW-Authenticate", "NTLM");
if (offerBasic) {
resp.addHeader("WWW-Authenticate", "Basicrealm=\"" + realm + "\"");
}
resp.setStatus(401);
resp.setContentLength(0);
resp.flushBuffer();
return null;
}
req.getSession().setAttribute("NtlmHttpAuth", ntlm);
} else if (!skipAuthentication) {
HttpSession ssn = req.getSession(false);
if (ssn == null || (ntlm = (NtlmPasswordAuthentication)ssn.getAttribute("NtlmHttpAuth")) == null) {
resp.setHeader("WWW-Authenticate", "NTLM");
if (offerBasic) {
resp.addHeader("WWW-Authenticate", "Basicrealm=\"" + realm + "\"");
}
resp.setStatus(401);
resp.setContentLength(0);
resp.flushBuffer();
return null;
}
}
return ntlm;
}
}
Web.Xml中配置
<servlet>
<servlet-name>myadservlet</servlet-name>
<servlet-class>com. company.test.ADServlet</servlet-class>
<init-param>
<param-name>jcifs.http.domainController</param-name>
<param-value>172.16.2.101</param-value>
</init-param>
<init-param>
<param-name>jcifs.netbios.wins</param-name>
<param-value>172.16.2.101,172.16.2.105</param-value>
</init-param>
<init-param>
<param-name>jcifs.smb.client.domain</param-name>
<param-value>dns. company.net.cn</param-value>
</init-param>
<init-param>
<param-name>jcifs.smb.client.soTimeout</param-name>
<param-value>18000</param-value>
</init-param>
<init-param>
<param-name>jcifs.netbios.cachePolicy</param-name>
<param-value>1200</param-value>
</init-param>
<init-param>
<param-name>jcifs.util.loglevel</param-name>
<param-value>0</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
若要解决此问题,从客户端,使用注册表编辑器 (Regedt32.exe) 将值添加到以下注册表项:
HKEY_CURRENT_USER/软件/microsoft/windows/CurrentVersion/internet设置 /
注意上面的注册表项是一个路径,它经过了折行以提高可读性。
添加以下注册表值:
值名称: DisableNTLMPreAuth
数据类型: REG_DWORD
值: 1
除了注册表项还需要关闭 Internet Explorer 中 启用集成 Windows 身份验证。 若要这样做,请按照下列步骤操作:
启动 Internet Explorer。
单击 工具,请单击 Internet 选项,然后单击 高级 选项卡。
在 安全,下单击以取消选择 启用集成 Windows 身份验证 (需要重启动),然后单击 应用。
关闭 Internet Explorer。
若要解决此问题,从服务器端,配置网站以使用下列身份验证方法之一:
若要允许匿名访问仅网站进行配置。
配置为允许匿名访问和 NLTM 身份验证 (集成 Windows 身份验证) 的网站