Indice
Autores
Esta práctica ha sido realizada por el grupo 4 de prácticas.
Tanto la programación como la documentación de la práctica han sido realizadas por Guillem Rull Fort y Jose María Rodríguez Valls.
Introducción
En esta sesión veremos los diferentes tipos de conexión segura. Tendremos que realizar un servidor HTTP con capacidad para conectarse en una conexión segura mediante SSL y encriptación en base64.
La práctica está íntegramente realizada en Java por lo que será necesario entender el funcionamiento con los ejemplos y documentación facilitados.
Entorno
Dispondremos de un compilador JDK.
Será necesario entender el comportamiento de la encriptación base64 para poder decodificar el usuario y password del cliente.
Si el usuario y password son correctos serviremos el archivo solicitado al cliente.
Toda la práctica esta íntegramente implementada en java.
Implementación
Ahora veremos el archivo HTTPServer que será el servidor encargado de verificar la autentificación por parte del cliente.
Hemos añadido una función encargada de verificar la autentificación por parte del cliente. Esta función nos retornará un booleano que nos indicará si podemos enviar el archivo al cliente o por otro lado si debemos pedir una autentificación.
La classe SecureServer.java no ha sido necesario modificarla.
HTTPServer.java
import java.net.*;
import java.io.*;
import java.util.*;
public class HTTPServer {
String NAME;
String VERSION;
int serverPort;
//Iniciamos el servidor por el puerto 8000.
public static void main(String args[]){
HTTPServer server = new HTTPServer("HTTPServer", "1.0", 8000);
server.run();
}
public HTTPServer(String name, String version, int port) {
this.NAME = name;
this.VERSION = version;
this.serverPort = port;
}
public void displayVersionInfo(){
System.out.println(NAME+" version "+VERSION);
}
//Arrancamos el servicio...
public void run() {
displayVersionInfo();
try { //Leemos del socket...
ServerSocket server = getServerSocket();
int localPort = server.getLocalPort();
System.out.println(NAME+" is listening on port "+localPort+".");
do {
Socket client = server.accept();
(new HTTPServerThread(client)).start();
} while(true);
} catch(Exception ex) {
System.out.println("Unable to listen on "+serverPort+".");
ex.printStackTrace();
System.exit(1);
}
}
ServerSocket getServerSocket() throws Exception {
return new ServerSocket(serverPort);
}
}
//Clase encargada de atender las solicitudes del cliente...
class HTTPServerThread extends Thread {
Socket client;
public HTTPServerThread(Socket client) {
this.client = client;
}
public void run() {
try {
describeConnection(client);
BufferedOutputStream outStream = new
BufferedOutputStream(client.getOutputStream());
HTTPInputStream inStream = new HTTPInputStream(client.getInputStream());
HTTPRequest request = inStream.getRequest();
request.log();
if(request.isGetRequest())
processGetRequest(request,outStream, inStream);
System.out.println("Request completed. Closing connection.");
}catch(IOException ex) {
System.out.println("IOException occurred when processing request.");
}
try {
client.close();
}catch(IOException ex) {
System.out.println("IOException occurred when closing socket.");
}
}
void describeConnection(Socket client) {
String destName = client.getInetAddress().getHostName();
String destAddr = client.getInetAddress().getHostAddress();
int destPort = client.getPort();
System.out.println("Accepted connection to "+destName+" ("
+destAddr+")"+" on port "+destPort+".");
}
void processGetRequest(HTTPRequest request,BufferedOutputStream outStream, HTTPInputStream inStream)
throws IOException {
String fileName = request.getFileName();
File file = new File(fileName);
if(file.exists()) sendFile(request, outStream, inStream,file);
else System.out.println("File "+file.getCanonicalPath()+" does not exist.");
}
//Envia el fichero al usuario...
void sendFile(HTTPRequest req, BufferedOutputStream out, HTTPInputStream inStream,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();
//Compruebo si es un cliente autentificado...
if (req.isUser()) {
out.write("HTTP/1.0 200 OK\r\n".getBytes());
out.write(("Content-Length: " + buffer.length + "\r\n").getBytes());
out.write("Content-Type: text/html\r\n\r\n".getBytes());
out.write(buffer);
} else { //Pido que se autentifique...
out.write("HTTP/1.1 401 Unauthorized\r\n".getBytes());
out.write("WWW-Authenticate: Basic realm= WallyWorld\r\n\r\n".getBytes());
}
out.flush();
out.close();
}catch(Exception ex){
try {
out.write(("HTTP/1.0 400 " + "No can do" + "\r\n").getBytes());
out.write("Content-Type: text/html\r\n\r\n".getBytes());
}catch(IOException ioe) {
}
System.out.println("Error retrieving "+file);
}
}
}
class HTTPInputStream extends FilterInputStream {
public HTTPInputStream(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 HTTPRequest getRequest() throws IOException {
HTTPRequest request = new HTTPRequest();
String line;
do {
line = readLine();
if(line.length()>0) request.addLine(line);
else break;
}while(true);
return request;
}
}
class HTTPRequest {
Vector lines = new Vector();
public HTTPRequest() {
}
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() {
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 = "index.htm";
if(fileName.charAt(fileName.length()-1)=='/')
fileName+="index.htm";
return fileName;
}else return "";
}
void log() {
System.out.println("Received the following request:");
for(int i=0;i<lines.size();++i)
System.out.println((String) lines.elementAt(i));
}
//Declaramos el usuario y password del cliente...
static final String USER = "pxc";
static final String PSW = "abc";
//Funcion que determina si el usuario y password son correctos...
boolean isUser() {
System.out.println("Respuesta cliente:");
for(int i = 0; i < lines.size(); i++)
{
System.out.println((String)lines.elementAt(i));
String line = (String) lines.elementAt(i);
String str[] = line.split(" ");
if (str[0].equals("Authorization:")) {
String id = Base64.decodeToString(str[2]);
String userpw[] = id.split(":");
if (userpw[0].equals(USER) && userpw[1].equals(PSW))
return true;
else
return false;
}
}
return false;
}
}
Resultados
Hemos conseguido que toda la práctica funcione con completa normalidad.
Es necesario que dispongamos de un puerto abierto para poder abrir el socket del servidor.
SSL
El protocolo SSL surgió como una necesidad de enviar datos de un modo seguro. Actualmente es el protocolo más utilizado en los momentos de transferencia de datos sensibles. Tales como números de tarjetas de crédito, datos personales, etc...
Lo normal es usar SSL con certificados por parte del servidor para demostrar la seguridad del sitio.
Ventajas de usar SSL
- Permiten enviar datos de una manera más segura.
- Aumenta la confianza de los usuarios en páginas seguras.
Inconvenientes de usar SSL
- Es más engorroso trabajar con datos encriptados.
- Es más complicado configurar los servidores.
- Normalmente los certificados son costosos.
Conclusiones
Hemos leído la documentación de esta sesión. Apartir de hay, hemos compilado los ejemplos que nos venían con la práctica.
Al entender completamente su funcionamiento hemos empezado a estructurar las modificaciones pertinentes para conseguir realizar un servidor HTTP con conexiones seguras.
Posteriormente solo nos quedaba realizar algunas pruebas de conexión por parte del cliente.
En principio al ver que funcionaba con normalidad solo nos quedaba realizar la documentación pertinente.