import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Hashtable;
import java.util.Properties;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import jet.server.api.UserSession;
import jet.server.api.http.HttpExternalAuthorized;



/** 
 * CustomHttpExternalAuthorized.java is a class that
 * implements the HttpExternalAuthorized interface.
 * This provides a way for an existing application
 * to co-operate with JReport Server to manage
 * a Single Sign On system to handle login to
 * the HTTP Session.
 */

/** 
 * This example implementation of HttpExternalAuthorized is used within 
 * this folder to show how to use this class so that an existing 
 * application can co-operate with the JReport Server 
 * login/security framework used by JSP pages and other servlets.
 * This file enables a Single Sign On function for JReport Server.
 *
 * This class's method getExternalAuthorizedUser() gets called by 
 * both the JReport HttpUtil.checkLogin() and 
 * HttpUserSessionManager.checkLogin() methods as a first step at 
 * identifying if an Authenticated user is logged into this web session.  
 * These checkLogin() methods are used by
 * all JReport JSP pages before they run, to verify that a JReport 
 * user is logged-in to the session.
 *
 * This method is how a user logged into the appliciation can be 
 * seen as logged into JReport Server without the user needing to 
 * do an another login dialog.
 *
 * See the javadoc for HttpUtil.checkLogin() and 
 *        HttpUserSessionManager.checkLogin()
 * for full details on what each checkLogin() method does within 
 * the login framework.
 * 
 * This class's method, handleUnAuthenticatedRequest(), will be 
 * called from HttpUserSessionManager.sendUnauthorizedResponse() 
 * before it sends the "HTTP 401 - Unauthorized" response.
 * (This HTTP 401 response initiates an HTTP Authentication dialog
 * with the browser, which prompts the user for login credentials.)
 * This call out to handlUnAuthenticatedRequest() allows the 
 * method here to handle the case by crafting a custom response 
 * that matches the application's need and then to notify
 * sendUnauthorizedResponse() to not send the HTTP 401 response.
 *
 * This is how to enforce a policy of using a single point of
 * log in using an application's log in system, rather than 
 * using HTTP Authentication for doing a log in.
 * With this method, the default login process and dialog used by 
 * JReport Server can be replaced with the login dialog used 
 * by the application.
 *
 * Note that HttpUtil.checkLogin() calls 
 * HttpUserSessionManager.sendUnAuthorizedResponse() when 
 * there is no user logged-in to the session and there 
 * is a failure to log in a user from credentials in the  
 * HTTP Request header or from credentials in the URL query parameters.  
 *
 * This sample code outputs activity messages to the console, 
 * rather than to a log file.  This is a demo, meant to show such
 * messages as part of the demo, so it is easy to see it is
 * running.  
 *
 * This class needs to be loaded at runtime so that JReport Server 
 * can call it from checkLogin().
 *
 * How to load this class: 
 * To install this demonstration program into JReport Server:
 *
 * 1. Compile it into CustomHttpExternalAuthorized.class 
 *    and put this into a jar file.  Then add a reference
 *    to this jar file into the CLASSPATH used for launching 
 *    JReport Server. 
 *
 *    If the class is put into external.jar in the lib folder, 
 *    add this entry to the CLASSPATH value in JReport.bat:
 *      CLASSPATH=...jar;%REPORTHOME%\lib\external.jar;%REPORTHOME%\lib.....
 *
 *
 * 2. Edit file <SERVER_PATH>/bin/server.bat and 
 *    <SERVER_PATH>/bin/server.sh add a system property to 
 *    the command line when starting the JVM, using the -D parameter
 *    using a key of jrs.httpExternalAuthorized,
 *    and a value of CustomHttpExternalAuthorized
 *
 *    Add:
 *      -Djrs.httpExternalAuthorized=CustomHttpExternalAuthorized
 *
 * 3. Restart JReport Server and this customized user authentication 
 *    class will be loaded and available.
 *    This  demo code will be run as part of JReport login/security framework.
 */
public class DemoExternalAuthorized implements HttpExternalAuthorized
{
    // Hold a list of known JReport users.
    Hashtable <String, String> jUsers = null;


    private String driver;
	private String dbUrl;
	private String dbUser;
	private String dbPassword;
	
	private static final String JRAUTH_KEY = "jrauth_key";
	private static final String JRAUTH_USERNAME = "jrauth_id";
	
	
	
    public DemoExternalAuthorized() {
        //******  Write message to console to show that class is loaded.  ****************
        System.out.println("======================"+this.getClass().getName()+" class is loaded");
		
		Properties initCfg = new Properties();
		
		try {
			initCfg.load(getClass().getResourceAsStream("/config/databaseCfg.ini"));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		driver = initCfg.getProperty("driver");
        dbUrl = initCfg.getProperty("dbUrl");
        dbUser = initCfg.getProperty("dbUser");
        dbPassword = initCfg.getProperty("dbPassword");
		
		try {
			Class.forName(driver);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
    }
    
    /**
     * read and delete auth information from database.
     * @param authKey
     * @return authorized jrUser
     * @throws SQLException
     */

    private String getAuthUserFromDb(String authKey, String username) throws SQLException {
    	//DDL: CREATE TABLE jr_auth(auth_key varchar(64), auth_uid varchar(256) NOT NULL, PRIMARY KEY(auth_key))
    	String jruser = null;
    	Connection con = DriverManager.getConnection(dbUrl, dbUser, dbPassword);
    	try {
    		//select userId from database according key
    		PreparedStatement st = con.prepareStatement("SELECT auth_uid FROM jr_auth WHERE auth_key=? and auth_uid=?");
    		try {
        		st.setString(1, authKey);
				st.setString(2, username);
        		ResultSet rs = st.executeQuery();
        		if(rs.next()) {
        			jruser = rs.getString(1);
        			System.out.println("\t found auth_key: " + authKey+", user="+jruser);
        		} else {
        			System.out.println("\t Authorized user not found for user: " + username + " with auth_key: " + authKey);
        			return null;
        		}
        		rs.close();
    		} finally {
    			st.close();
    		}
    		
    	} finally {
    		con.close();
    	}
    	return jruser;
    }
    


    /** 
     * Returns a JReport User ID associated with the currently logged in application user. 
     */
    public String getExternalAuthorizedUser(String activeRealm, HttpServletRequest req) {
		System.out.println("=====getExternalAuthorizedUser");
    	//HttpUtil.getHttpRptServer().getResourceManager().getAllUsers("admin")
        String jrauthKey = null;
		String jrusername = null;

        HttpSession session = req.getSession(true);
		
        if (session.getAttribute(JRAUTH_KEY) != null){
            jrauthKey = session.getAttribute(JRAUTH_KEY).toString();
			jrusername = session.getAttribute(JRAUTH_USERNAME).toString();
        }

        if (jrauthKey == null) {
            jrauthKey = req.getHeader(JRAUTH_KEY);
			jrusername = req.getHeader(JRAUTH_USERNAME);
        }

        if (jrauthKey == null) {
            jrauthKey = req.getParameter(JRAUTH_KEY);
			jrusername = req.getParameter(JRAUTH_USERNAME);
        }

        if (jrauthKey != null) {
        	try {
				String jruser = getAuthUserFromDb(jrauthKey, jrusername);
				return jruser;
			} catch (Exception e) {
				System.out.println("Exception: " + e.getMessage());
				e.printStackTrace();
			}
        }

        System.out.println("\t getExternalAuthorizedUser: unauthorized request");
        return null;
    }

    /** 
     *
     * getExternalAuthorizedUser(String activeRealm, Object userInfo)
     *
     * This signature of the getExternalAuthorizedUser() is not a known use case.
     * It exists in the Java interface definition for potential future use.
     *
     */
    public String getExternalAuthorizedUser(String activeRealm, Object userInfo) {
        if (userInfo instanceof HttpServletRequest) {
            // Only one userInfo type is supported - the one used by the other signature.
            return getExternalAuthorizedUser(activeRealm, (HttpServletRequest)userInfo);
        } else {
            System.out.println("Unknown userInfo object! " + userInfo);
            return null;
        }
    }

    /** 
     * Ask to invalidate an external authorized user session(i.e. the session expired).
     * The report server calls this method before invalidating the session. 
     * Note: The server does not call this method when an user logs out. 
     * The method notifyLogout(...) will be called after logout.
     * @param userSession the user session. 
     *
     * @return true invalidate the session. false do not invalidate the session.
     */
    public boolean askInvalidate(UserSession userSession) {
        System.out.println("=======askInvalidate="+userSession.getUserID());

        //return true to invalidate the user session, else return false.
        return true;
    }

    /** 
     * Notify an external authorized user session logout.
     * The report server calls this method after logout. 
     * @param userSession the user session. 
     */
    public void notifyLogout(UserSession userSession) {
        System.out.println("=====notifyLogout="+userSession.getUserID());
    }

    /** 
     * Handle the case where an Unauthorized Response should be sent to the client.
     */
    public boolean handleUnAuthenticatedRequest(HttpServletRequest req,
                                                 HttpServletResponse res,
                                                 String authScheme,
                                                 String realm) throws java.io.IOException {
    	System.out.println("======handleUnAuthenticatedRequest: false");
    	// generate  HTML to display in browser 
        res.setStatus(HttpServletResponse.SC_OK);
        res.setContentType("text/html");
        PrintWriter writer = res.getWriter();
        writer.println("<html>");
        writer.println("<head>");
        writer.println("<title>Unauthorized Request Noticed</title>");
        writer.println("</head>");
        writer.println("<body>");
        writer.println("<b>Unauthorized request is handled by SSO module: "+DemoExternalAuthorized.class.getName()+"</b>");
        writer.println("<br/>Because this JReport session timeout or been logout. <p/>");
        writer.println("<b>Please logout from main application and login again.</b>");
        writer.println("</body>");
        writer.println("</html>");
    	return false;
    }
    
}
