Tomcat 7 JSP页面:使用Shibboleth身份验证会话在Tomcat中进行身份验证时避免500错误

问题描述 投票:0回答:1

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):

http://www.i2b2.org

testshib:

(我们按照此建立了Shibboleth服务提供商)

http://www.testshib.org/

Shibboleth IdP:

http://shibboleth.net/

问题:

页面在状态代码为500的JSP页面上失败,在设置“id”的行上,因为它上面的行有一个“auth”变量(Java中的List<string>类型),它是null。请注意,此页面包含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>

可能为这个问题提供可能答案的想法:

  1. 在ASP.NET中,如果会话不存在,您可以告诉它自动重定向到另一个页面(使用配置)。 Tomcat是否通过提供某些条件(使用代码)来提供该功能?
  2. 我们如何强制杀死Tomcat会话(不处理此页面),并重定向,好像我们对i2b2有一个全新的请求?我知道在ASP.NET中,如果收到应用程序错误,可以调用代码。 Tomcat能提供什么吗?
  3. 如果我们想要更多地破解这个页面,我们怎样才能简单地避免条件错误,但仍然有页面进程,然后重定向?

还有其他想法吗?

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();
        }

    }
}
jsp tomcat authentication shibboleth i2b2
1个回答
0
投票

事实上,Tomcat确实可以捕获未处理的应用程序异常。它等同于ASP.NET Application_Error事件。这可能不是一个优雅的解决方案,但它现在有效。每当我们得到任何JSP异常时,我们都应该重定向到这个error.jsp页面,然后通过在error.jsp页面代码中强制重定向来重定向到Shibboleth IdP登录页面。

在部署web.xml文件中设置此项。这与i2b2部署文件夹有关。

<error-page>
        <exception-type>java.lang.Throwable</exception-type>
        <location>/error/error.jsp</location>
</error-page>

然后我把它扔进了error.jsp页面:

<%@ page isErrorPage="true" import="java.io.*" contentType="text/plain"%>

Message:
<%=exception.getMessage()%>

StackTrace:
<%
    // redirect to Shibboleth IdP login page
    String redirectURL = "https://redirecturl/";
    response.sendRedirect(redirectURL);
%>

然后重新启动Linux服务。它必须按此顺序完成,因为与shibd和tomcat服务存在依赖关系。

service httpd stop
service tomcat stop
service jboss stop
service shibd stop
service shibd start
service jboss start
service tomcat start
service httpd start
© www.soinside.com 2019 - 2024. All rights reserved.