Il programma HTTPsServer è molto simile al precedente HTTPServer, fatta eccezzione per il fatto che risulta in grado di instaurare, con il Browser Client, una connessione sicura secondo il protocollo SSL v.3 .
HTTPsServer.java:
import java.net.*;
import java.io.*;
import java.util.*;
import java.lang.*;
import java.util.*;
import java.security.*;
import java.security.cert.X509Certificate;
import iaik.security.ssl.*;
import iaik.asn1.structures.Name;
import com.entrust.security.provider.*;
import com.entrust.toolkit.*;
import com.entrust.util.*;
import com.entrust.x509.directory.*;
public class HTTPsServer {
static final String NAME = "HTTPsServer";
static final String VERSION = "1.0";
ServerSConfiguration configs = new ServerSConfiguration();
LoggerS loggers = new LoggerS();
/* MAIN */
// Crea un istanza di HTTPServer e richiama il metodo Run della stessa
public static void main(String args[]) {
HTTPsServer server = new HTTPsServer();
if(args.length > 0) server.processCommandLine(args);
server.run();
}
public HTTPsServer() {
super();
}
// Valutazione dei parametri passati nella linea di comando
public void processCommandLine(String[] args) {
for(int i=0;i < args.length;++i) {
if(args[i].equals("-CONFIG")) {
if(i+1 < args.length)
configs.processConfigurationFile(args[i+1]);
else System.out.println("Configuration file argument is missing.");
break;
}
}
String logFile = configs.getLogFile();
if(logFile!="") loggers = new LoggerS(logFile,configs.echoToConsole());
}
/* Visualizzazione versione del Server */
public void displayVersionInfo(){
System.out.println("HTTPsServer version "+VERSION);
}
// Si inizializzano l'Entrust Toolkit e il JCE,
// si controlla attraverso l'Entrust Manager se il proprio certificato è ancora valido e in
// caso affermativo si effettua il logon, si impostano gli algoritmi crittografici e le chiavi
// dopo di che si crea un nuovo ServerSocket, si assegna il socket alla variabile server, // si esegue un ciclo infinito nel quale si rimane in attesa dell'arrivo di una connessione,// si crea un'istanza socket per gestirla
public void run() {
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
displayVersionInfo(); // Versione del Server
configs.display();// Caratteristiche del Server
// Inizializzazione ciphers.
com.entrust.util.Util.initCiphers();
EntrustProfile entrustProfile = new EntrustProfile();
entrustProfile.setPKIXVersion(EntrustProfile.PKIXforEntrust3);
try {
String filename="WebAndrea.epf";
String password="SnorkMuffin";
entrustProfile.logon( new FileInputStream(filename), new StringBuffer(password));
if ( entrustProfile.randomSeedRequired() ) {
System.out.println( "The profile " + filename + " requires a valid random seed.\nUse the ProfileRandomSeed program to add a seed to your profile." );
System.exit( 1 );
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("Logon failed.");
}
System.out.println("EntrustProfile done.");
SSLServerContext sslServerContext = new SSLServerContext();
// Si accettano solo questi ciphers forti
CipherSuite [] suites = {
CipherSuite.SSL_RSA_WITH_3DES_EDE_CBC_SHA,
CipherSuite.SSL_RSA_WITH_RC4_SHA,
CipherSuite.SSL_RSA_WITH_RC4_MD5
};
sslServerContext.setEnabledCipherSuites( suites );
try {
System.out.println("Enter the IP address of the directory: ");
String addressDir = stdIn.readLine();
JNDIDirectory directory = new JNDIDirectory( addressDir, 389);
directory.connect();
ETKCertificateVerifier verifier =
new ETKCertificateVerifier( directory, entrustProfile );
sslServerContext.setTrustDecider(verifier);
} catch (Exception ex) {
ex.printStackTrace();
}
System.out.println("ETKCertificateVerifier done.");
try {
// Set up del certificato RSA.
X509Certificate[] certchain=new X509Certificate[2];
certchain[0]= entrustProfile.getEncryptionCertificate();
certchain[1]= entrustProfile.getCaCertificate();
sslServerContext.setRSACertificate(certchain,entrustProfile.getDecryptionKey());
// Si genera un coppia di chiavi RSA temporanea.
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(512,Util.secureRandom());
sslServerContext.setRSATempKeyPair(kpg.generateKeyPair());
// Si abilitano le suite cipher valide.
CipherSuite[] enabledCS = serverContext.updateCipherSuites();
} catch (Exception ex) {
System.out.println("Unable to set RSA server certificate.");
System.out.println("RSA cipher-suites can not be used.");
}
byte[] types = { ClientTrustDecider.rsa_sign, };
Name[] cas=null;
cas = new Name[1];
cas[0]=Util.getSubject(entrustProfile.getCaCertificate());
sslServerContext.setRequireClientCertificate(types,cas);
try {
SSLServerSocket server = new SSLServerSocket(configs.getServerPort(), sslServerContext);
SSLSocket clients = null;
int localPort = server.getLocalPort();
loggers.datedLog(NAME+" is listening on port "+localPort+".");
do {
// Si attende la connesione di un client
clients = (SSLSocket) server.accept();
// Ricevuta la richiesta si apre per il servizio un nuovo ServerThread che estende la classe Thread
(new HTTPsServerThread(clients,configs,loggers)).start();
} while(true);
} catch(IOException ex) {
loggers.datedLog("Unable to listen on "+configs.getServerPort()+".");
System.exit(0);
}
}
}
class HTTPsServerThread extends Thread {
SSLSocket clients;
ServerSConfiguration configs;
LoggerS loggers;
public HTTPsServerThread(SSLSocket clients,ServerSConfiguration configs, LoggerS loggers) {
this.clients = (SSLSocket) clients;
this.configs = configs;
this.loggers = loggers;
}
// Corpo del Thread
public void run() {
try {
// Descrive il tipo di connessione instaurato con il cliente
describeConnection(clients);
// Si creano oggetti delle classi HTTPOutputStream e HTTPInputStream per comunicare col Client. I flussi sono memorizzati in buffer per mogliorare le prestazioni di I/O
HTTPsOutputStream outStream = new HTTPsOutputStream(new BufferedOutputStream(clients.getOutputStream()));
HTTPsInputStream inStream = new HTTPsInputStream(clients.getInputStream());
// Cattura le richieste HTTP di input
HTTPsRequest request = inStream.getRequest();
request.logs(loggers);
if(request.isGetRequest()) {
String response = request.prepareResponse();
String ext = request.getExtName((ServerSConfiguration) configs);
// Se il file trasmesso è un archivio ".jar", comunica al Browser di non trattenerlo poiché nella Cache ha validità per 0 sec.
if (ext.equals("jar")) response +="Expire : 0 \n";
outStream.println(response);
outStream.println();
loggers.datedLog("Send msg: "+ response);
processGetRequest(request,outStream);
}
loggers.datedLog("Request completed. Closing connection.");
}catch(IOException ex) {
loggers.datedLog("IOException occured when processing request.");
}
try {
clients.close();
}catch(IOException ex) {
loggers.datedLog("IOException occured when closing SSLSocket.");
}
}
void describeConnection(SSLSocket clients) {
String destName = clients.getInetAddress().getHostName();
String destAddr = clients.getInetAddress().getHostAddress();
int destPort = clients.getPort();
loggers.datedLog("Accepted connection to "+destName+" ("
+destAddr+")"+" on port "+destPort+".");
}
void processGetRequest(HTTPsRequest request,HTTPsOutputStream outStream) throws IOException {
String fileName = request.getFileName(configs);
File file = new File(fileName);
if(file.exists()) {
String fullPath = file.getCanonicalPath();
if(inServerRoot(fullPath)) {
int len = (int) file.length();
sendFile(outStream,file);
}else loggers.datedLog("File is not in server root.");
}else loggers.datedLog("File "+file.getCanonicalPath()+" does not exist.");
}
public boolean inServerRoot(String fileName) {
String serverRoot = configs.getServerRoot();
int fileLength = fileName.length();
int rootLength = serverRoot.length();
if(fileLength < rootLength) return false;
if(serverRoot.equals(fileName.substring(0,rootLength))) return true;
return false;
}
void sendFile(HTTPsOutputStream out,File file) {
try {
DataInputStream in = new DataInputStream(new FileInputStream(file));
int len = (int) file.length();
byte buffer[] = new byte[len];
in.readFully(buffer);
in.close();
for(int i=0;i < len;++i) out.write(buffer[i]);
out.flush();
out.close();
loggers.datedLog("File sent: "+file.getCanonicalPath());
loggers.logs("Number of bytes: "+len);
}catch(Exception ex) {
loggers.datedLog("Error retrieving "+file);
}
}
}
class HTTPsInputStream extends FilterInputStream {
public HTTPsInputStream(InputStream in) {
super(in);
}
public String readLine() throws IOException {
StringBuffer result=new StringBuffer();
boolean finished = false;
boolean cr = false;
do {
int ch = -1;
ch = read();
if(ch==-1) return result.toString();
result.append((char) ch);
if(cr && ch==10){
result.setLength(result.length()-2);
return result.toString();
}
if(ch==13) cr = true;
else cr=false;
} while (!finished);
return result.toString();
}
public HTTPsRequest getRequest() throws IOException {
HTTPsRequest request = new HTTPsRequest();
String line;
do {
line = readLine();
if(line.length() > 0) request.addLine(line);
else break;
}while(true);
return request;
}
}
class HTTPsOutputStream extends FilterOutputStream {
public HTTPsOutputStream(OutputStream out) {
super(out);
}
public void println() throws IOException {
write(13);
write(10);
}
public void println(String s) throws IOException {
for(int i=0;i < s.length();++i) write(s.charAt(i));
println();
}
}
class HTTPsRequest {
Vector lines = new Vector();
public HTTPsRequest() {
}
public void addLine(String line) {
lines.addElement(line);
}
boolean isGetRequest() {
if(lines.size() > 0) {
String firstLine = (String) lines.elementAt(0);
if(firstLine.length() > 0)
if(firstLine.substring(0,3).equalsIgnoreCase("GET"))
return true;
}
return false;
}
String getFileName(ServerSConfiguration configs) {
if(lines.size() > 0) {
String firstLine = (String) lines.elementAt(0);
String fileName = firstLine.substring(firstLine.indexOf(" ")+1);
int n = fileName.indexOf(" ");
if(n!=-1) fileName = fileName.substring(0,n);
try {
if(fileName.charAt(0) == '/') fileName = fileName.substring(1);
} catch(StringIndexOutOfBoundsException ex) {}
if(fileName.equals("")) fileName = configs.getDefaultFile();
if(fileName.charAt(fileName.length()-1)=='/')
fileName+=configs.getDefaultFile();
return configs.getServerRoot()+fileName;
}else return "";
}
String getExtName(ServerSConfiguration configs) {
if(lines.size() > 0) {
String firstLine = (String) lines.elementAt(0);
String extName = firstLine.substring(firstLine.indexOf(" ")+1);
int n = extName.indexOf(" ");
if(n!=-1) extName = extName.substring(0,n);
try {
if(extName.charAt(0) == '/') extName = extName.substring(1);
} catch(StringIndexOutOfBoundsException ex) {}
if(extName.equals("")) extName = configs.getDefaultFile();
if(extName.charAt(extName.length()-1)=='/')
extName+=configs.getDefaultFile();
n = extName.indexOf(".")+1;
extName = extName.substring(n,extName.length());
return extName;
}else return "";
}
String prepareResponse() {
String lineOut="HTTP/";
for (int i=0;i < lines.size();++i) {
if (i==0) {
String line = (String) lines.elementAt(0);
int n = line.indexOf("1");
line=line.substring(n,line.length());
lineOut+=line;
}
}
// Ritorna lo Stato del Server
lineOut+=" 200 \n";
// Ritorna di altri eventuali parametri
lineOut+="Cache-Control : no-cache \n";
lineOut+="Cache-Control : private \n";
return lineOut;
}
void logs(LoggerS loggers) {
loggers.datedLog("Received the following request:");
for(int i=0;i < lines.size();++i)
loggers.logs((String) lines.elementAt(i));
}
}
// Questa classe si occupa della configurazione del Server Web
class ServerSConfiguration {
static final char CONFIG_COMMENT_CHAR = '#';
int serverPort = 443;
String serverRoot = "C:\\Inetpub\\WwwRoot\\";
String defaultFile = "Default.html";
String logFile = "";
boolean echoLogToConsole = true;
public ServerSConfiguration() {
}
public char getCommentChar() {
return CONFIG_COMMENT_CHAR;
}
public int getServerPort() {
return serverPort;
}
public String getServerRoot() {
return serverRoot;
}
public String getDefaultFile() {
return defaultFile;
}
public String getLogFile() {
return logFile;
}
public boolean echoToConsole() {
return echoLogToConsole;
}
public void display() {
System.out.println(" serverPort: "+serverPort);
System.out.println(" serverRoot: "+serverRoot);
System.out.println(" defaultFile: "+defaultFile);
System.out.println(" logFile: "+logFile);
System.out.println(" echoLogToConsole: "+echoLogToConsole);
}
public void processConfigurationFile(String fname) {
try {
File file = new File(fname);
if(file.exists()) {
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
while((line=reader.readLine())!=null)
processConfigurationLine(line);
reader.close();
}
}catch(Exception ex) {
System.out.println("Unable to process configuration file.");
}
}
public void processConfigurationLine(String line) throws NumberFormatException {
line = removeLeadingWhiteSpace(line);
if(line.length()==0) return;
int n;
int n1 = line.indexOf(' ');
int n2 = line.indexOf('\t');
if(n1 == -1) n = n2;
else if(n2 == -1) n = n1;
else if(n1 < n2) n = n1;
else n = n2;
if(n==-1 || n==line.length()-1) return;
String param = line.substring(0,n);
String value = line.substring(n+1);
if(param.equals("serverPort"))
serverPort = (new Integer(value)).intValue();
else if(param.equals("serverRoot")){
serverRoot = value;
if(!serverRoot.equals("")){
char ch = serverRoot.charAt(serverRoot.length()-1);
if(ch!='/' && ch!='\\') serverRoot+="/";
}
}else if(param.equals("defaultFile"))
defaultFile = value;
else if(param.equals("logFile"))
logFile = value;
else if(param.equals("echoLogToConsole"))
echoLogToConsole = (new Boolean(value)).booleanValue();
}
String removeLeadingWhiteSpace(String line) {
boolean finished = false;
do {
if(line.length()==0) return "";
char ch = line.charAt(0);
if(ch==CONFIG_COMMENT_CHAR) return "";
if(ch!=' ' && ch!='\t') return line;
line=line.substring(1);
} while (!finished);
return "";
}
}
// Questa classe si occupa della registrazione delle operazioni effettuate.
// La registrazione può essere effettuata su console o su file.
class LoggerS {
public String logFile;
public boolean echoLogToConsole = true;
public BufferedWriter writer = null;
public LoggerS() {
}
public LoggerS(String fname, boolean echo) {
logFile = fname;
echoLogToConsole = echo;
try {
writer = new BufferedWriter(new FileWriter(fname,true));
}catch(IOException ex){}
}
void logMsg(String msg) {
if(writer!=null) {
try {
writer.write(msg);
writer.newLine();
writer.flush();
}catch(IOException ex){}
}
if(echoLogToConsole) System.out.println(msg);
}
public synchronized void logs(String msg) {
logMsg(" "+msg);
}
public synchronized void datedLog(String msg) {
logMsg((new Date()).toString()+" "+msg);
}
}
|