Tomcat 7 异常:
Apache Tomcat/7.0.63 - HTTP 状态 500 - 处理 JSP 页面时发生异常
参考:
我将此代码与我们的 i2b2 应用程序集成,因此我们可以针对我们的 Shibboleth IdP 进行身份验证。
https://github.com/HSSC/i2b2-web-integration/blob/master/doc/INSTALL.md
应用程序(i2b2):
测试:
(我们按照这个来构建 Shibboleth 服务提供商)
Shibboleth IdP:
问题:
该页面在状态代码为 500 的 JSP 页面上失败,在设置“id”的行上,因为它上面的行有一个List<string>
为空的“auth”变量(Java 中的类型)。请注意,此页面具有 JSP 标记和 Javascript 的组合。
login.jsp 页面上失败的代码片段:
function initI2B2()
{
// alert('initI2B2');
<%
shibboleth.ConnectDatabase auth = (shibboleth.ConnectDatabase) session.getAttribute("connectDatabase");
String id = org.apache.commons.lang.StringEscapeUtils.escapeHtml(auth.getUser().identifier); // fails here because the List<string> object is null
String sessionId = org.apache.commons.lang.StringEscapeUtils.escapeHtml(auth.getUser().session);
Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateTime = sdf.format(cal.getTime());
String token = DigestUtils.sha512Hex(dateTime + sessionId);
%>
var passedInUserKey = "<%= org.apache.commons.lang.StringEscapeUtils.escapeHtml(auth.getUser().identifier)%>";
var passedInPassKey = "<%= org.apache.commons.lang.StringEscapeUtils.escapeHtml(auth.getUser().session)%>";
var passedInDomainK = "demo";
var passedInInstitutionid = "1";
var tokenV = "<%= token%>";
造成这种情况的工作流程?
如果我们有一个好的会话,代码通常会很好。我们现在的解决方法是让会话在 24 小时内超时。
这是导致错误的工作流程...
点击 i2b2 页面 > 自动重定向到 Shibboleth IdP > 使用 IdP 凭据登录 > 重定向回 i2b2 页面 > 此代码将用户和会话 ID(密码)从 Shibboleth 会话中取出,并使用它自动授权进入 i2b2 应用程序。
login.jsp 页面被黑客入侵以从 Shibboleth 会话中获取数据,因此用户不必输入凭据。
问题是当 shibboleth 会话超时,或者 Tomcat 会话过期或者浏览器中的缓存被清除时,就会出现这个错误,因为整个页面需要会话中的这两个变量(id 和密码)。
清除缓存是获得此错误的最快方法。另一种方法是将 Tomcat 默认会话超时从 30 分钟更改为 1 分钟。
<session-config>
<session-timeout>1</session-timeout>
</session-config>
可能为这个问题提供可能答案的想法:
在 ASP.NET 中,如果会话不存在,您可以告诉它自动重定向到另一个页面(使用配置)。Tomcat 是否通过给它一些条件(带有代码)来提供该功能?
我们如何强行终止 Tomcat 会话(不处理此页面),并像我们对 i2b2 有一个全新的请求一样重定向?我知道在 ASP.NET 中,如果收到应用程序错误,可以调用一些代码。Tomcat 提供什么吗?
如果我们想更深入地破解这个页面,我们怎么能简单地通过条件避免错误,但仍然有页面进程,然后重定向?
还有其他想法吗?
package edu.tmc.uth.i2b2shibboleth;
import java.security.*;
import java.sql.*;
import java.util.*;
import javax.faces.bean.*;
import javax.faces.context.*;
import javax.servlet.ServletContext;
import javax.servlet.http.*;
/**Manages the retrieval of Shibboleth attributes and the connection to the
* i2b2 hive database.
*
* @author JRussell
*/
@ManagedBean(name = "connectDatabase")
@SessionScoped
public class ConnectDatabase implements HttpSessionBindingListener {
private User user;
private Connection connection;
private List<String> test = new ArrayList<String>();
String propertyPath = null;
private ResourceBundle properties;
public User getUser() {
return user;
}
/*Main function for retrieving Shibboleth information and updating
* database records. This is called from the Facelets page (index.xhtml).
*/
public List<String> getUserInfo() {
try {
connection = connectToDatabase();
setShibbolethAttributes();
updateI2b2UserDatabase();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
return test;
}
/*Returns a connection to the i2b2 hive database.
* Uses the properties in the database.properties file.
*/
public Connection connectToDatabase() {
try {
properties = ResourceBundle.getBundle("edu/tmc/uth/i2b2shibboleth/database");
String url = properties.getString("I2B2_PM.connectionURL");
String userName = properties.getString("I2B2_PM.userName");
String password = properties.getString("I2B2_PM.password");
Class.forName(properties.getString("I2B2_PM.databaseClass"));
connection = DriverManager.getConnection(url, userName, password);
if (connection != null) {
System.out.println("connected to DB");
test.add("Connected to i2b2 hive database.");
}
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return connection;
}
/*Populates the Shibboleth attributes into the User object.
* The request header values are based on the attribute-map.xml configuration
* file on the Shibboleth Service Provider. The attribute identifiers and
* the attributes released are configured on an institutional basis.
*/
public void setShibbolethAttributes() {
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
String firstName = request.getHeader("Shib-InetOrgPerson-givenName");
String lastName = request.getHeader("Shib-Person-surname");
String email = request.getHeader("Shib-InetOrgPerson-mail");
String identifier = request.getHeader("Shib-iamPerson-subjectUniqueId");
String session = request.getHeader("Shib-Session-ID");
user = new User(firstName, lastName, email, identifier, session);
test.add("Basic User attributes");
test.add(user.toString());
test.add("All Shibboleth headers");
//Outputs all of the headers from the Shibboleth request
Enumeration enumer = request.getHeaderNames();
while(enumer.hasMoreElements()){
String headerName = enumer.nextElement().toString();
if(headerName.startsWith("Shib")){
test.add(headerName+" - "+request.getHeader(headerName));
}
}
}
/*Add a new user to the i2b2 hive database if they don't have an existing record.
* Update the password and enable the user if the i2b2 user already exists.
*/
private void updateI2b2UserDatabase() throws SQLException {
//Try to find current user in database
String stmt = "SELECT user_id FROM pm_user_data WHERE user_id=?";
PreparedStatement pst = connection.prepareStatement(stmt);
pst.setString(1, user.identifier);
System.out.println(stmt+" "+user.identifier);
ResultSet result = pst.executeQuery();
//user record found in database so update password
if (result.next()) {
System.out.println("user record found");
test.add("Subject identifier already in database - " + result.getString("user_id"));
stmt = "UPDATE pm_user_data SET password=?, status_cd=? WHERE user_id=?";
pst = connection.prepareStatement(stmt);
pst.setString(1, encryptMD5(user.session));
pst.setString(2, "A");
pst.setString(3, user.identifier);
pst.executeUpdate();
connection.commit();
}
else { //new user so add record to database
test.add("New user - " + user.identifier + " " + user.first + " " + user.last);
stmt = "INSERT INTO pm_user_data (user_id, full_name, password, email, status_cd) \n"
+ "VALUES (?,?,?,?,?)";
pst = connection.prepareStatement(stmt);
pst.setString(1, user.identifier);
pst.setString(2, user.first + " " + user.last);
pst.setString(3, encryptMD5(user.session));
pst.setString(4, user.email);
pst.setString(5, "A");
pst.executeUpdate();
//assign user roles to i2b2 project
String project = properties.getString("I2B2_PM.projectName");
pst = connection.prepareStatement("INSERT INTO pm_project_user_roles (project_id, user_id, user_role_cd, status_cd) \n"
+ "VALUES (?,?,?,?)");
pst.setString(1, project);
pst.setString(2, user.identifier);
pst.setString(3, "DATA_OBFSC");
pst.setString(4, "A");
pst.executeUpdate();
pst.setString(3, "DATA_AGG");
pst.executeUpdate();
pst.setString(3, "USER");
pst.executeUpdate();
connection.commit();
}
}
/* The i2b2 applications expect passwords to be encrypted.
*This function encrypts passwords with MD5 before inserting them
*into the database.
*/
private String encryptMD5(String text) {
String encrypted = "";
byte[] defaultBytes = text.getBytes();
try {
MessageDigest algorithm = MessageDigest.getInstance("MD5");
algorithm.reset();
algorithm.update(defaultBytes);
byte messageDigest[] = algorithm.digest();
StringBuilder hexString = new StringBuilder();
for (int i = 0; i < messageDigest.length; i++) {
hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
}
encrypted = hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return encrypted;
}
/*Function needed to implement HttpSessionBindingListener.
* Don't need to modify the function itself.
*/
public void valueBound(HttpSessionBindingEvent event) {
//do nothing
}
//This function deactivates a user in the i2b2 hive database when
//the user session times out. Session timeout is set in web.xml.
public void valueUnbound(HttpSessionBindingEvent event) {
connection = connectToDatabase();
try {
//Try to find current user in database
String stmt = "SELECT user_id FROM pm_user_data WHERE user_id=?";
PreparedStatement pst = connection.prepareStatement(stmt);
pst.setString(1, user.identifier);
ResultSet result = pst.executeQuery();
//user record found in database so deactivate them since they have logged off
if (result.next()) {
System.out.println("in results.next");
stmt = "UPDATE pm_user_data SET status_cd=? WHERE user_id=?";
pst = connection.prepareStatement(stmt);
pst.setString(1, "D");
pst.setString(2, user.identifier);
pst.executeUpdate();
connection.commit();
}
connection.close();
ServletContext context = event.getSession().getServletContext();
FacesContext.getCurrentInstance().getExternalContext().redirect("logout.xhtml");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}