// 2012-07-08 johnpfeiffer requires Password, SSLCertificate, SSLKey, SSLUtility
// TODO: REFACTOR saveSSLInput( HttpServletRequest request , PrintWriter out )
// TODO: Unit Tests
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.UUID;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class UploadSSL extends HttpServlet
{
private static final long serialVersionUID = 1L;
private static final String CLASSVERSION = "0.54";
private static final String PARAMLOGINUSERPASSWORD = "userPassword";
private static final String PARAMLOGINBUTTON = "login";
private static final String PARAMLOGOUTBUTTON = "logout";
private static final String FORMSTYLE = "style ='margin: 0px; padding: 0px;'";
private static final String LOGOUTFORMSTYLE = "style ='margin: 0px; padding: 0px;'";
private static String SSLLOCATION = "/var/lib/ssl/";
private static String SSLKEYFILENAME = "cert.key";
private static String SSLCERTIFICATEFILENAME = "cert.crt";
private static String SSLINTERMEDIATEFILENAME = "intermediate.crt";
Password loginPassword = null;
private static String servletURL;
private ArrayList <String> authorizedTokens;
public void init( ServletConfig config ) throws ServletException
{
super.init( config );
authorizedTokens = new ArrayList <String>();
writeToLog( "UploadSSL version " + CLASSVERSION );
loginPassword = new Password( 8 );
writeToLog( "One time use login password: " + loginPassword.get() );
}
protected void doGet( HttpServletRequest request , HttpServletResponse response ) throws ServletException , IOException
{
String contextPath = request.getContextPath();
String servletName = getServletName();
servletURL = contextPath + "/" + servletName;
String sessionToken;
response.setContentType( "text/html" ); // MIME type
PrintWriter servletresponse = null;
try
{
servletresponse = response.getWriter();
}catch( Exception e )
{
System.err.println( "Unable to create a PrintWriter" );
e.printStackTrace();
System.exit( 1 );
}
HttpSession session = request.getSession( true );
servletresponse.println( getXHTMLHeader( "UploadSSL" ) );
servletresponse.println( "<body>" );
String currentToken = "";
if( session != null )
{
currentToken = (String) session.getAttribute( "sessionToken" );
}
String logout = request.getParameter( PARAMLOGOUTBUTTON );
if( logout != null && !logout.isEmpty() && logout.equals( PARAMLOGOUTBUTTON ) )
{
logout = "";
writeToLog( logoutCurrentUser( request , session , currentToken ) );
}
if( !authorizedTokens.contains( currentToken ) ) // validate start a session, accidentally keeping an extra token from login?
{
String userPassword = request.getParameter( PARAMLOGINUSERPASSWORD );
if( loginPassword.isValid( userPassword ) )
{
userPassword = ""; // use the session, not the password
session.setMaxInactiveInterval( 5 * 60 ); // 5 * 60 seconds = 5 minutes
sessionToken = UUID.randomUUID().toString(); // SecureRandom based
session.setAttribute( "sessionToken" , sessionToken );
authorizedTokens.add( sessionToken );
session = changeSessionIdentifier( request ); // security measure against session hijacking
currentToken = (String) session.getAttribute( "sessionToken" );
writeToLog( getUTCTimestamp() + " UTC Login successful: " + session.getId() + " , " + currentToken );
loginPassword = new Password( 8 );
writeToLog( "One time use login password: " + loginPassword.get() );
}else
{
servletresponse.println( getLoginForm() );
}
}
if( authorizedTokens.contains( currentToken ) ) // resume a session
{
// BEGIN APPLICATION SPECIFIC LOGIC HERE
displayInputForm( request , servletresponse );
String saving = request.getParameter( "input" );
if( saving != null && !saving.isEmpty() && saving.equals( "save" ) )
{
saveSSLInput( request , servletresponse );
displaySSLStatus( servletresponse );
servletresponse.println( "<br /> <br />" + getUTCTimestamp() + " UTC Settings saved <br />" );
System.out.println( getUTCTimestamp() + " UTC Configuration saved" ); // tomcat6 writes to catalina.out
}
// END APPLICATION SPECIFIC LOGIC
servletresponse.println( "<br />" );
servletresponse.println( getLogoutForm() );
}
servletresponse.println( "</body></html>" );
servletresponse.close();
} // end doGet()
// BEGIN APPLICATION SPECIFIC METHODS
// this method is ugly =( , needs refactoring
private void saveSSLInput( HttpServletRequest request , PrintWriter out )
{
String userInput = request.getParameter( "userinput" ); // defined in displayInputForm
String targetFile = request.getParameter( "targetfile" ); // defined in displayInputForm
if( userInput != null && !userInput.isEmpty() && targetFile != null && !targetFile.isEmpty() )
{
if( targetFile.equals( "write-cert.crt" ) || targetFile.equals( "write-intermediate.crt" ) || targetFile.equals( "write-cert.key" ) )
{
out.println( "<pre>" + targetFile + "</pre> " );
out.println( "<pre>" + userInput + "</pre> " );
}
}
if( targetFile.equals( "write-cert.crt" ) )
{
SSLCertificate cert = new SSLCertificate( userInput );
if( cert.isValid() )
{
try
{
cert.writeToFile( SSLLOCATION + SSLCERTIFICATEFILENAME );
}catch( IOException ioe )
{
out.println( ioe.getMessage() + "<br />" );
System.out.println( ioe.getMessage() );
}
}else
{
out.println( "ERROR: Input is not a valid PEM format SSL certificate" );
System.out.println( "ERROR: Input is not a valid PEM format SSL certificate" );
}
}else if( targetFile.equals( "write-intermediate.crt" ) )
{
SSLCertificate intermediate = new SSLCertificate( userInput );
if( intermediate.isValid() )
{
try
{
intermediate.writeToFile( SSLLOCATION + SSLINTERMEDIATEFILENAME );
}catch( IOException ioe )
{
out.println( ioe.getMessage() + "<br />" );
System.out.println( ioe.getMessage() );
}
}else
{
out.println( "ERROR: Input is not a valid PEM format SSL certificate" );
System.out.println( "ERROR: Input is not a valid PEM format SSL certificate" );
}
}else if( targetFile.equals( "write-cert.key" ) )
{
SSLKey sslkey = new SSLKey( userInput );
try
{
sslkey.writeToFile( SSLLOCATION + SSLKEYFILENAME );
}catch( IOException ioe )
{
out.println( ioe.getMessage() + "<br />" );
System.out.println( ioe.getMessage() );
}
}else
{
out.println( "Error: invalid option selected" );
}
targetFile = null;
}
private void displaySSLStatus( PrintWriter out )
{
try
{
SSLUtility openssl = new SSLUtility();
if( openssl.isCertificateAndKeyValid( SSLLOCATION + SSLCERTIFICATEFILENAME , SSLLOCATION + SSLKEYFILENAME ) )
{
out.println( "SUCCESS: Current SSL Certificate and Key match <br />" );
}else
{
out.println( "ERROR: Current SSL Certificate and Key do not match <br />" );
}
out.println( "Certificate and Intermediate Check Result... <br />" );
String intermediateCheckResult = openssl.isCertificateAndIntermediateValid( SSLLOCATION + SSLCERTIFICATEFILENAME , SSLLOCATION + SSLINTERMEDIATEFILENAME );
out.println( intermediateCheckResult );
}catch( IOException ioe )
{
out.println( ioe.getMessage() );
}
}
private void displayInputForm( HttpServletRequest request , PrintWriter out )
{
String contextPath = request.getContextPath();
String servletName = getServletName();
String submitTarget = contextPath + "/" + servletName;
out.println( "<br />" );
out.println( "<form id='upload' action='" + submitTarget + "' method=\"post\" >" );
out.println( "<label><input type='radio' name='targetfile' value='write-cert.crt' /> Upload cert.crt </label>" );
out.println( "<label><input type='radio' name='targetfile' value='write-intermediate.crt' /> Upload intermediate.crt </label>" );
out.println( "<label><input type='radio' name='targetfile' value='write-cert.key' /> Upload cert.key </label>" );
out.println( "<br /><br />" );
out.println( "<textarea name='userinput' rows='10' cols='80'>Delete this and Paste your SSL Certificate or SSL Key</textarea>" );
out.println( "<br /><br />" );
out.println( "<div><input type='submit' name='input' value='save'/></div>" );
out.println( "</form>" );
out.println( "<script type='text/javascript'> document.forms[ 'upload' ].elements[ 'userinput' ].focus(); </script>" );
}
// END APPLICATION SPECIFIC METHODS
// GENERIC HELPER METHODS
private HttpSession changeSessionIdentifier( HttpServletRequest request )
{
HttpSession session = request.getSession();
HashMap <String , Object> attributes = new HashMap <String , Object>();
@SuppressWarnings( "unchecked" )
Enumeration <String> attributeNames = (Enumeration <String>) session.getAttributeNames();
while( attributeNames != null && attributeNames.hasMoreElements() )
{
String name = attributeNames.nextElement();
Object value = session.getAttribute( name );
attributes.put( name , value );
}
session.invalidate();
HttpSession newSession = request.getSession();
Set <Map.Entry <String , Object>> attributeValues = attributes.entrySet();
Iterator <Map.Entry <String , Object>> it = attributeValues.iterator(); // copy back the session content
while( it.hasNext() )
{
Map.Entry <String , Object> entry = it.next();
newSession.setAttribute( (String) entry.getKey() , entry.getValue() );
}
return newSession;
}
private String getUTCTimestamp()
{
long currentTimeMilliseconds = System.currentTimeMillis();
Date now = new Date( currentTimeMilliseconds );
SimpleDateFormat utcFormat = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );
utcFormat.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
return utcFormat.format( now );
}
private void writeToLog( String content )
{
System.out.println( content ); // tomcat defaults to catalina.out
}
// side effect to the session?
private String logoutCurrentUser( HttpServletRequest request , HttpSession session , String currentToken )
{
StringBuilder strb = new StringBuilder();
if( session != null )
{
while( authorizedTokens.contains( currentToken ) )
{
authorizedTokens.remove( currentToken );
}
if( request.isRequestedSessionIdValid() == true )
{
strb.append( getUTCTimestamp() + " UTC " + session.getId() + " , " + currentToken + " Logged out." );
session.invalidate();
}else
{
strb.append( "Logged out. Session is invalidated." );
}
}
return strb.toString();
}
private static String getLogoutForm()
{
StringBuilder strb = new StringBuilder();
String newline = System.getProperty( "line.separator" );
strb.append( "<form " + LOGOUTFORMSTYLE + " id='" + PARAMLOGOUTBUTTON + "' action='" + servletURL + "' method='post' >" + newline );
strb.append( "<div><input type='submit' name='" + PARAMLOGOUTBUTTON + "' value='" + PARAMLOGOUTBUTTON + "' /></div>" + newline );
strb.append( "</form>" + newline );
return strb.toString();
}
private static String getLoginForm()
{
StringBuilder strb = new StringBuilder();
String newline = System.getProperty( "line.separator" );
strb.append( "<form " + FORMSTYLE + " id='" + PARAMLOGINBUTTON + "' action='" + servletURL + "' method='post' >" + newline );
strb.append( "Password: <input type='password' name='" + PARAMLOGINUSERPASSWORD + "' id='" + PARAMLOGINUSERPASSWORD + "' /> <br /><br />" + newline );
strb.append( "<span><input type='submit' name='" + PARAMLOGINBUTTON + "' value='" + PARAMLOGINBUTTON + "'/></span>" + newline );
strb.append( "</form>" + newline );
// strb.append( "<script type='text/javascript'> document.forms[ '"+ PARAMLOGINBUTTON + "' ].elements[ '" + PARAMLOGINUSERPASSWORD +
// "' ].focus(); </script>" + newline );
strb.append( "<script type='text/javascript'> document.getElementById( '" + PARAMLOGINUSERPASSWORD + "' ).focus(); </script>" );
return strb.toString();
}
private static String getXHTMLHeader( String title )
{
StringBuilder strb = new StringBuilder();
String newline = System.getProperty( "line.separator" );
strb.append( "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">" + newline );
strb.append( "<html xmlns=\"http://www.w3.org/1999/xhtml\">" + newline );
strb.append( "<head><title>" + title + "</title>" + newline );
strb.append( "<meta http-equiv='Content-Type' content='text/html;charset=utf-8' />" + newline );
strb.append( "<link type='text/css' rel='stylesheet' href='css/style.css' />" + newline );
// strb.append( "<script type='text/javascript' src='" + contextPath +
// "/javascript.js'></script> + newline " );
strb.append( "</head>" + newline );
return strb.toString();
}
protected void doPost( HttpServletRequest request , HttpServletResponse response ) throws ServletException , IOException
{
doGet( request , response );
}
} // end class