viernes, 27 de diciembre de 2019

Samba y ssh: Compartir recursos en red (3) RECOMENDABLE!!!. ssh. keygen

1. Introducción


Parece ser que cuando apagamos el ordenador y lo volvemos a enchufar tenemos problemas de conexión con las unidades de otros sistemas mapeadas.

En esta entrada vamos a seleccionar lo mejor de los blogs 1 y 2 anteriores.

Para ello vamos a resumir los pasos mas interesantes y luego se hará un script que deberíamos utilizar cada vez que arrancamos los ordenadores.

Si alguien sabe la forma de hacer las conexiones para que sean permanentes, le agradecería que nos aportara la solución.

2. Acceso mediante ssh. Resumen de esta entrada. Compartición de claves RSA


a. Verificar que está instalado Openssh tanto en cliente como en el servidor con el comando:

ssh -V

b. Generar la clave en el cliente mediante

ssh-keygen -q -f ~/.ssh/id_rsa_server_name -t rsa

y nos pide una contraseña( esta contraseña nos la pedirá para acceder por ssh cada vez que rearranquemos el sistema). La clave se guarda en el fichero ~/.ssh/id_rsa siendo "~" la ruta del /home/usuario .

c. Desde el cliente, copiar la clave al sevidor. (y puede pedirnos la contraseña del usuario remoto)

scp ~/.ssh/id_rsa.pub  remoteUser@remoteServer_ip:   # No olvidar los 2 puntos ":" 

d. En el servidor hacemos un append (añadir al final del fichero) de dicha clave al fichero  ~/.ssh/authorized_keys y le añadimos finalmente una línea en blanco:

cat ~/id_rsa_server_name.pub >> ~/.ssh/authorized_keys
echo "" >> ~/.ssh/authorized_keys  # y metemos una linea en blanco!!! MUY IMPORTANTE
rm ~/id_rsa.pub                    # y borramos el fichero que hemos descargado
NOTA: ChatGPT nos dice que se puede copiar como
cat ~/.ssh/id_rsa_server_name.pub | ssh your_user@remote_server 'mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys'

NOTA1En el servidor se puede realizar mediante el programa PuTTY que es un shh client. Pero el problema es que no se puede hacer copy + paste. También se puede hacer utilizando el comando "ssh" directamente por ejemplo:
   ssh remopteUser@repoteServer_ip 'cat ~/id_rsa.pub >> ~/.ssh/authorised_keys'
observando las comillas simples.

NOTA2: Tambien se puede utilizar el software Remina que si que deja copiar y pegar. Para conectar hay que apretar la cruz verde de arriba a la izquierda, y llenar los campos como indica la figura




e. Ejecutamos la primera vez el acceso al servidor y nos pedirá la contraseña que le hemos dado al generar la clave

ssh -o PreferredAuthentications=publickey remoteUser@remoteServer_ip

f. Ya podemos ejecutar cualquier comando ssh (rsync, rcp ..) sin que nos vuelva a pedir la contraseña hasta que rearranquemos el sistema

g. Si rearrancamos el sistema basta con ejecutar

ssh remoteUser@remoteServer_ip

y nos pedirá la contraseña que valdra otra vez para el próximo reaarranque. Este paso lo utilizaremos para ejecutar un script cada vez que se arranca la máquina.


3. Montar un disco de un servidor windows en una carpeta local


a. Crear la carpeta local

sudo mkdir /mnt/WINDOWS01_C

el directorio mnt en principio solo accede root, por eso utilizamos sudo. WINDOWS01 es el nombre del servidor windows, y _C lo utilizamos para indicar que es la unidad C.

b. Montar la carpeta remota del servidor en dicha carpeta local con samba. Según Jim Fell y si queremos evitar dar una contraseña (perjudicando la seguridad del sistema) como dice Jesse Web

Si el servidor windows tiene instalada la version 2 de Samba (SMB2Protocol) entonces esto funciona

echo 'rootPassword' | sudo -S mount -t cifs -o "domain=CORPORACION,username=myuser,password=mypassword,vers=2.0,rw,hard,nosetuids,noperm" //192.168.x.x/c$ /mnt/WINDOWS01_C

Si está instalada la versión 3 hay que cambiar vers=2.0 por vers=3.0

Si por el contrario, está activada la versión 1 que es antigua, funcionará con 
 
echo 'rootPassword' | sudo -S mount -t cifs -o "domain=CORPORACION,username=myuser,password=mypassword,sec=ntlm,vers=1.0,rw,hard,nosetuids,noperm//192.168.x.x/c$ /mnt/WINDOWS01_C

 o mejor visto


# Esto me funcionaba ayer y hoy NO!!
echo 'rootPassword' | sudo -S mount -t cifs -o "domain=CORPORACION,username=myuser,password=mypassword,vers=2.0,rw,hard,nosetuids,noperm" //192.168.x.x/c$ /mnt/WINDOWS01_C

# Esto si me funciona hoy!!!
echo 'rootPassword' | sudo -S mount -t cifs -o "domain=CORPORACION,username=myuser,password=mypassword,vers=2.0,rw,hard,nosetuids,noperm" //192.168.x.x/c$ /mnt/WINDOWS01_C

Tener cuidado con no meter espacios en blanco al lado de las comas !!!!!

siendo:
  'rootPassword' la contraseña que pide al hacer "sudo"
  'myuser' el usuario remoto de windows
  'mypassword' la contraseña del usuario remoto de windows
 //192.168.x.x/c$ hace referencia a la unidad C del servidor windows cuya IP es //192.168.x.x
 /mnt/WINDOWS01_C la carpeta local donde mapear


c. Esto nos vale como siempre hasta que rearrancamos el ordenador.

4. Un shell script para después de arrancar el ordenador.


Ahí tenemos el shell script


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# 1. Activates ssh asking for the pwd of the ssh key
# 2. Mounts remote folders in the /mnt directory

# For using arrays in a shell script:  
# @see: https://www.cyberciti.biz/faq/bash-for-loop-array/

#0. sudo password
rootPwd='rootPassword'


#1. For connecting alfresco files with RSA password. "myRSAPassword"
ssh remoteUser@192.x.x.10

#2.1 Define the local folders to mount
mntFolders[0]=/mnt/WINDOWS01_C
mntFolders[1]=/mnt/WINDOWS02_F
mntFolders[2]=/mnt/WINDOWS03_D

#2.2 Define the remote connections to be mounted to local folders
folders[0]=//192.x.x.1/C$ folders[1]=//192.x.x.2/F$ folders[2]=//192.x.x.3/D$ #3. Unmount the folders for var in "${mntFolders[@]}" do echo "Unmounting ${var}" echo "$rootPwd" | sudo -S umount "$var" done echo Por favor, intro continua.. read continuar #4. Create the folders for var in "${mntFolders[@]}" do echo "Creating mount folder ${var}" echo "$rootPwd" | sudo -S mkdir "$var" done echo Por favor, intro continua.. read continuar #5. Mount the folders # Use c style for loop # get total subscripts in an array total=${#mntFolders[*]} # for (( i=0; i<=$(( $total -1 )); i++ )) do # echo "$rootPwd" | sudo -S mount -t cifs -o "domain=CORPORACION,username=myuser,password=mypassword,vers=2.0,rw,hard,nosetuids,noperm" "${folders[$i]}" "${mntFolders[$i]}"
    echo "$rootPwd" | sudo -S mount -t cifs -o "domain=CORPORACION,username=myuser,password=mypassword,sec=ntlm,vers=1.0,rw,hard,nosetuids,noperm" "${folders[$i]}" "${mntFolders[$i]}"
done echo Por favor, intro continua.. read continuar

Cuando ejecutemos, en la línea 13 nos pedirá la contraseña de la clave RSA y una vez dentro hay que salirse de la sessión ssh mediante Crtl-d

En la línea 25 se quejará pues cuando se arranca el sistema, no hay nada montado en esas carpetas de montaje, pues se han pedido las conexiones.

En la línea 35 también se quejará pues las carpetas ya existen.

Pero a partir de la línea 49 hay que ir con mucho cuidado pues es ahí donde se conectan las unidades remotas a las carpetas del /mnt

5. Averiguar si el Windows Server tiene configurado SAMBA

Según Microsoft Vamos al PowerSell de Windows (no vale para el simple cmd !!!) y ejecutamos para ver si tiene SAMBA 1

Get-SmbServerConfiguration | Select EnableSMB1Protocol

y devolverá True o false



Y para el SAMBA 2 y 3 que normalmente vienen por defecto.

Get-SmbServerConfiguration | Select EnableSMB2Protocol

jueves, 12 de diciembre de 2019

Acceder a recursos de una red windows desde Ubuntu con Samba. Mostrar en Nautilus (2)

1. Prerequisitos

Según Wiki Ubuntu hay que instalar cfis

sudo apt-get install cifs-utils


En un post anterior se hablaba del tema, pero con Ubuntu 18.04 algunas cosas cambian. En estas versiones anteriores hay métodos faciles (como dice Justin Garrison) de acceder a Windows

Según L.D. James en AskUbuntu en el navegador de ficheros de Ubuntu 18.04 (Nautilus) hacer Crlt-L e indicar por ejemplo

smb://192.168.x.x/C$

te pedirá usuario, dominio y contraseña y a funcionar ! Se ha compartido el disco C de dicho servidor.

También se puede hacer por línea de comandos como

gio mount smb://192.168.x.x/C$

En este caso es un antiguo Windows Server 2003. Pero hay que leerse el resto de la contestación del Sr. James y afinar un poco mas....

hay que modificar el fichero /etc/samba/smb.conf y hay que cambiar lo que se indica en amarillo


#======================= Global Settings =======================
[global]

client use spnego = no  # Puede que no tengas esa línea
client NTLMv2 auth = no # Puede que no tengas esa línea

## Browsing/Identification ###
# Change this to the workgroup/NT-domain name your Samba server will part of
#   workgroup = WORKGROUP
   workgroup = CORPORACION
   client max protocol = NT1


2. ¿Dónde está el punto de montaje?

El problema surge para buscar el punto de montaje. menos mal que WLigtenberg da luz al problema.

Se monta en mi caso en:

/run/user/1000/gvfs


Y Webwurst y Tobyll nos aportan luz al respecto mediante los comandos:

findmnt   que devuelve


├─/run                                tmpfs       tmpfs   rw,nosuid,noexec,relatime,size
│ ├─/run/lock                         tmpfs       tmpfs   rw,nosuid,nodev,noexec,relatim
│ ├─/run/rpc_pipefs                   sunrpc      rpc_pip rw,relatime
│ ├─/run/user/1001                    tmpfs       tmpfs   rw,nosuid,nodev,relatime,size=
│ ├─/run/user/124                     tmpfs       tmpfs   rw,nosuid,nodev,relatime,size=
│ └─/run/user/1000                    tmpfs       tmpfs   rw,nosuid,nodev,relatime,size=
│   └─/run/user/1000/gvfs             gvfsd-fuse  fuse.gv rw,nosuid,nodev,relatime,user_
├─/snap/core18/1279                   /dev/loop0  squashf ro,nodev,relatime
├


o tambien
gvfs-mount -l   que está deprecado y se debe utilizar
gio mount -l

y devuelve


Drive(5): Generic- SD/MMC
  Type: GProxyDrive (GProxyVolumeMonitorUDisks2)
Drive(6): Generic- MS/MS-Pro/HG
  Type: GProxyDrive (GProxyVolumeMonitorUDisks2)
Drive(7): Generic- SD/MMC/MS/MSPRO
  Type: GProxyDrive (GProxyVolumeMonitorUDisks2)
Mount(0): c$ a 192.168.28.11 -> smb://192.168.28.11/c$/
  Type: GDaemonMount


Pero este último comando no nos aporta la información que interesa


3. ¡Oh Sorpresa! Múltiples montajes

Pero ahora monto otro servidor .... y me aparecen 2 directorios nuevos en /run/user/1000/gvfs !!!

/run/user/1000/gvfs/smb-share:server=192.168.x.x,share=c$
/run/user/1000/gvfs/smb-share:server=192.168.y.y,share=F$

¡Sorpresa, sorpresa! A ver como me lo monto para hacer cópias de seguridad!



viernes, 29 de noviembre de 2019

Backups incrementales de Alfresco

1. Procedimiento

Vamos a guardar las copias de las siguientes fechas

-Una supercompleta a dia 1 de Enero del año actual. En esta copia se guardará todo lo que hay en este año y los anteriores. Sirve de copia de seguridad de todo lo anterior. Se llamara:
  
   Alfresco.TOTAL.AAAA.tar siendo AAAA el año anterior


- Una completa del año actual hasta el dia 1 del mes inclusive que se llamará

   Alfresco.AAAAMM01.tar siendo AAAA el año actual y MM el mes actual (01 es el dia)

- Una incremental diaria en base a la del dia 1, a partir del dia 2 el 31 inclusive que se llamará
 
      Alfresco.MMDD.tar siendo MM el mes y DD el dia del mes

Se podria aplicar compresión, pero no queda muy justificada pues los ficheros de alfresco están bastante comprimidos.

2. Pasos

1. Supongamos que tenemos 2 carpetas:

  /opt/mybackup-rsync donde se guarda un rsync diario para hacer copia de seguridad
 /opt/mytars  donde se guardan las copias de seguridad en formato tar

2. Realizar el resync de los datos del servidor
Para ello seguimos los pasos del post anterior. Si hay datos de un rsync previo, tardará menos. Sinó, tardará lo suyo

cd /opt/mybackup-resync  # Nos situamos en la carpeta local donde descargar el backup

rsync -avzh usuarioRemoto@IP:/opt/alfresco-4.2.f/alf_data .   # Ejecutamos la copia

3. Miramos que copia vamos a realizar

3.1 Copia total

Vamos a la carpeta padre y ejecutamos la copia


cd /opt     # vamos a la carpeta padre

tar -cvf mytars/alfresco.TOTAL.2018.tar mybackup-rsync


3.2 Si es copia del año hasta hoy dia 01 de Noviembre de 2019. Para ello ejecutamos  (OJO el formato es mm/dd/aaaa  !!)

find ./mybackup-resync -type f -newermt '01/01/2019 0:00:00'  -exec tar -rvf /mytars/alfresco.20191101.tar "{}" +

parece ser que cambiando "{}" por '{}' también funciona y así es mas fácil de usar en scripts

3.3 Si es copia incremental desde el dia 1 de noviembre del año 2019 hasta hoy dia 29 de Noviembre de 2019. Para ello ejecutamos (OJO el formato es mm/dd/aaaa  !!)


find ./mybackup-resync -type f  -newermt '11/01/2019 0:00:00'  -exec tar -rvf /mytars/alfresco.29.tar "{}" +

parece ser que cambiando "{}" por '{}' también funciona y así es mas fácil de usar en scripts

Copiar un LV (Volumen lógico) o un disco a una máquina remota

1. En modo simple

1.1 Ejecutado desde la máquina que tiene el disco a copiar. Hay que tener en cuenta que el usuario debe de tener permiso sobre el directorio donde se va a grabar la imagen

dd if=/dev/midisco | ssh user@targetServer 'dd of=/path/to/target'

1.2 Ejecutado desde la máquina remota al disco a copiar. A veces el "sudo" remoto puede dar problemas, y puede que en aqlgunos casos se pueda obviar

ssh user@targetServer "sudo dd if=/dev/midisco" | dd of=/path/to/target

En mi caso, copiando un disco de 180Gb con 80Gb de datos y el resto vacío, tardó 27 min.

2. Ajustes finos en el comando dd (tweaks)

Según Rod en el año 2015

2.1 Averiguamos el tamaño de bloque del LV, para ello nos vamos al directorio donde está montado (en este caso /opt ) y ejecutamos


stat -fc %s /opt

y nos devuelve 4096

Como norma tenemos que utilizar un múltiplo de la longitud de bloque!

2.2 Si la seguridad del sistema lo permite, se puede seleccionar una encriptación ssh poco segura pero rápida como arcfour si lo permite tu versión de Openssh, o segun(/dev/blog) aes128-ctr pueden acelerar la conexión. Para ver los cifrados que se pueden realizar ejecutamos

ssh -Q cipher localhost 

y en mi caso devuelve


3des-cbc
aes128-cbc
aes192-cbc
aes256-cbc
rijndael-cbc@lysator.liu.se
aes128-ctr
aes192-ctr
aes256-ctr
aes128-gcm@openssh.com
aes256-gcm@openssh.com
chacha20-poly1305@openssh.com

vemos que aes126-ctr si está y lo usamos

ssh -c aes128-ctr user@targetServer "sudo dd if=/dev/midisco bs=4M" | dd of=/path/to/target

Pero no se ha visto mejoría!

Lo que si que está claro es que el algoritmo de cifrado 3des-cbc enlentece mucho y no se aconseja usar. Por otra parte  según tdg5 , a él le va mejor un bloque de 128K=131072 (bs=131072) le va un poco mas rápido. Hechas las pruebas, tal vez aumente solo el 1% el rendimiento.

3. ¿Comprimimos?

Si comprimimos, ahorramos disco... pero tardamos 2 horas! o sea se multiplica por 5 el tiempo de la copia. De todas formas se puede intentar.

ssh user@targetServer "sudo dd if=/dev/midisco | gzip -1 -" | dd of=/path/to/target

Hay que tener en cuenta que estoy haciendo una copia de seguridad de Alfresco, y parece ser que los ficheros ya vienen comprimidos, por tanto, poco ganamos con la compresión, excepto para laparte din datos del volumen lógico.

4. Opcion scp. 

OJO: No copia particiones, sino ficheros y/o carpetas

En un blog anterior, queríamos hacer una copia de seguidad de Alfresco y teniendo en cuenta que :
1. Estamos en la máquina local donde queremos copiar la carpeta remota
2. Cuidado econ el scp ya que primero hay que indicar el destino y despues el origen
usábamos:


scp -rp /home/backups.destino/ usuarioRemoto@IP:/opt/alfresco-4.2.f/alf_data

donde las opciones:
  r indica copia recursiva de ficheros y subcarpetas
  p para preservar fechas y autorías de ficheros.

también podemos indicar si queremos compresión la opción C. Pero como hemos dicho en este caso,  poco se gana ya que los ficheros de Alfresco vienen con una tasa de compresión alta.

5. Opción rsync

rsync permite la transferencia rápida de ficheros de forma incremental según el atareao.

Para evitar problemas de borrado, voy a excluir la opción--delete.

Verificar que rsync está instalado tanto en la máquina local como en la remota.

De todas maneras, algunos comandos han tenido que modificarse.  Para ello nos situamos en una carpeta local y después ejecutamos la copia. La primera vez tarda bastante, pero después hace una copia incremental.


cd /mybackup-folder  # Nos situamos en la carpeta local donde descargar el backup

rsync -avzh usuarioRemoto@IP:/opt/alfresco-4.2.f/alf_data .   # Ejecutamos la copia

Para hacer la primera copia se ha tardado 1h-20 min



miércoles, 27 de noviembre de 2019

Compresión de ficheros con tar y otros medios

0. Limitaciones con los ficheros grandes

Para poder manejar ficheros grandes, hay que verificar que:
1. La partición del disco duro permita manejar ficheros grandes LFS (por ejemplo FAT32 NO lo permite), por tanto hay que buscar un formato (ext1?) o buscar en internet los formatos que permitan LFS

1. Usando el tar con compresión


Tar tiene una limitación de 68 Gigas. Por desgracia me di cuenta haciendo un backup de 80 Gigas,

Veamos algunas formas  de comprimir con tar


tar -cf   archive.tar    folder   # Sin compresión
tar -cvf  archive.tar    folder   # Sin compresión (v)erbose

tar -cfJ  archive.tar.xz folder   # compresión xz

tar -cvzf archive.tar.gz folder   # compresión gzip (v)erbose  
tar -cvjf archive.tar.bz2 folder  # compresión bzip2 (v)erbose  


2. Ficheros grandes

Para ello es interesante partir el fichero en trozos mas pequeños. Con 7z se puede hacer, pero tarda lo suyo

7z a archive.7z -vsize[b|k|m|g] folder

La opción -v se le pasa el tamaño y las unidades (b:bytes, k=kbytes, m=megabytes, g=gigabytes). Para tamaño de ficheros de 10G con FAT32 falla, pero va bien con ficheros de 1G, pero las copias se ralentizan mucho.

Probamos con otros compresores (xz, gzib, bzip2), pero no permiten hacer compresión de una carpeta a un solo fichero, ni por tanto hacer split. Para ello se debe hacer en combinación con un tar. Hay que tener cuidado con estos compresores ya que si se utilizan solos, hay que meter la opción -k para que no borre el fichero ofiginal,




SHH : Ejecutar comandos y hacer copias desatendidos de ficheros remotos

0. Introducción

Quiero hacer unas copias de ficheros de forma desatendida desde un servidor remoto.
Para ello se ha pensado en ssh.  Pero cada vez que conectamnos nos pide que introduzcamos a mano una contraseña, con lo que la opción de realizar-lo en un CRON-TAB queda descartada.

1. Opcion 1: sshpass


Se instala este programa y se simula que se introduce la contraseña. Ver serverfault 


$ sudo apt-get install sshpass
$ sshpass -p your_Password12345 ssh user@hostname

No se hasta que punto puede funcionar en sistemas heterogeneos (widows-linux) o si existe una version adecuada a windows de sshpass

2. Opción2: compartición de claves RSA


Para ello se actúa así:

0. Comprobar que esté Openssh instalado tanto en el cliente como en el servidor, ejecutando el comando


ssh -V


1. Generar claves en la màquina local


ssh-keygen -t rsa -b 4096 -R 192.XXX.XXX.XXX              
     # Generating public/private rsa key pair. 
     # Enter file in which to save the key (/home/ximo/.ssh/id_rsa):
     # /home/ximo/.ssh/id_rsa already exists.
     Overwrite (y/n)? n

2. Copiar las claves al servidor remoto

ssh-copy-id myuser@192.XXX.XXX.XXX     
     #/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
     #/usr/bin/ssh-copy-id: INFO: 2 key(s) remain to be installed -- if you are prompted now it is to install the new keys
     
     myuser@192.XXX.XXX.XXX's password: 
#Number of key(s) added: 2 #Now try logging into the machine, with: "ssh 'myuser@192.XXX.XXX.XXX'" # and check to make sure that only the key(s) you wanted were added.


3. Ejecutar el ssh sobre el servidor remoto

ssh myuser@192.XXX.XXX.XXX                 
# Entramos ya sin pedir contraseña


========================================================================
Esto que viene a continuación es antiguo y ha quedado desfasado



1. Crear el directorio ~/.ssh en la máquina cliente (Nota ~ es el directorio de usuario /home/myuser).

2. Generar la clave rsa en dicha carpeta del cliente y pedirá una contraseña (por ejempo your_Password12345) que se tendrá que guardar. Se generará en el fichero ~/.ssh/id_rsa.pub


client$    ssh-keygen -q -f ~/.ssh/id_rsa -t rsa

3. Desde el cliente copiamos la clave al servidor remoto


client$    scp ~/.ssh/id_rsa.pub  remoteUser@remoteServer_ip:   # No olvidar los 2 puntos ":"      

y nos pedirá la contraseña de remoteUser (que tiene en el remoteServer)

4. en el servidor hacemos un append (añadimos al final del fichero) dicha clave  al fichero ~/.ssh/authorized_keys y le añadimos finalmente una línea en blanco


server$    cat ~/id_rsa.pub >> ~/.ssh/authorized_keys
server$    echo "" >> ~/.ssh/authorized_keys  # y metemos una linea en blanco!!! MUY IMPORTANTE
server$    rm ~/id_rsa.pub                    # y borramos el fichero que hemos descargado

5. Ejecutamos la primera vez en el cliente el acceso al servidor y nos pedirá la contraseña que le hemos dado al generar la clave rsa (en nuestro caso your_Password12345 )


client$    ssh -o PreferredAuthentications=publickey remoteUser@remoteServer_ip

6. Ya podemos entrar con ssh o scp (para copiar ficheros) y ya no nos vuelve a pedir la contraseña

client$    ssh remoteUser@remoteServer_ip

7. Problema: Si rearrancamos la máquina, nos vuelve a pedir la contraseña !!!


jueves, 21 de noviembre de 2019

Alfresco Backup

1. El fichero de propiedades "alfresco-global.properties".

En un caso concreto se encuentra en /opt/alfresco-4.2.f/tomcat/shared/classes
Las entradas más importantes son:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
###############################
## Common Alfresco Properties #
###############################
dir.root=/opt/alfresco-4.2.f/alf_data    #Instalación
alfresco.context=alfresco
alfresco.host=0.0.0.0
alfresco.port=8080
alfresco.protocol=http

share.context=share
share.host=0.0.0.0
share.port=8080
share.protocol=http

### database connection properties ###
db.driver=org.postgresql.Driver
db.username=myuser
db.password=mypassword
db.name=alfrescodb
db.host=192.168.xx.xx
db.port=5432
#db.url=jdbc:postgresql://192.168.28.38/alfresco
db.url=jdbc:postgresql://${db.host}:${db.port}/${db.name}

### FTP Server Configuration ###
ftp.enabled=true
ftp.port=21

### RMI service ports ###
alfresco.rmi.services.port=50500
avm.rmi.service.port=0
avmsync.rmi.service.port=0
attribute.rmi.service.port=0
authentication.rmi.service.port=0
repo.rmi.service.port=0
action.rmi.service.port=0
deployment.rmi.service.port=0

### External executable locations ###
ooo.exe=/program/soffice.bin
ooo.enabled=true
ooo.port=8100
img.root=/opt/alfresco-4.2.f/common
img.dyn=${img.root}/lib
img.exe=${img.root}/bin/convert
swf.exe=/opt/alfresco-4.2.f/common/bin/pdf2swf
swf.languagedir=/opt/alfresco-4.2.f/common/japanese

jodconverter.enabled=false
jodconverter.officeHome=
jodconverter.portNumbers=8100

### Initial admin password ###
alfresco_user_store.adminpassword=110079e729078af9e8a4d2fa6b13ed5c

### E-mail site invitation setting ###
notification.email.siteinvite=false

### License location ###
dir.license.external=/opt/alfresco-4.2.f

### Solr indexing ###
#index.subsystem.name=solr
#dir.keystore=${dir.root}/keystore
#solr.port.ssl=8443
index.subsystem.name=noindex


### BPM Engine ###
system.workflow.engine.jbpm.enabled=false

Obervar que la BD de Postgres puede estar o no en el muismo servidor, y por tanto los usuarios y contraseñas de acceso pueden ser distintos también.


2. Pasos a realizar en un hot Backup de Alfresco


1. Copiar el fichero alfresco-global.properties

2. Hacer Backup de los índices de Solr o Lucene si es el caso ??
En este caso, la línea 68 contiene esta información:

   index.subsystem.name=noindex

Por tanto no se están utilizando los índices de solr o lucene, y no utilizamos la indexación de alfresco y no nos afecta esta apartado

3. Hacer un bakcup de la Base de Datos, en este caso como es Postgres, se hará un pg_dump.
para ello de forma remota se puede hacer segun stackoverflow:


PGPASSWORD="mypassword"   pg_dump -h 192.168.xx.xx -Fc -o -U myuser alfrescodb > /home/backups/alfrescodb.dump


4. Hacer backup de la carpeta indicada en la entrada "dir.root" del fichero de propiedades. En este caso opt/alfresco-4.2.f/alf_data .Para ello usamos ssh


scp -rp /home/backups/ usuarioRemoto@IP:/opt/alfresco-4.2.f/alf_data

Pero .....

3. A tener en cuenta

1. Una copia de seguridad de 80Gb con ficheros pequeños me ha costado alrededor de 2 horas con el scp, por tanto hay que saber en que terreno moverse!

2. Haciendo lo mismo pero con un "ssh y dd" tardamos 20 minutos... Pero tenemos que copiar todo el disco (o LV) y nos ocupa 180 Gb.??


ssh usuarioRemoto@IP "sudo dd if=/dev/midisco" | dd of=image.ximo

3. En un post futuro hablaremos sobre como optimizar la copia de un LV

martes, 10 de septiembre de 2019

Llamada a programas EJECUTABLES desde Java

1. Introducción


Uno de los principales problemas que tenía utilizando Java era el no saber como llamar a programas ejecutables.

Por tanto cuando se creaba un proyecto se tenía que ir agregando dependencias hasta que éste se hacía insostenible por su tamaño y problemas entre las versiones de dependencias.

He estado viendo algunos enlaces interesantes :

  • Mkyong : Explica muy bien las dos alternativas que ofrece Java ( ProcessBuilder y Runtime.getRuntime().exec)
  • Zetcode
  • Baeldung que incluye las mejoras de Java 9 para tratar las "pipes"


2. Apache commons exec

La mayor parte de las veces he tenido una buena experiencia con Apache, El problema es que esta libreria es ya algo antigua.

La dependencia maven es:


1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-exec -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-exec</artifactId>
    <version>1.3</version>
</dependency>

Veamos el código fuente de una clase de utilidad que he creado junto con un "main" de prueba.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package openadmin.utils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecuteResultHandler;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteException;
import org.apache.commons.exec.ExecuteWatchdog;
import org.apache.commons.exec.PumpStreamHandler;

public class CmdUtils {
	/**
	 * 
	 * @param commandLine            Line to execute
	 * @param optSuccessValue        (Optional) If the success return is not equal
	 *                               to "0". For instance Acrobat returns 1
	 * @param optMaxDurationMiliSecs (Optional) Maximum wait until kill the program
	 *                               if blocked,
	 * @param isAsync                True if we want to execute the command
	 *                               asynchronously
	 * @param outputStream           ByteArrayOutputStream to collect the output
	 *                               messages of the program
	 * 
	 * @return
	 * @throws ExecuteException
	 * @throws IOException
	 */
	public static int execProgram(String commandLine, Integer optSuccessValue, Long optMaxDurationMiliSecs,
			Boolean isAsync, ByteArrayOutputStream outputStream) throws ExecuteException, IOException {

		int exitValue = 0;
		ExecuteWatchdog watchdog = null;

		CommandLine cmdLine = CommandLine.parse(commandLine);
		DefaultExecutor executor = new DefaultExecutor();

		if (outputStream != null) {
			PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream);
			executor.setStreamHandler(streamHandler);
		}

		if (optSuccessValue != null)
			executor.setExitValue(optSuccessValue);
		if (optMaxDurationMiliSecs != null) {
			watchdog = new ExecuteWatchdog(optMaxDurationMiliSecs);
			executor.setWatchdog(watchdog);
		}
		if (isAsync != null && isAsync)
			executor.execute(cmdLine, new DefaultExecuteResultHandler());

		else
			exitValue = executor.execute(cmdLine);

		return exitValue;
	}

	public static void main(String[] args) {

		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		
		String[] commandLines = { "/usr/bin/java -version", "java -version", "ls /home/eduard/",
				"/usr/bin/AutoFirma  sign -i /home/ximo/kk/xmlprueba.xml -o /home/ximo/kk/xml_firma103.xsig -format xades -store mozilla -alias EPN1" };

		int i = 0;
		try {
			for (String s : commandLines) {
				System.out.println(i++ + "-->" + s);
				execProgram(s, null, null, null, outputStream);
				int j=0;
				for (String line : outputStream.toString().split("\\n")) 
					System.out.println("Action:" + i + "." + ++j + "-->" + line);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}






Aquí se ejecutan 4 comandos (en azul, líneas 63-64) de forma secuencial (en un sistema Ubuntu) con ejecución satisfactoria. Observar que en última sentencia se llama AUTOFIRMA para firmar un documento "xml" utilizando un certificado del repositorio de Mozilla. si se quiere mas detalles, se puede ver un post anterior sobre Autofirma.

Observar que queremos interceptar la salida del comando mostrando las líneas (en el caso del "ls" parece que no va...)

Observar también que se puede ejecutar de forma asíncrona con el parámetro isAsync

Happy coding!

domingo, 18 de agosto de 2019

Enviar correos con GMAIL(2). Simple Java Mail (Recomendable) YA OBSOLETO POR CULPA DE LA DOBLE AUTENTICACION

0.Introducción

Justo después de realizar la entrada anterior, me encuentro con Simple Java Mail que es muy simple de utilizar, así que vamos a utilizar esta librería.

1. Dependencia maven


Es la siguiente;


1
2
3
4
5
6
    <!-- https://mvnrepository.com/artifact/org.simplejavamail/simple-java-mail -->
    <dependency>
      <groupId>org.simplejavamail</groupId>
      <artifactId>simple-java-mail</artifactId>
      <version>5.3.0</version>
    </dependency>

2. Abrir la seguridad Google a aplicaciones no seguras

Hay que ir a este enlace: https://myaccount.google.com/lesssecureapps y desactivar la opción de seguridad. Tal como se vió en la entrada anterior

3. Verificar que el certificado del smtp.google.com está en el cacert

Esto se vió en la entrada anterior y se basa en  My Tech Notes


4. Ver esta simple clase de Java



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package u.requests;

import org.simplejavamail.email.Email;
import org.simplejavamail.email.EmailBuilder;
import org.simplejavamail.mailer.MailerBuilder;
import org.simplejavamail.mailer.config.TransportStrategy;

public class SendMail {

 public static void main(String[] args) {
  Email email = EmailBuilder.startingBlank()
   .from("Ximo Dante", "ximodante@gmail.com")
   .to("edu"  , "eduxxxxx@gmail.com")
   .to("kevin", "kevinxxx@gmail.com")
   .withSubject("Using Simple Java Mail 01")
   .withPlainText("Edu, Kevin. I am using Simple Java Mail API...!!!")
   .buildEmail();

  MailerBuilder
   .withSMTPServer("smtp.gmail.com", 587, "ximodante@gmail.com", "mypassword")   .withTransportStrategy(TransportStrategy.SMTP_TLS)
   // or
   //.withSMTPServer("smtp.gmail.com", 465, "your user", "your password")
   //.withTransportStrategy(TransportStrategy.SMTPS);
   .buildMailer()
   .sendMail(email);
 }

}

Y a funcionar!!!!!

Enviar correos con GMAIL(1). Java Mail (No recomendable)

0. Introducción.


Aunque parece sencillo enviar e-mails mediante Java y Gmail, hay algunos problemas tontos que solucionar.

El primero es seleccionar las librerías de "javamail". Parece ser que "javamail" ahora cambian de nombre a "jakarta.mail".

El segundo es el tema de la configuración del protocolo  "smtp" de gmail, que se puede utilizar mediante protocolos TLS y SSL, mediante puertos diferentes (587 y 465 respectivamente), y cada cual requiere unas propiedades de configuración.

El tercero es que hay que ir a este enlace: https://myaccount.google.com/lesssecureapps y desactivar la opción de seguridad.

El cuarto es que el almacén de certificados del java que estemos utilizando debe de tener el certificado del smtp de google para confiar en él.

1. Definir las dependencias en el fichero pom de maven

Hay que tener en cuenta que en mi caso estoy utilizando un jdk 10, por tanto es prudente adjuntar las librerías que a partir del jdk 9 dejan de ser incluidas.

Se ha marcado con fondo amarillo las dependencias críticas que son las de jakarta.mail y las no incluidas en los JDKs posteriores a 1.8.


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>ximodante</groupId>
  <artifactId>DecretsScheduler01</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>DecretsScheduler01</name>
  <description>Scheduler for updating SOFTPROP decret number and GEXFLOW doc description</description>
  
  <properties>
    <lombok.version>1.18.8</lombok.version>
    <h2.version>1.4.196</h2.version>
    <hibernate.version>5.2.16.Final</hibernate.version>
    <jaxb.version>2.3.0</jaxb.version>
    <activation.version>1.2.0</activation.version>
    
        
    <failOnMissingWebXml>false</failOnMissingWebXml>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <!-- Java version-->
    <java.version>10</java.version>
  </properties>  
    
  <dependencies>
   <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>${lombok.version}</version>
      <scope>provided</scope>
    </dependency>
    
    <!--  Apache commons string utils .. -->
    <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.7</version>
    </dependency>
    
    <!-- Apache commons bean utils-->
    <!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->
    <dependency>
      <groupId>commons-beanutils</groupId>
      <artifactId>commons-beanutils</artifactId>
      <version>1.9.3</version>
    </dependency>
    
    <!-- https://mvnrepository.com/artifact/org.postgresql/postgresql -->
    <dependency>
      <groupId>org.postgresql</groupId>
      <artifactId>postgresql</artifactId>
      <version>42.2.6</version>
    </dependency>  
     
       
    
    <!-- JPA 2.1 Provider -->
    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>${hibernate.version}</version>
    </dependency>
    
    <!-- Envers for auditing the database -->
    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-envers -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-envers</artifactId>
      <version>${hibernate.version}</version>
    </dependency>
    
    <!-- Hibernate Testing !!! -->
    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-testing -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-testing</artifactId>
      <version>${hibernate.version}</version>
      <scope>test</scope>
    </dependency>
    
    <!-- 2018-05 Hibernate Bean Validator Optional Doesn't follow the same versioning !!-->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>6.0.10.Final</version>
    </dependency>
    
    <!-- https://mvnrepository.com/artifact/com.sun.mail/jakarta.mail -->
    <dependency>
      <groupId>com.sun.mail</groupId>
      <artifactId>jakarta.mail</artifactId>
      <version>1.6.3</version>
    </dependency>

 
    <!--BEGIN Java 9 references to JEE  not included in JDK9-->
    <!-- 2017-07 JAXB API -->
    <!-- https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api -->
    <dependency>
      <groupId>javax.xml.bind</groupId>
      <artifactId>jaxb-api</artifactId>
      <version>${jaxb.version}</version>
    </dependency>
    
    <!-- 2017-08 JAXB Implementation -->
    <!-- https://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-impl -->
   
    <dependency>
      <groupId>com.sun.xml.bind</groupId>
      <artifactId>jaxb-impl</artifactId>
      <version>${jaxb.version}</version>
    </dependency>
        
    <!-- 2017-08 Old JAXB Core -->
    <!-- https://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-core -->
    <dependency>
      <groupId>com.sun.xml.bind</groupId>
      <artifactId>jaxb-core</artifactId>
      <version>${jaxb.version}</version>
    </dependency>
    
    <!-- 2017-09-06 Activation API -->
    <!-- https://mvnrepository.com/artifact/javax.activation/javax.activation-api -->
    <dependency>
      <groupId>javax.activation</groupId>
      <artifactId>javax.activation-api</artifactId>
      <version>${activation.version}</version>
    </dependency>

    <!-- 2017-09-06 Activation Implementation -->
    <!-- https://mvnrepository.com/artifact/com.sun.activation/javax.activation -->
    <dependency>
      <groupId>com.sun.activation</groupId>
      <artifactId>javax.activation</artifactId>
      <version>${activation.version}</version>
    </dependency>

    <!-- END Java 9 references to JEE  not included in JDK9-->
    
    
    
  </dependencies>
  
</project>


2. Definir las propiedades para utilizar el servidor de GMAIL

Como hemos dicho se pueden definir el acceso por TLS y SSL , para ello hemos creado un fichero de propiedades en

src/mail/rsources/properties/mail.properties

donde se muestran las 2 configuraciones. Basta con comentar la que no se desee. En este caso está activada la opción 1.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#For Google Mail GMail
username=myuser@gmail.com
password=mypassword

#OPTION 01
#--BEGIN If use TLS
mail.smtp.host=smtp.gmail.com
mail.smtp.port=587
mail.smtp.auth=true
mail.smtp.starttls.enable=true
#--END If use TLS

#OPTION 02
#--BEGIN If use SSL
#mail.smtp.ssl.enable=true
#mail.smtp.host=smtp.gmail.com
#mail.smtp.ssl=true
#mail.smtp.port=465
#mail.smtp.auth=true
#mail.smtp.socketFactory.port=465;
#mail.smtps.quitwait=false
#mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory;
#--END If use SSL

3. Abrir la seguridad Google a aplicaciones no seguras

Hay que ir a este enlace: https://myaccount.google.com/lesssecureapps y desactivar la opción de seguridad.

4. Agregar el certificado de smtp.gmail.com al almacén de certificados del java a utilizar

Hay que tener en cuenta que si se cambia el Java a ejecutar el programa, se tendrá que volver a instalar el certificado.

Hay quien dice que una vez instalado el certificado en el alamcén de certificados, se puede copiar este fichero "cacerts" al nuevo java.

Veamos los pasos a seguier según My Tech Notes:

1. Capturar el certificado de smtp.gmail.com


1
2
3
4
5
6
7
8
#For Linuix and Mac
openssl s_client -connect smtp.gmail.com:465


#For Windows
#Install openssl first
#Run command:
s_client -connect smtp.gmail.com:465


2. Copiar en un fichero (por ejemplo gmail.cert) el contenido entre "-----BEGIN CERTIFICATE-----" y "-----END CERTIFICATE-----" inclusive


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
-----BEGIN CERTIFICATE-----
MIIFiTCCBHGgAwIBAgIQAiKavL3Byn4CAAAAAD7OozANBgkqhkiG9w0BAQsFADBC
MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZpY2VzMRMw
EQYDVQQDEwpHVFMgQ0EgMU8xMB4XDTE5MDcyOTE3MzA0NVoXDTE5MTAyNzE3MzA0
NVowaDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcT
DU1vdW50YWluIFZpZXcxEzARBgNVBAoTCkdvb2dsZSBMTEMxFzAVBgNVBAMTDnNt
dHAuZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvarO
2yqbcJ3AJRFMqP5PXmWbSTQz3E+MwgUKxeK0HH6JM9AB/WzkRxNiRy87tZyJXHRw
J2LBed5ZbLHCf8XC+A4ZZFjyz58/Vd63ix1g7+j7xwYNFynUcmDUYKbTsTYY1dSS
IP4tnLFDQUgcm0QogGu29DKWydTQ13d0PV71ggYPwALffoFjzg4sJ+F5aLGklChs
H6UDDkUbCe6bL+Xd52NX7I9j+jABkDsBAnMRnqWToZ8oGLWP6WPR5qi6BR31X//q
QwJwtV5kYL+Ga5/NDhy2vr4FNp9j479scYoaqAHakfaerwQecDGSgNvhWMgVHvzP
fmUH/Wbw19XrKj+1XwIDAQABo4ICUzCCAk8wDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFIjG4Xk2Ljbc
/tW/gDBpSAspoVomMB8GA1UdIwQYMBaAFJjR+G4Q68+b7GCfGJAboOt9Cf0rMGQG
CCsGAQUFBwEBBFgwVjAnBggrBgEFBQcwAYYbaHR0cDovL29jc3AucGtpLmdvb2cv
Z3RzMW8xMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2cvZ3NyMi9HVFMxTzEu
Y3J0MBkGA1UdEQQSMBCCDnNtdHAuZ21haWwuY29tMCEGA1UdIAQaMBgwCAYGZ4EM
AQICMAwGCisGAQQB1nkCBQMwLwYDVR0fBCgwJjAkoCKgIIYeaHR0cDovL2NybC5w
a2kuZ29vZy9HVFMxTzEuY3JsMIIBAwYKKwYBBAHWeQIEAgSB9ASB8QDvAHUAY/Lb
zeg7zCzPC3KEJ1drM6SNYXePvXWmOLHHaFRL2I0AAAFsPv/GPwAABAMARjBEAiBV
Sx+FOZIHrNFGeFn+FzijD+cAxQGNs4ZBtse46eqYhwIgF5ik74oyQtJcHDIiUNNH
k3KO/uf8ybdf+w4dqwxFN0kAdgB0ftqDMa0zEJEhnM4lT0Jwwr/9XkIgCMY3NXnm
EHvMVgAAAWw+/8YbAAAEAwBHMEUCICbDyQ2QAmzHNU9UvMfQcrKx0zNKod1rrD4l
asqF9KwxAiEAh5xlln8LCxVgrCrzSUJ53OhVOPSFpwtSckOCj4zSul8wDQYJKoZI
hvcNAQELBQADggEBAMRgqtLuioioRY90BaDyofKqPuH//hv6Au6R1f5FMeQIfZbC
ADpeFenRqBAR/a522YrawKfrI2SLQQquVUPNZWQWrmZCPpkJWhBg2FuxZlezsRO7
KEdOAuf2RmHISJuXj8SAxCpAsUw3w8ReyNdLa7DFRE/uhMDXgyGynWp7yJcUdFoa
itQfEo2Uf3dbTfVuqvHMi2FCrY/+Tn9+l2tj/XhERnGQ9akB/gmHruOrpgMcWZH/
XdRl7bJqxsQPItOB8l1AH/y7+dn4hFbf7AO/tf4tZQmzD0kBUPCixt/5GA5qSMU6
cRY2a+xRS1gs3twpkqscIFyoY1ttEyEQIHDjoLM=
-----END CERTIFICATE-----

3. Averiguar la ruta del java utilizado. Puede ser la misma del $JAVA_HOME. Incluir este certificado en el cacert


1
2
3
4
5
#Si el JDK es el mismo del $JAVA_HOME
sudo keytool -import -alias smtp.gmail.com -keystore $JAVA_HOME/lib/security/cacerts -file /ruta/al/fichero/gmail.cert

#Si el JDK no es el mismo del $JAVA_HOME
sudo keytool -import -alias smtp.gmail.com -keystore /ruta/al/jdk/lib/security/cacerts -file /ruta/al/fichero/gmail.cert

Nos preguntará el password del cacert que suele ser "changeit"
y contestar a Trust this certificate? [no]:  yes

5. Programa fuente para ejecutar

Hay muchas opciones mas simples como la de Dileep Guntanadugu, que son mas fáciles de entender. Pero ahí va mi versión.

Aquí está una simple propuesta para enviar un correo. El problema puede aparecer al utilzar las clases que se sirven para acceder al fichero de propiedades.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package openadmin.utils;

import java.util.Properties;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class MailUtils {

 public static Properties getEmailProperties(boolean isExecutedFromJar) throws Exception {
  if (isExecutedFromJar) return PropertiesUtils.getRelativeFromJarFileProperties("mail.properties");
  else return PropertiesUtils.getRelativeProperties("properties/mail.properties");
 } 
 
 public static Session getMailSession(Properties mailProps) {
  return Session.getInstance(
   mailProps,
            new javax.mail.Authenticator() {
    protected PasswordAuthentication getPasswordAuthentication() {
     return new PasswordAuthentication(
      mailProps.getProperty("username"),
                        mailProps.getProperty("password"));
                }
            });
 };
 
 
 public static Message getEmailMessage(Session mailSession, String fromEmail, String toCommaEmails, String subject, String text ) throws AddressException, MessagingException {
  Message message = new MimeMessage(mailSession);
        
  message.setFrom(new InternetAddress(fromEmail));
        message.setRecipients(
                Message.RecipientType.TO,
                
                InternetAddress.parse(toCommaEmails)
        );
        
        message.setSubject(subject);
        
        message.setText(text);        
        return message;
 };
 
 
 
 
 public static void sendEmail(Message message) throws MessagingException  {
  Transport.send(message);
 }
 
  

 /******************************************************************************
  * MAIN METHOD
  ******************************************************************************/
 public static void main(String args[]) {
  boolean isExecutedFromJar=false;
  try {
   Properties mailProps=getEmailProperties(isExecutedFromJar);
   Session mailSession=getMailSession(mailProps);
   
   Message mailMessage=getEmailMessage(mailSession, "ximodante@gmail.com", "destination01@gmail.com, destination02@gmail.com", "PRUEBA N-SIMA DE email ximodante", "This is the content of the n-esimo email de Ximo Dante...");
   
   
   sendEmail(mailMessage);
   
  } catch(Exception e) {
   e.printStackTrace();
  }
 }


6. Clases para acceder al fichero de propiedades


Se adjunta la clase PropertiesUtils y FileUtils para acceder al fichero de propiedades:


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
package openadmin.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;

import java.util.Properties;

public class PropertiesUtils {
 
 // Valid only in web
 public static String ResourcesPath=Thread.currentThread().getContextClassLoader().getResource("").getPath();
 
 
 /**
  * The properties path is referred relatively to resources path
  * @param filePath
  * @return
  * @throws FileNotFoundException
  * @throws IOException
  */
 public static Properties getRelativeProperties(String filePath) throws FileNotFoundException, IOException {
  Properties properties = new Properties();
       
  //String path = ResourcesPath + filePath;
  //System.out.println("PROPERTIES.PATH=" + path);
  //properties.load(new FileInputStream(path));
  
  
  System.out.println(filePath);
  //URL url = ClassLoader.getSystemResource("/resources/" + filePath);
  //URL url = ClassLoader.getSystemResource("/src/main/resources/" + filePath);+
  URL url = ClassLoader.getSystemResource(filePath);
  System.out.println(url);
  properties.load(url.openStream());
  
  
  for(Object o: properties.keySet()) System.out.println(o.toString() + "-->"+ properties.getProperty(o.toString()));
  
  return properties;
 }
 
 /**
  * Leemos la propiedades de una ruta absoluta.
  * OJO: Si queremos leer un fichero de propiedades "file.properties" que se encuentra 
  *      en la misma carpeta que el proyecto (o el jar ejecutable) :
  *   
  *      final File f = new File(PropertiesUtils.class.getProtectionDomain().getCodeSource().getLocation().getPath());
  *      
  *      String suffix=File.separator +"..";
     *      //myFile=f.getAbsolutePath()+ "/../../../file.properties" ;
     *      myFile=f.getAbsolutePath()+ StringUtils.repeat(suffix, 3) + File.separator + file.properties" ;
     *      Properties myProps=PropertiesUtils.getAbsoluteProperties(myFile);
     *      
  * @param filePath
  * @return
  * @throws FileNotFoundException
  * @throws IOException
  */
 public static Properties getAbsoluteProperties(String filePath) throws FileNotFoundException, IOException {
  Properties properties = new Properties();
       
  //String path = ResourcesPath + filePath;
  System.out.println(filePath);
  properties.load(new FileInputStream(filePath));
  
  
  
  
  for(Object o: properties.keySet()) System.out.println(o.toString() + "-->"+ properties.getProperty(o.toString()));
  
  return properties;
 }
 
 /**
  * Gets the folder where resides the executable jar
  * @return
  */
 /**
 public static String getJarFolderPath() {
  
  final File f = new File(PropertiesUtils.class.getProtectionDomain().getCodeSource().getLocation().getPath());
     String suffix=File.separator +"..";
     //jarFolder=f.getAbsolutePath()+ "/../../../"file.properties" ;
     String jarFolder=f.getAbsolutePath()+ StringUtils.repeat(suffix, 3) + File.separator;
     return jarFolder;
 }
 */
 public static Properties getRelativeFromJarFileProperties(String filePath) throws Exception {
  Properties properties = new Properties();
  
  //String myPath=getJarFolderPath()+filePath;
  String myPath=FileUtils.getJarContainingFolder() + File.separator + filePath;
  System.out.println(myPath);
  //System.out.println(PropertiesUtils.class.getResource(PropertiesUtils.class.getSimpleName() + ".class").getPath());
  //System.out.println(System.getProperty("user.dir"));
  properties.load(new FileInputStream(myPath));
  
  for(Object o: properties.keySet()) System.out.println(o.toString() + "-->"+ properties.getProperty(o.toString()));
  
  return properties;
 }
 
 
 public static void saveAbsoluteProperties(Properties properties, String filePath, String comments) throws FileNotFoundException, IOException {
  //String path = ResourcesPath + filePath;
  properties.store(new FileOutputStream(filePath), comments);
 }
 
 public static void saveRelativeFromJarFileProperties(Properties properties, String filePath, String comments) throws Exception {
  String myPath=FileUtils.getJarContainingFolder() + File.separator + filePath;
  System.out.println(myPath);
  properties.store(new FileOutputStream(myPath), comments);
 }
 
 public static void main(String[] args) throws FileNotFoundException, IOException{
  //String myFile="properties/last_fac.properties";
  String myFile="properties/application.properties";
  Properties myProps=getRelativeProperties(myFile);
  myProps.setProperty("A", "9999.888");
  myProps.setProperty("J", "1111.222");
  //for(Object o: myProps.keySet()) System.out.println(o.toString() + "-->"+ myProps.getProperty(o.toString()));
  //String myFile2="/home/eduard/last_fac2.properties";
  //saveAbsoluteProperties (myProps,myFile2, "ultima actualizacion");
  //myFile="../kk.properties";
        
         /*
               ws/pr/tg/cl/file  
         myFile="../../../../kk.properties";
         Properties myProps1=getRelativeProperties(myFile);
         System.out.println(myProps1.getProperty("prop2"));
         */
  /*
      System.out.println("-------------------------");
         //myFile="kk.properties";
      myFile="";
         String prefix="../";
         for (int i=0; i<15; i++) {
          System.out.println(myFile);
          URL url = ClassLoader.getSystemResource(myFile);
          System.out.println(url);
          System.out.println("-------------------------");
          myFile=prefix+myFile;
         }
        */
  /*
        final File f = new File(PropertiesUtils.class.getProtectionDomain().getCodeSource().getLocation().getPath()); 
        System.out.println(f.getAbsolutePath());
        myFile=f.getAbsolutePath();
        String sufix="/..";
        for (int i=0; i<15; i++) {
      System.out.println(myFile);
      URL url = new URL("file:"+myFile);
      System.out.println(url);
      url=new URL("file:"+myFile+"/kk.properties");
      System.out.println(url);
      System.out.println("-------------------------");
      myFile=myFile+sufix;
     }
     */
  System.out.println("----------------------------------------------");
  final File f = new File(PropertiesUtils.class.getProtectionDomain().getCodeSource().getLocation().getPath()); 
        System.out.println(f.getAbsolutePath());
        String suffix=File.separator + "..";
        myFile=f.getAbsolutePath();
        for (int i=0; i<10; i++) {
      System.out.println(myFile);
      String propFile=myFile + File.separator + "kk.properties";
      System.out.println(propFile);
      try {
       Properties myPrp=getAbsoluteProperties(propFile);
       System.out.println(myPrp.getProperty("prop1"));
      } catch (Exception e) {
       e.printStackTrace();
      }
      System.out.println("-------------------------");
      myFile=myFile+suffix;
     }
  
 }
}




 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package openadmin.utils;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.net.URLDecoder;
import java.security.CodeSource;

public class FileUtils {

 /**
  * Folder that contains jar file or folder that contains project folder
  * @return
  * @throws Exception
  */
 public static String getJarContainingFolder() throws Exception {
  Class<?> aClass=MethodHandles.lookup().lookupClass();
  CodeSource codeSource = aClass.getProtectionDomain().getCodeSource();

  File jarFile;

  if (codeSource.getLocation() != null) {
   jarFile = new File(codeSource.getLocation().toURI());
  } else { // It is not a jar file
   String path = aClass.getResource(aClass.getSimpleName() + ".class").getPath();
      String jarFilePath = path.substring(path.indexOf(":") + 1, path.indexOf("!"));
      jarFilePath = URLDecoder.decode(jarFilePath, "UTF-8");
      jarFile = new File(jarFilePath);
  }
  String s=jarFile.getParentFile().getAbsolutePath();
  System.out.println("S------>:" + s);
  if (s.endsWith(File.separator+"target")) { // Maven target directory for compiled classes
   s=s.substring(0, s.lastIndexOf(File.separator));
   s=s.substring(0, s.lastIndexOf(File.separator));
  } 
  return s;
 }
 
 public static byte[] readFile(String fileName) throws IOException {
  File file = new File(fileName);//filename should be with complete path
  FileInputStream fis = new FileInputStream(file);
  byte[] b = new byte[ (int) file.length()];
  fis.read(b);
  fis.close();;
  return b;
 }
 
 public static void writeToFile(String fileName, String myString) throws IOException {
  BufferedWriter writer = new BufferedWriter( new FileWriter( fileName));
  writer.write( myString);
  // do stuff 
  writer.close();
 }
 
 /**
  * test in main class
  * @param args
  */
 public static void main(String[] args) {
  try {
   System.out.println(getJarContainingFolder());
   System.out.println(System.getProperty("java.class.path"));
   System.out.println(System.getProperty("user.dir"));
   byte[] b=readFile("/home/eduard/Audit.0.log");
   String sb=new String(b);
   System.out.println(sb);
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

 }

}