jueves, 26 de marzo de 2009
Trabajar con Certificados SSL en Java
Cuando desarrollamos una aplicación en Java que va ha hacer uso de un recurso seguro (mediante un certificado), debemos asegurarnos que este certificado podrá ser validado por una entidad certificadora que reconozca Java. Debido a que Java es un lenguaje multi-plataforma, no utiliza la información de certificados alojada en el Sistema Operativo.
Por defecto, la máquina virtual de Java dispone de las Entidades Certificadoras (CA) más comunes, como Verisign o Thawte. Sin embargo, suele darse el caso, sobretodo en entornos de desarrollo, que necesitemos utilizar una Entidad Certificadora "de prueba". En este caso, debemos importar esta CA en el almacén de claves de la máquina virtual que estemos utilizando.
Importar Certificado en el almacén de certificados (keystore)
La máquina virtual de Java (JVM) cuenta con un almacén de claves (keystore) que incorpora las entidades más habituales y la posibilidad de agregar aquellas que nos sean necesarias. El keystore se encuentra en la ruta: JVM_PATH\lib\security\cacerts. Por ejemplo:
C:\Archivos de programa\Java\jre1.6.0_05\lib\security\cacerts
C:\Archivos de programa\Java\jdk1.5.0_15\jre\lib\security
Para añadir una nueva entidad certificadora a la JVM que estemos utilizando, debemos utilizar el comando keytool (JVM_PATH\bin\keytool):
keytool -import -keystore "C:\Archivos de
programa\Java\jre1.6.0_05\lib\security\cacerts" -file
c:\NuevaEntidadCertificadora.cer -alias CA_SwitchOffAndLetsGo -storepass
changeit
Puede observarse que el almacén de certificados contiene la contraseña por defecto 'changeit'. El nombre que especifiquemos en el alias, debe ser único en el keystore y servirá de referencia futura en el almacén. Podemos listar los certificados instalados utilizando la opción list del keytool:
keytool -list -keystore "C:\Archivos de
programa\Java\jre1.6.0_05\lib\security\cacerts" -storepass changeit
Importar Certificado utilizando el panel de control de Java (Windows)
Atención: con esta opción únicamente se añadirán los certificados a la instalación activa de la JVM en Windows.
Para añadir la nueva entidad, se accederá al Panel de Control de Windows, y se seleccionará la opción "Java". Seguidamente se marcará la pestaña "Seguridad" y se pulsará sobre el botón "Certificados".
En el apartado de Certificados, se seleccionará la opción "Importar" y se localizará el archivo que contiene el certificado (si el certificado tiene extensión .cer se tendrá que seleccionar la opción 'Todos los archivos'). El nuevo certificado aparecerá en la pestaña "Usuario".
miércoles, 11 de febrero de 2009
Como hacer la descarga de ficheros con servlets
response.setContentType("text/html");
Pero el contenido de la respuesta lo podemos cambiar a cualquier otro Mime type:
http://www.webmaster-toolkit.com/mime-types.shtml
Según esto podemos hacer que nuestro servlet devuelva cualquier tipo de fichero.
En el siguiente ejemplo escribo un servlet capaz de enviarnos un fichero zip de cualquier parte del disco del servidor. (Nota. esto hay que manejarlo con cuidado porque puede producir un hueco de seguridad gordisimo)
package org.company.servlet.readfile;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
import java.net.*;
/**
*
This class handles Streaming Data Content
**/
public class Readfile extends HttpServlet {
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
/*
* This Method Handles Post
*
* @param HttpServletRequest request
* @param HttpServletResponse response
*/
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
/*
* This Method Handles Get
*
* @param HttpServletRequest request
* @param HttpServletResponse response
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String urlstr = null;
UserBean user = (UserBean) request.getSession().getAttribute("user");
try {
response.reset();
urlstr = request.getParameter("filename");
ServletOutputStream sOutStream = response.getOutputStream();
streamBinaryData(user.getName(), urlstr, sOutStream, response);
} catch (Exception e) {
e.printStackTrace();
}
}
private void streamBinaryData(String username, String file, ServletOutputStream outstr, HttpServletResponse resp) throws IOException{
String ErrorStr = null;
try {
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
String inFile = "/midirectorio/" + file;
int tam = (int) new File(inFile).length();
bis = new BufferedInputStream(new FileInputStream(inFile));
try {
//Asignamos el tipo de fichero zip
resp.setContentType("application/x-zip-compressed"); //Cualquier mime type
//Seteamos el tamaño de la respuesta
resp.setContentLength(tam);
resp.setHeader("Content-Disposition", "attachment;filename=\"" + file + "\"");
bos = new BufferedOutputStream(outstr);
// Bucle para leer de un fichero y escribir en el otro.
byte[] array = new byte[1000];
int leidos = bis.read(array);
while (leidos > 0) {
bos.write(array, 0, leidos);
leidos = bis.read(array);
}
} catch (Exception e) {
e.printStackTrace();
ErrorStr = "Error Streaming the Data";
outstr.print(ErrorStr);
} finally {
if (bis != null) {
bis.close();
}
if (bos != null) {
bos.close();
}
if (outstr != null) {
outstr.flush();
outstr.close();
}
}
} catch (Exception e) {
System.out.println("Fichero no encontrado");
resp.sendRedirect("fileNotFound.jsp");
}
}
}
Con este servlet conseguimos que en el navegador aparezca la típica ventanita de "descargas" al hacer una llamada al servlet, que recibe como parámetro el nombre del fichero. Este es el motivo por el que debemos tener cuidado al usar esto ya que podríamos crear un hueco de seguridad y que el usuario final se pueda descargar cualquier fichero de nuestro servidor.
Lo mejor sería tener un directorio controlado del que sacar los ficheros como en el ejemplo, o que se filtre el filename de entrada para saber que está entre los permitidos, etc ...
Configurar la red manualmente en Ubuntu
Bueno pues este artículo intenta explicar como configurarla manualmente para que se quede permanente ya que desde el UI no lo he conseguido.
1 Paso:
> vi /etc/network/interfaces
El contenido debemos editarlo para que quede:
auto lo
iface lo inet loopback
iface eth0 inet static
address XXX.XXX.X.XXX
netmask 255.255.255.XXX
gateway XXX.XXX.X.XXX
nameserver XXX.XXX.X.XXX
domain midominio.es
auto eth0
Esta configuración especifica:
address -> dirección ip
netmask -> máscara de red
gateway -> la puerta de enlace, suele ser la dirección ip del rooter
nameserver -> (opcional) dirección ip del servidor de dns, puedes poner tantos como servidores dns tengas
domain -> para configurar el dominio de red en el que te encuentras
Nota. Esta configuración está hecha para una conexión cableada por eso usa eth0
Paso 2:
Aunque en este fichero podemos especificar los dns, lo suyo es especificarlos en el fichero
> vi /etc/resolv.conf
El contenido del fichero debería ser:
nameserver XXX.XXX.X.XXX
Nota. Tantos nameserver como servidores de dns tengamos.
Bueno pues con esto, tu configuración quedará permanetemente configurada, de hecho
si el NetworkManager (UI para la configuración de red de ubuntu) funcionara bien, en estos ficheros debe poner algo así como
# Generated by NetworkManager
Eso es todo.
lunes, 20 de octubre de 2008
JUnit 3.8.1 vs JUnit 4.x
Bueno pues JUnit es una herramienta que desde que se publicó su versión 3.8.1 ha quedado un poco congelada. Pero recientemente el proyecto a vuelto a cobrar vida con las nuevas versiones 4.x. Estas nuevas versión introducen algunos conceptos nuevos y hacen uso de las anotaciones introducidas en la versión 1.5 de java.
A continuación, se listan las principales novedades de esta versión de JUnit respecto a versiones precedentes:
- Es necesario utilizar la versión 5 de la JDK para ejecutar los tests.
- Las clases de prueba no necesitan heredar de la clase junit.framework.TestCase.
- Los métodos de inicialización y liberación pueden ser definidos con cualquier nombre siempre y cuando sean etiquetados adecuadamente con @Before y @After. Además puede existir más de un método de inicialización y liberación simultaneamente.
- Los nombre de los métodos de prueba no necesitan contener el prefijo test, sin embargo es necesario que sean definidos con la etiqueta @Test, la cual permite ser utilizada con parámetros que enriquecen las posibilidades de la prueba.
- Existe la posibilidad de declarar métodos de inicialización y liberación globales a la clase de pruebas mediante las etiquetas @BeforeClass y @AfterClass.
JUnit3.8.1
package pruebasSistemaSoftware.junit381;
import junit.framework.*;
import servidorEstadoTrafico.Registro;
import servidorEstadoTrafico.RegistroMalFormadoException;
import servidorEstadoTrafico.Tramo;
public class RegistroTest extends TestCase {
private Registro m_registro;
public void setUp(){
String strCarretera ="M-40";
String strHora="12:23:45";
String strFecha="1/3/2007";
String strClima="Nublado";
String strObras = "No";
m_registro = new Registro(strCarretera,strHora,strFecha,strClima,strObras);
Tramo tramo1 = new Tramo("0","10","3","1","Retenciones","Sin accidentes");
Tramo tramo2 = new Tramo("10","12","2","0","Retenciones","Sin accidentes");
Tramo tramo3 = new Tramo("12","15","3","1","Retenciones","Sin accidentes");
m_registro.anadirTramo(tramo1);
m_registro.anadirTramo(tramo2);
m_registro.anadirTramo(tramo3);
}
public void tearDown(){
}
public void testComprobarFormato(){
try{
m_registro.comporbarFormato();
} catch (RegistroMalFormadoException e){
fail("Se ha originado una excepcion inesperada" + e.toString());
}
}
public void testObtenerLongitud(){
assertEquals(m_registro.obtenerLongitud(),10+2+3);
}
JUnit 4.x
package pruebasSistemaSoftware.junit4.2;
import java.lang.*;
import java.util.*;
import org.junit.Test;
import org.junit.After;
import org.junit.Before;
import static org.junit.Assert.*;
import junit.framework.JUnit4TestAdapter;
import servidorEstadoTrafico.Registro;
import servidorEstadoTrafico.RegistroMalFormadoException;
import servidorEstadoTrafico.Tramo;
public class RegistroTest{
private Registro m_registro;
@Before public void inicializar(){
String strCarretera = "M-40";
String strHora="12:23:45";
String strFecha="1/3/2007";
String strClima="Nublado";
String strObras = "No";
m_registro = new Registro(strCarretera,strHora,strFecha,strClima,strObras);
Tramo tramo1 = new Tramo("0","10","3","1","Retenciones","Sin accidentes");
Tramo tramo2 = new Tramo("10","12","2","0","Retenciones","Sin accidentes");
Tramo tramo3 = new Tramo("12","15","3","1","Retenciones","Sin accidentes");
m_registro.anadirTramo(tramo1);
m_registro.anadirTramo(tramo2);
m_registro.anadirTramo(tramo3);
}
@After public void liberar(){
}
@Test(expected=RegistroMalFormadoException.class)
public void comprobarFormato() throws RegistroMalFormadoException {
m_registro.comprobarFormato();
}
@Test(timeout=1000)
public void obtenerLongitud(){
assertEquals(m_registro.obtenerLongitud(),10+2+3);
}
}
Ejemplos extraidos del libro "Pruebas de Software y JUnit Un análisis en profundidad y ejemplos prácticos"
Plantilla Ant
Bueno pues voy a poneros una plantilla que va a recoger todas estas tareas:
-Limpiar: Se eliminan los directorios que contienen las clases compiladas y la documentación que pudo ser generrada anteriormente. Se eliminan ambos a la vez para que no exista una versión de documentación que no se corresponda con las clases compiladas y viceversa.
-Compilar: En la primera de sus tareas se crea, si no existe, el directorio donde se guardarán las clases compiladas. El directorio no existirá porque se ha eliminado con el objetivo limpiar, del cual depende compilar. La segunda tarea compila las clases, situadas en ${src} y almacena los resultados de la compilación en el directorio ${build}. Para ello utiliza el classpath definido en la propiedad ${classpath}.
-Jar: Se genera un archivo .jar con todas las clases presentes een el directorio ${destino} (build). Esta tarea depende del objetivo compilar para garantizar que existan clases compiladas en este directorio antes de intentar generar el archivo .jar.
-Documentar: En la primera tarea se crea, si no existe, el directorio donde se guardará la documentación generada. El directorio no existirá porque se ha eliminado con el objetivo limpiar, del cual depende compilar. La segunda tarea genera la documentación del proyecto.
-Main: Se ejecutan todos los objetivos para crear el programa y dejarlo listo para ser ejecutado.
<project name="Proyecto_basico" default="main" basedir=".">
<!-- propiedades globales del proyecto -->
<!-- definición de directorios que se van a usar-->
<property name="src" value="."/>
<property name="build" value="build"/>
<property name="doc" value="doc"/>
<!-- caracteristicas del proyecto-->
<property name="classpath" value="./lib/misclases.jar"/>
<target name="limpiar">
<delete dir="$"/>
<delete dir="${doc}"/>
</target>
<target name="compilar" depends="limpiar">
<mkdir dir="${build}"/>
<javac srcdir="${src}" destdir="${build}" classpath="${classpath}"/>
</target>
<target name="jar" depends="compilar">
<jar jarfile="clases.jar" basedir="${build}" includes="**"/>
</target>
<target name="documentar" depends="limpiar">
<mkdir dir="${doc}"/>
<javadoc packagenames="proyectobasico" sourcepath="${src}" destdir="${doc}"/>
</target>
<target name="main" depends="compilar,documentar">
</target>
</project>
Bueno espero que os sirva para describir vuestros proyectos si en algún momento no recordáis la sintaxis de Ant.
jueves, 2 de octubre de 2008
Comprimir y descomprimir en Linux
Comprimir y descomprimir archivos en Linux desde la línea de comandos es algo habitual y siempre viene bien tener a mano un pequeño resumen de cómo hacerlo.
Los típicos
Ficheros .tar
tar empaqueta varios archivos en uno solo, pero no comprime.Instalar la herramienta: # emerge -n tar
Empaquetar: # tar cf archivo.tar ficheros
Desempaquetar: # tar -xvf archivo.tar
Ver contenido: # tar -tf archivo.tar
Ficheros .gz
gzip sólo comprime fichero a fichero, no empaqueta varios ficheros en uno ni comprime directorios.Instalar la herramienta: # emerge -n gzip
Comprimir: # gzip fichero
Descomprimir: # gzip -d fichero.gz
Ficheros .bz2
bzip2 sólo comprime fichero a fichero, no empaqueta varios ficheros en uno ni comprime directorios.Instalar la herramienta: # emerge -n bzip2
Comprimir: # bzip2 fichero
Descomprimir: # bzip2 -d fichero.bz2
Ficheros .tar.gz
Comprimir: # tar -czf archivo.tar.gz ficheros
Descomprimir: # tar -xvzf archivo.tar.gz
Ver contenido: # tar -tzf archivo.tar.gz
Ficheros .tar.bz2
Comprimir: # tar -c ficheros | bzip2 > archivo.tar.bz2
Descomprimir: # bzip2 -dc archivo.tar.bz2 | tar -xv
Ver contenido: # bzip2 -dc archivo.tar.bz2 | tar -t
Ficheros .zip
Instalar las herramientas: # emerge -n zip unzip
Comprimir: # zip archivo.zip ficheros
Descomprimir: # unzip archivo.zip
Ver contenido: # unzip -v archivo.zip
Ficheros .rar
Instalar la herramienta: # emerge -n rar
Comprimir: # rar a archivo.rar ficheros
Descomprimir: # rar x archivo.rar
Ver contenido: # rar l archivo.rar o # rar v archivo.rar
Los no tan típicos
Ficheros .lha
Instalar la herramienta: # emerge -n lha
Comprimir: # lha a archivo.lha ficheros
Descomprimir: # lha x archivo.lha
Ver contenido: # lha v archivo.lha o # lha l archivo.lha
Ficheros .arj
Instalar las herramientas: # emerge -n arj unarj
Comprimir: # arj a archivo.arj ficheros
Descomprimir: # unarj archivo.arj o # arj x archivo.arj
Ver contenido: # arj v archivo.arj o # arj l archivo.arj
Ficheros .zoo
Instalar la herramienta: # emerge -n zoo
Comprimir: # zoo a archivo.zoo ficheros
Descomprimir: # zoo x archivo.zoo
Ver contenido: # zoo L archivo.zoo o # zoo v archivo.zoo
lunes, 29 de septiembre de 2008
Configuración de SSH en debian
Lo primero que hacemos es instalar el SSH
#apt-get install ssh
Luego de la instalación buscamos el archivo de configuración sshd_config que esta en
# vi /etc/ssh/sshd_config
(Nota. no confundir con el fichero ssh_config)
Agregamos o modificamos las siguientes entradas en el archivo
Parámetro Port
Si fuera necesario por seguridad se puede cambiar el puerto por el cual escucha el SSH
Port 54321
Parámetro ListenAddress
Especificamos bajo que direcciones intefaces responderá las peticiones
ListenAddress 10.0.0.5
Parámetro PermitRootLogin
Especificamos si el superusuario podrá conectarse mediante SSH
PermitRootLogin no
Parámetro X11Forwarding
Especificamos si es necesario que se ejecuten aplicaciones gráficas mediante SSH
X11Forwarding no
Parámetro AllowUsers
Especificamos que usuarios se conectarán mediante SSH
AllowUsers espiridion, cascajo, pully
Tambien se puede restringir el acceso por usuario y host
AllowUsers espiridion@192.168.0.55 cascajo@192.168.5.22
Reiniciamos el SSH
#/etc/init.d/ssh restart