miércoles, 29 de diciembre de 2010

Administración de usuarios/grupos en alfresco (I)

Debido a que la administración de usuarios y grupos en alfresco no ofrece demasiadas posibilidades, estuve indagando un poco en la forma de realizar tareas que eran muy repetitivas con ayuda de javascript. He de agredecer a Pedro Jimenez Caracuel que fue quien me ayudó en un comienzo con esto (estaba bastante perdido....).

De modo que voy a mostrar una serie de scripts que en mi caso son bastante útiles (algunos más que otros).

- anade_user_group.js (añade un usuario a un grupo, puede parecer una tontería, pero nos servirá para extenderlo a varios usuarios y ver de una manera más clara su funcionamiento):
//Variables a completar
var nombregrupo="Nombre del Grupo";
var user="Nombre del usuario";


var groupPrefix="GROUP_";
//Fichero de log
var logFile = space.childByNamePath("documento_salida.txt");
if (logFile == null)
{
logFile = space.createFile("documento_salida.txt");
}
logFile.content ="";
var log = "";
//Obtenemos el ScriptNode para el grupo
var srcGrpNode=people.getGroup(groupPrefix+nombregrupo);
//Obtenemos el ScriptNode para el usuario
var authority = people.getPerson(user);

if(authority && srcGrpNode) //Si el usuario y el grupo existen
{
var listado = people.getMembers(srcGrpNode);
var array_usuarios = [];
for (var i=0;i
{
array_usuarios[i]=(listado[i]).properties["{http://www.alfresco.org/model/content/1.0}userName"];
}
if (array_usuarios.indexOf(user)== -1) //Si el usuario no existe en el grupo, lo insertamos
{
people.addAuthority(srcGrpNode,authority);
log+="1.-añadido usuario:" + user + " al grupo " + nombregrupo;
}
else
{
log+="1.- El usuario: " + user + " ya esta asignado al grupo " + nombregrupo;
}

}
else //Ha salido porque el grupo o el usuario no existen
{
if (authority)
log+="1.- El grupo: " + nombregrupo + " no existe" ;
else
log+="1.- El usuario: " + user + " no existe" ;
}
logFile.content += log;



- anade_users_group.js (añade una lista de usuarios a un grupo):

//Variables a completar
var users = new Array ('usuario1','usuario2','usuario3');
var grupo="Nombre del grupo";

var groupPrefix="GROUP_";
//Fichero de log
var logFile = space.childByNamePath("documento_salida.txt");
if (logFile == null)
{
logFile = space.createFile("documento_salida.txt");
}
logFile.content ="";
var log = "";

var srcGrpNode=people.getGroup(groupPrefix+grupo);
if (srcGrpNode)
{
//Se obtiene un array con los miembros del grupo.
var listado = people.getMembers(srcGrpNode);
var array_usuarios = [];
for (var i=0;i
{
array_usuarios[i]=(listado[i]).properties["{http://www.alfresco.org/model/content/1.0}userName"];
}
log+="Grupo: " + grupo + "\n";
//Recorremos el array de usuario para insertarlos en el grupo
for(var i=0;i
{
var authority = people.getPerson(users[i]);
if(authority) //Si el usuario existe
{
if (array_usuarios.indexOf(users[i])== -1) //Y no existe aun en el grupo
{
people.addAuthority(srcGrpNode,authority);
log+="- añadido usuario:" + users[i] + " al grupo " + grupo + " \n";
}
else
{
log+="- El usuario: " + users[i] + " ya existe en el grupo " + grupo + "\n";
}
}
else
{
log+="- No existe usuario:" + users[i] + "\n";
}
}
}
else
{
log+="El grupo: " + grupo + " no existe.\n";
}
logFile.content += log;


- anade_user_group_list.js (añade un usuario a un listado de grupos):

//Variables a completar
var grupos = new Array ('grupo1','grupo2','grupo3');
var user="Nombre del usuario";
var groupPrefix="GROUP_";
var logFile = space.childByNamePath("documento_salida.txt");
if (logFile == null)
{
logFile = space.createFile("documento_salida.txt");
}
logFile.content ="";
var log = "";
var authority = people.getPerson(user);
if(authority)
{
for(var i=0;i
{
var srcGrpNode=people.getGroup(groupPrefix+grupos[i]);
if (srcGrpNode)
{
var listado = people.getMembers(srcGrpNode);
var array_usuarios = [];
for (var j=0;j
{
array_usuarios[j]=(listado[j]).properties["{http://www.alfresco.org/model/content/1.0}userName"];
}
if (array_usuarios.indexOf(user)== -1) //Si el usuario no existe en el grupo, lo insertamos
{
people.addAuthority(srcGrpNode,authority);
log+="- añadido usuario:" + user + " al grupo " + grupos[i] + " \n";
}
else
{
log+="- El usuario: " + user + " ya esta en el grupo " + grupos[i] + "\n";
}
}
else
{
log+="- El grupo: " + grupos[i] + " no existe.\n";
}
}//final for
}
else
{
log+="- No existe usuario:" + user + "\n";
}
logFile.content += log;

sábado, 4 de diciembre de 2010

Variables jvm

A raíz de una auditoría realizada sobre varios entornos de Alfresco, nos aconsejaron una serie de valores a indicar en la máquina virtual de java. Aprovecho para aclarar algunas de estas variables.

Una posible configuración:

JAVA_OPTS='-Xms1024m -Xmx1536m -Xmn256m -Xss128k -server -d64
-Xloggc:/opt/alfresco/tomcat/logs/gc.log -Xcheck:jni -Xconcurrentio -XX:
+UseParNewGC -XX:+CMSPermGenSweepingEnabled
-Dsun.rmi.dgc.server.gcInterval=600000
-Dsun.rmi.dgc.client.gcInterval=600000 -XX:SurvivorRatio=8
-XX:TargetSurvivorRatio=90 -XX:MaxTenuringThreshold=31 -XX:+UseParNewGC
-XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled'


Significado:

-server, solo puede haber una opción en la variable, de esta manera activamos Server Hotspot VM.

-d32/-d64, activa el modelo de datos de 32/64bits, por lo que en un entorno de pruebas puede confirmarse la mejor configuración para nuestros entornos con una JVM, recomendable siempre la última revisión (para solución de incidencias detectadas por el fabricante Sun), específica para nuestra plataforma y activando o desactivando el modelo que interese para aumentar estabilidad o rendimiento.

-Xloggc://logs/gc.log, podemos almacenar un log para las acciones del recolector de basura.

-Xcheck:jni, nos muestra comprobaciones adicionales de funciones jni.

-Xconcurrentio, activa opciones internas adicionales para la sincronización basada en hilos LWP que aumentan el rendimiento.

-Xmx1536m -Xms1024m -Xmn256m, mediante la optimización de estos tres valores especificamos la memoria total de objetos heap inicial y máxima y la memoria young generation, donde se almacenan todos los objetos de la aplicación web desde su primera carga en memoria.

-Xss128k, podemos especificar memoria de pila para cada hilo, si hay problemas relacionados se recomienda aumentar a 256k.

-XX:SurvivorRatio=8, el índice de supervivencia es la proporción entre el espacio de objetos nuevos (eden) y el espacio de supervivientes de la sección de objetos jóvenes del almacenamiento dinámico. Al aumentar este valor se optimiza la JVM para las aplicaciones en las que se crean muchos objetos y se conservan pocos objetos.

-XX:TargetSurvivorRatio=90, permite ocupar el 90% del espacio de supervivientes en lugar del 50%, permitiendo mejor utilización del espacio de memoria superviviente.

-XX:MaxTenuringThreshold=31 -XX:MaxPermSize=192m, con estos valores aumentaremos el rendimiento global de nuestra instalación.

-XX:+UseParNewGC, activa recolección de basura en paralelo en la memoria young generation.

-XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled, con estos valores activamos la recolección de basura concurrente CMS para la memoria permanente, siendo altamente recomendable.


* Propiedades de sistema, con el indicador -D=”valor” indicamos muchas características:


-Dsun.rmi.dgc.server.gcInterval=600000
-Dsun.rmi.dgc.client.gcInterval=600000, con estos valores podemos establecer el intervalo de tiempo en milisegundos para la ejecución del recolector de basura (10 minutos) en la máquina hotspot que hemos elegido.

Aclaración sobre algunas variables:

-Xms1536m : Tamaño inicial de Java heap, por defecto: 4MB
-Xmx1536m : Tamaño máximo de Java heap, por defecto: de 16 a 512 MB

Se suele recomendar que estas dos variables tengan el mismo valor, con objeto de no hacer trabajar a la jvm para agrandar este espacio (ya que le estamos indicando el tamaño que deberá tener desde un principio).

-XX:PermSize=512m : Tamaño inicial de la región permanente
-XX:MaxPermSize=512m : Tamaño máx de la región permanente, por defecto
64MB

Decompilador Java

Por si tenéis que decompilar algún class de java....

http://jdec.sourceforge.net/

Lo descomprimís en alguna carpeta y le dais permiso de ejecución a su contenido, luego ejecutáis ./Jdec-UI.sh

Hay unos parámetros que se tienen que cambiar, una vez abierta la aplicación, presionad Alt+Mays+A, y en el listado podéis poner algo así:

Output_Mode
file
Log_Mode
file
Output_Folder_Path
/home/rafa/Escritorio
Output_File_Extension
java
LOG_LEVEL
2
Log_File_Path
/opt/jdec/log.txt
UI_LOG_FILE_PATH
/opt/jdec/log2.txt
JAVA_CLASS_FILE
/opt/jdec/
JAR_FILE_PATH
/opt/jdec/
Show_Imports
true
JDec_Option
dc
Temp_Dir
/home/rafa/Escritorio
Inner_Depth
2
Inline_Anonymous_Inner_Class_Content
false
Interpret_Exception_Table
false
Interpret_Non_ASCII
true
Force_Non_ASCII
true
Skip_Class_Version_Check
true
int_local_var_prefix
aInt
byte_local_var_prefix
aByte
short_local_var_prefix
aShort
char_local_var_prefix
aChar
float_local_var_prefix
aFloat
double_local_var_prefix
aDouble
long_local_var_prefix
aLong
boolean_local_var_prefix
aBoolean
string_local_var_prefix
aString
other_local_var_prefix
other

Volcado de memoria (hprof)

Debido a los errores de memoria cada vez más frecuentes (tipo java.lang.OutOfMemoryError: PermGen space failure) en las aplicaciones java que administramos en entornos de producción y a que en la mayoría de los casos se debe a un error de programación, java nos da la posibilidad de añadir una variable para realizar un volcado de la memoria.

Con esto obtenemos en un fichero una copia exacta del contenido de la memoria de la jvm en el momento del error. Este fichero nos servirá para tener una base sobre la cual estudiar el origen del problema (hay herramientas para procesar este tipo de ficheros, como jvisualvm).

Dicha variable sería:

-XX:HeapDumpPath=/ruta/donde/guardar/el/fichero/ -XX: +HeapDumpOnOutOfMemoryError


Sólo es factible sobre la versión de java 1.6 (por lo que no se podría aplicar a todas las aplicaciones).

Este fichero puede ser analizado con distintas herramientas: JVisualVM, Eclipse Memory Analyzer...

Si además quieres que ser avisado por correo cuando esto se produzca, se puede establecer en el cron (cada 5 min por ejemplo) que lance un script parecido al siguiente (este está hecho en python):

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

import os, string, datetime, time, smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
from email import Encoders

#Variables
servidor_de_correo = "servidor de correo"
emisor= "maquina@dominio"

#Funcion para el envio de correo
def sendMail(to, subject, text, server=servidor_de_correo):
assert type(to)==list
fro = emisor

COMMASPACE = ', '
msg = MIMEMultipart()
msg['From'] = fro
msg['To'] = COMMASPACE.join(to)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject

msg.attach( MIMEText(text) )


smtp = smtplib.SMTP(server)
smtp.sendmail(fro, to, msg.as_string() )
smtp.close()


#Funcion de registro de log
def log (texto):
now = datetime.datetime.now()
f = open(fichero_log, 'a')
f.write(str (now.ctime()) + ' -> ' + texto + '\n')
f.close()

#Variables
cuenta_de_correo = "cuenta de correo donde mandar el aviso"
fichero_pid = "/var/run/tomcat5.pid"
f = open(fichero_pid,"r")
pid = str(f.read()).strip()
fichero_hprof = "java_pid" + pid + ".hprof"
fichero_log = "/ruta_fichero_log/comprueba.log"
existe = os.path.isfile("/tmp/" + fichero_hprof)
if existe:
log("Se ha creado el volcado de memoria.")
sendMail(
["cuenta_de_correo"],
"Volcado de memoria","Se ha producido un error de memoria provocando el volcado en el fichero " + fichero_hprof
)

else:
log("No se ha producido error de memoria ni volcado.")



El script simplemente estará revisando la existencia del fichero de volcado, que suele denominarse:

java_pid15546.hprof

donde 15546 es el pid del tomcat donde hemos configurado la variable para el hprof.

En cuanto detecte que existe, mandará un correo a la cuenta especificada.

alf_bootstrap_lock

Se trata de un error muy típico de Alfresco (al menos en versiones 2.1) cuando se produce alguna complicación de actualización o un reinicio inesperado. Es una medida de seguridad que deja bloqueado el sistema mostrando el siguiente mensaje de error:

Caused by: org.alfresco.error.AlfrescoRuntimeException: A previous schema upgrade failed. Revert to the original database before attempting
the upgrade again.

Si se ha producido por algún reinicio inesperado, la solución es simplemente elminar la tabla:

alf_bootstrap_lock

Tras esto, arrancaremos alfresco sin ningún problema.

Obtener informacion de repositorios a través de los metadatos .git publicados por error

 A raiz de CTF realizado recientemente, me ha parecido interesante publicar este post sobre los errores de seguridad que se encuentran en mu...