Tag Archives: Uncategorized

Alfresco Summit 2013 – Barcelona

Finalmente pude dar las dos “charlas relámpago” que tenía previstas y que tanto miedo me daban por tener que ser en inglés. Una sobre Alfviral para poder escanear documentos en busca de virus y software maligno y la otra (Alfresco Audio Transcriber) sobre la indexación de audio mediante la extracción y transcripción de palabras a texto. Ambos proyectos son pilotos funcionales y por tanto no eran charlas teóricas.

Sobre el Summit en general, muy bien, montado al siempre estilo Alfresco y aunque el primer día no estuve (Party and Pool) me consta que fue un gran comienzo. Vi a personas y sobre todo amigos que hacía tiempo no veía y sobre todo pude constatar que Alfresco como sistema de gestión documental está muy vivo y avanza, quizás, hasta demasiado rápido 😉

Como anécdota deciros que en una ruleta que había con premios, sobre todo camisetas, bolígrafos y chapas, había dos regalos más grandes, un escáner y una mochila, pues bien, tiré y… ¡mochila! aquí os dejo una imagen 🙂

Y aquí os dejo también las presentaciones.

[slideshare id=28013196&w=427&h=356&style=border-width: 1px 1px 0; border: 1px solid #CCC; margin-bottom: 5px;&sc=no]
[slideshare id=28013519&w=427&h=356&style=border-width: 1px 1px 0; border: 1px solid #CCC; margin-bottom: 5px;&sc=no]

Espero poder ir al del año que viene, sea donde sea…  😉

Protección antivirus en Alfresco ECM (tercera parte)

Finalmente escribo esta tercera parte porque quedaron algunos puntos pendientes y me gustaría comentarlos.
El impacto que se produce al realizar llamadas a un comando o programa al sistema operativo desde Java es muy alto, solo estaría recomendable para sitios donde no haya una gran cantidad de subida de documentos o donde esta no sea  masiva.
La primera opción, la “desatendida” que escanea directamente el repositorio es menos intrusiva y puede ser programada además mediante una entrada en la crontab.
Existe una tercera forma dentro del sistema de escaneo bajo demanda, aunque realmente no es así, sino que es escaneado cuando el evento OnContentUpdate o OnContentRead es disparado. Esta forma es mediante el envío de la información al antivirus en forma de “data stream” o flujo de datos hacia un puerto determinado.
En este caso ClamAV puede ejecutarse en modo “demonio” con el comando clamd y podemos configurarlo para que escuche solicitudes de datos desde un puerto determinado de forma que enviaremos a este el documento para que sea escaneado y se nos devuelva un código de verificación.
Para configurar clamd se realiza en el fichero clamd.conf (generalmente en /usr/local/etc aunque dependerá de la distribución Linux que tengamos). 
De esta forma podemos cambiar algunos valores que por defecto están algo bajos:
/usr/local/etc/clamd.conf:
[…]
TCPSocket 3310
MaxConnectionQueueLength 30
StreamMaxLength 50M
MaxThreads 50
[…]
Ya solo queda modificar la clase para que envíe el flujo de datos hacia el puerto indicado y según nos devuelva el resultado así actuar. En mi caso he dejado la llamada directa al comando clamscan así como esta otra forma para que pueda seleccionarse la más adecuada según cada caso. 
También he realizado algunas modificaciones como que se pueda seleccionar qué evento se quiere que sea disparado (update, read, o ambos)  así como los nuevos valores de configuración necesarios.
La única acción que se realiza sigue siendo la asignación del aspecto “Infected”. Así se ha dejado para no realizar más acciones dentro de la propia lógica de la clase de detección y dejar este trabajo al propio Alfresco. Para ello solo habrá que crear una regla donde se necesite que contenga una acción sobre todo el contenido que se encuentre con este aspecto. Las acciones pueden ir desde enviar un mensaje de correo electrónico al propietario del documento, al administrador, etc. como mover el documento a un espacio de cuarentena o de infectados,… en fin, cada uno que elija las acciones según la política de seguridad y aplicación que se esté dando a Alfresco.
Para no dejar más código aquí, he creado un proyecto en Google Code para que pueda bajarse directamente el AMP o los fuentes de forma más fácil.
El proyecto está en: http://code.google.com/p/alfviral
El SVN es: “http://alfviral.googlecode.com/svn/trunk/ alfviral-read-only”
Si alguno quiere colaborar, como siempre, estaré encantado.  😉


Swithun Crowe ha realizado una “custom action” para poder escanear un documento a petición. Es otra idea más y esta es totalmente “bajo demanda” ya que es mediante una acción. Como es otra posibilidad se podría adaptar perfectamente a “Alfresco Virus Alert” y tenerla como otra posibilidad más dentro del marco de seguridad y protección de antivirus para Alfresco.

La entrada en la wiki es: http://wiki.alfresco.com/wiki/Antivirus

Protección antivirus en Alfresco ECM (segunda parte)

En la primera parte se vio como implementar una solución de antivirus escaneando todo el repositorio y que podía programarse por ejemplo en la “crontab” del sistema operativo.
Otra forma de realizar la detección de un virus que suba a Alfresco es mediante un escaneo “on-demand”, es decir, bajo demanda, y en este sentido cuando sea actualizado el contenido del documento. Dentro de las posibilidades que tenemos, de realizarlo de esta forma, podemos enviar un stream de datos del documento hacia el antivirus o bien ejecutar el propio antivirus pasándole exactamente el fichero a escanear. Ambas soluciones son posibles en ClamAV y en cualquiera de los dos casos el antivirus devuelve un código de error que será 0 si no hay infección y distinto si ha sido detectado, el fichero no existe, etc.
Por otra parte, Alfresco ECM disponde de las llamadas “policies” para ejecutar clases de Java o scripts de JavaScript cuando se produce algún “evento”. De todos los posibles tanto a nivel de contenido y de nodos, vamos a usar los siguientes:
Interface
Method
org.alfresco.repo.content.ContentServicePolicies
onContentUpdate
onContentRead
Usando OnContentUpdate y OnContentRead se puede lanzar la detección cuando sean leídos los documentos y/o cuando son actualizados. En el ejemplo se va a utilizar el evento OnContentUpdate para que cuando se realice una actualización de este (en el momento en el que se hace un COMMIT) se lance el antivirus y si este devuelve un código de error se añada un aspecto “infected” con dos propiedades, la fecha de detección y si ha sido “limpiado”.

Primero definimos los beans que usamos en el “behavior”: alfviral-behavior-context.xml

    
       
            true
        property>
       
           
                classpath:alfresco/extension/alfviral-behavior.properties
           
       
   
   
    <bean id="AlfViralBehavior" class="com.fegor.alfresco.behavior.OnUpdateReadScan"
        init-method=”init”>
       
           
       
       
           
       
       
           
       
       
            ${alfviral.command}
       
       
            ${dir.contentstore}
                  
    bean>

Seguidamente del fichero de propiedades: alfviral-behavior.properties

alfviral.command=/usr/bin/clamscan

Montamos el modelo de datos: alfviral-model-context.xml

       
   
       
           
                alfresco/extension/alfviralModel.xml
           
       
     

El modelo: alfviralModel.xml

     
   Alfresco Virus Alarm Model
   Fernando González Ruano (twitter://fegorara)
   1.0
  
     
     
  
  
     
  
   
       
            Infected
           
               
                    d:date
                    false
               
               
                    d:boolean
                    false
               
           
       
   

La parte para el cliente web del browser: web-client-config-custom.xml


  
     
        
        
     
  
  
     
        
     
  

El fichero de propiedades para las etiquetas: webclient.properties

ava_date=Fecha de detecciu00F3n
ava_clean=u00BFDesinfectado?

Y por último la clase java: OnUpdateReadScan.java

package com.fegor.alfresco.behavior;

import java.io.IOException;
import java.io.Serializable;
import java.util.*;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.repo.content.ContentServicePolicies;
import org.alfresco.repo.policy.Behaviour;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.apache.log4j.Logger;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.ContentReader;

/**
 * Integrates antivirus scanning documents for alfresco
 *
 * Implements the policies of “OnContentUpdate” and “OnContentRead”.
 *
 * @author Fernando González Ruano (fegor)
 */
public class OnUpdateReadScan
    implements ContentServicePolicies.OnContentUpdatePolicy,
                ContentServicePolicies.OnContentReadPolicy
{
    private Logger logger = Logger.getLogger(OnUpdateReadScan.class);

    // behaviours
    private Behaviour onContentUpdate;
    private Behaviour onContentRead;
   
    // dependencias
    private PolicyComponent policyComponent;
    private ContentService contentService;
    private NodeService nodeService;
   
    // configuration
    private List command;
    private String store;
    private final String NAMESPACE_ALFVIRAL_CONTENT_MODEL = “alfviral.model”;
    private final QName ASPECT_INFECTED = QName.createQName(NAMESPACE_ALFVIRAL_CONTENT_MODEL, “infected”);
    private final QName PROP_INFECTED_DATE = QName.createQName(NAMESPACE_ALFVIRAL_CONTENT_MODEL, “date”);
    private final QName PROP_INFECTED_CLEAN = QName.createQName(NAMESPACE_ALFVIRAL_CONTENT_MODEL, “clean”);  
   
    Map aspectValues = new HashMap();

    // método de inicio
    public void init ()
    {
        if (logger.isDebugEnabled()) logger.debug(“Start OnUpdateReadScan.”);
       
        // crear behaviours
        this.onContentUpdate = new JavaBehaviour(this,
                “onContentUpdate”,
                NotificationFrequency.TRANSACTION_COMMIT);
       
        this.onContentRead = new JavaBehaviour(this,
                “onContentRead”,
                NotificationFrequency.TRANSACTION_COMMIT);
       
        // binding “policies”
        this.policyComponent.bindClassBehaviour(QName.createQName
                (NamespaceService.ALFRESCO_URI,
                “onContentUpdate”),
                “cm:content”, this.onContentUpdate);
       
        this.policyComponent.bindClassBehaviour(QName.createQName
                (NamespaceService.ALFRESCO_URI,
                “onContentRead”),
                “cm:content”, this.onContentRead);
    }
   
    @Override
    public void onContentUpdate (NodeRef nodeRef, boolean flag)
    {
        ContentReader contentReader = this.contentService.getReader(nodeRef, ContentModel.PROP_CONTENT);
       
        // full path of file
        String contentUrl = contentReader.getContentUrl();
        String contentPath = contentUrl.replaceFirst(“store:/”, this.store);
       
        if (logger.isDebugEnabled())
        {
            logger.debug(“(Update) “+this.command+” “+contentPath);
        }
        else if (logger.isInfoEnabled())
        {
            logger.info(“(Update) Llamando al script de escaneo de virus para “+nodeRef.getId());
        }
       
        try
        {
            // execute command “antivir contentPath”
            this.command.add(contentPath);
            ProcessBuilder pb = new ProcessBuilder(this.command);
            Process process = pb.start();
           
            int intResult = process.waitFor();

            logger.debug(“(Update) Resultado del escaneo: “+intResult);
           
            // if result is not 0, file is infected
            if (intResult != 0)
            {
                logger.info(“ALERTA ** El fichero: “+contentReader.getContentUrl()+” está infectado. **”);
               
                // add aspect Infected is not assigned              
                if (!nodeService.hasAspect(nodeRef, this.ASPECT_INFECTED))
                {  
                    this.aspectValues.put(this.PROP_INFECTED_DATE, new Date());
                    this.aspectValues.put(this.PROP_INFECTED_CLEAN, false);               
                    nodeService.addAspect(nodeRef, this.ASPECT_INFECTED, this.aspectValues);
                   
                    // TODO Other actions… quarantine, delete, send email, etc.
                }
                else
                {
                    logger.debug(“Este fichero se detectó como infectado anteriormente.”);                   
                }
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }
   
    @Override
    public void onContentRead (NodeRef nodeRef)
    {
        // TODO Actions for read content
    }
   
    // Setters…
    public void setPolicyComponent(PolicyComponent policyComponent)
    {
        this.policyComponent = policyComponent;
    }
   
    public void setContentService(ContentService contentService)
    {
        this.contentService = contentService;
    }
   
    public void setNodeService(NodeService nodeService)
    {
        this.nodeService = nodeService;
    }
   
    public void setStore(String store)
    {
        this.store = store;
    }
   
    public void setCommand(List command)
    {
        this.command = command;
    }   
}

A partir de aquí…

Esto es solo un ejemplo de la multitud de acciones y configuraciones que pueden realizarse en este sentido, por ejemplo, falta el código para el evento OnContentRead, falta alguna acción de mover los documentos infectados a algún espacio de cuarentena, avisar al administrador y al usuario de la detección, internacionalizar, etc. pero creo que es un buen punto de partida para que cada cual adapte esta solución a su manera. No os lo voy a dar todo hecho ¿verdad?… 😉

Finalmente dos capturas de pantalla:


Un extracto del log (poniendo en el log4j.properties el valor log4j.logger.com.fegor=debug):

 

10:44:16,141 User:admin DEBUG [alfresco.behavior.OnUpdateReadScan] (Update) [/usr/local/bin/clamscan, /home/alfresco/enterprise/alf_data/contentstore/2010/12/30/8/3/30a7961f-cdef-4410-9ba0-ca94a8542d03.bin, /home/alfresco/enterprise/alf_data/contentstore/2010/12/30/10/42/4a6a4884-c14e-4b24-ae22-c1e2a9839593.bin, /home/alfresco/enterprise/alf_data/contentstore/2010/12/30/10/42/4a6a4884-c14e-4b24-ae22-c1e2a9839593.bin] /home/alfresco/enterprise/alf_data/contentstore/2010/12/30/10/44/b9b5c69c-cff5-400e-9f63-4888ca745749.bin
10:44:20,125 User:admin DEBUG [alfresco.behavior.OnUpdateReadScan] (Update) Resultado del escaneo: 1
10:44:20,126 User:admin INFO  [alfresco.behavior.OnUpdateReadScan] ALERTA ** El fichero: store://2010/12/30/10/44/b9b5c69c-cff5-400e-9f63-4888ca745749.bin está infectado. **

Y algo de bibliografía que podéis consultar:

Libro: Alfresco Developer Guide
Autor: Jeff Potts
ISBN: 978-1-847193-11-7

Web de Jeff Potts: http://ecmarchitect.com/
Wiki de Alfresco: http://wiki.alfresco.com/wiki/Policy_Component
Web de ClamAV: http://www.clamav.net/lang/en/

Compilar Alfresco Community en MacOS X


Instalar Eclipse:

Lo primero es instalar Eclipse de http://www.eclipse.org siguiendo el instalador para MacOS X.

Instalar Alfresco desde el instalador:

Lo segundo, como recomendación para copiar todas las utilidades que necesitamos sin necesidad de bajarselas de las respectivas webs, es instalar la versión de Alfresco con instalador que haya para MacOS X desde http://www.alfresco.com

Luego, copiamos el directorio tomcat que hay en el Alfresco instalado en la ubicación donde queremos dejar el resultado de la compilación, en mi caso en /Users/fegor/Documents/workspace/tomcat

Para la configuración podemos aprovechar para copiar un fichero de configuración de ejemplo que es desplegado en el primer arranque (por cierto, en la instalación se puede usar la base de datos por defecto que es Derby ya que la que usaremos posteriormente es MySQL)

cd /Users/fegor/Documents/workspace/tomcat
cp webapps/alfresco/WEB-INF/classes/alfresco-global.properties.sample shared/classes/alfresco-global.properties

Se modifica este fichero con los valores correspondientes:

dir.root=/Users/fegor/Documents/workspace/tomcat/alf_data
db.username=alfresco
db.password=alfresco
db.driver=org.gjt.mm.mysql.Driver
db.url=jdbc:mysql://localhost/alfresco

Y se añaden las líneas para localizar las diferentes herramientas necesarias (hay que verificar que los paths son los correctos)

ooo.exe=/Applications/OpenOffice.org.app
ooo.user=${dir.root}/oouser
img.root=/Users/fegor/Documents/workspace/tomcat/ImageMagick-6.5.9
swf.exe=/Users/fegor/Documents/workspace/tomcat/pdf2swf

Instalando OpenOffice:

Si se va a utilizar OpenOffice para más cosas que la conversión de documentos en Alfresco, lo mejor es instalarlo de forma estándar descargándolo de http://porting.openoffice.org/mac/

Instalando pdf2swf:

La forma que he visto más sencilla es instalar la versión full para MacOS X (por ejemplo la versión 3.1 SP2 tiene instalador para MacOS X) y luego copiar el ejecutable a nuestra compilación:

cp /Users/fegor/Alfresco/bin/pdf2swf /Users/fegor/Documents/workspace/tomcat

Instalando ImageMagick:

Para la instalación de ImageMagick se puede copiar también el directorio de la instalación full de Alfresco o bien descargarlo de http://www.imagemagick.org/script/binary-releases.php

En esta página existen dos formas de instalarlo, una mediante MacPorts (http://www.macports.org/) y otra bajándose directamente el paquete en tar.gz (http://www.imagemagick.org/download/binaries/ImageMagick-x86_64-apple-darwin10.2.0.tar.gz). He preferido bajar el paquete, descomprimirlo y ponerlo directamente dentro de la instalación de tomcat (Alfresco) ya que solo va a usarse para esto.

Por tanto:

tar xvzf ImageMagick-x86_64-apple-darwin10.2.0.tar.gz
mv ImageMagick-6.5.9/ /Users/fegor/Documents/workspace/tomcat/

Instalando MySQL para Mac:

Se puede descargar de la propia http://www.mysql.com y usar las instrucciones de instalación siguientes: http://dev.mysql.com/doc/refman/5.0/es/mac-os-x-installation.html

Una vez instalada y arrancada hay que crear la base de datos alfesco con usuario alfresco y password alfresco.

mysqladmin -u root create alfresco
mysql -u root -e “grant all on alfresco.* to ‘alfresco’@’localhost.localdomain’ identified by ‘alfresco’ with grant option;”
mysql -u root -e “grant all on alfresco.* to ‘alfresco’@’localhost’ identified by ‘alfresco’ with grant option;”

Bajar los fuentes de Alfresco:

Se puede seguir el siguiente enlace en caso de problemas, http://wiki.alfresco.com/wiki/Alfresco_SVN_Development_Environment y en concreto para eclipse el siguiente http://wiki.alfresco.com/wiki/Alfresco_on_Eclipse

Instalar Sysdeo para usar (arrancar y parar) los servidores de aplicaciones tomcat, desde http://www.eclipsetotale.com/tomcatPlugin/tomcatPluginV321.zip.

Solo hay que descomprimirlo dentro del directorio plugins, en mi caso en /Applications/eclipse/plugins

Ejecutar eclipse y configurar en Eclipse -> Preferences -> Tomcat el lugar donde está el tomcat, la JVM y añadir los siguientes parámetros a la JVM (JVM Settings):

-server
-Xss256k
-Xms256m
-Xmx512m
-XX:NewSize=128M
-XX:MaxPermSize=128M

Y en Classpath: hay que introducir el camino a las classes de tomcat:

/Users/fegor/Documents/workspace/tomcat/shared/classes

Ahora configuramos Ant desde Eclipse -> Preferencias -> Ant -> Runtime -> Properties

Y añadir las siguientes propiedades:

env.TOMCAT_HOME = /Users/fegor/Documents/workspace/tomcat
env.APP_TOMCAT_HOME = /Users/fegor/Documents/workspace/tomcat
env.VIRTUAL_TOMCAT_HOME = /Users/fegor/Documents/workspace/tomcat/virtual-tomcat

Instalar Subclipse:

En nuestro eclipse: Help -> Install new software… (botón Add)

Name: Subclipse 1.6.x (Eclipse 3.2+)
Location: http://subclipse.tigris.org/update_1.6.x

Y proceder a marcar las casillas e instalar (botón Next…).

Configurar el proyecto de Alfresco en SVN:

1) Ir a File -> New -> Project
2) Seleccionar el asistente SVN y “Checkout Projects with Subversion”
3) En “Create a new repository location”
4) Seleccionar la URL: “svn://svn.alfresco.com” (*)
5) Por último la carpeta Alfresco y pulsar Finish.

Importar el proyecto Alfresco siguiendo los siguientes pasos:

1) File -> Import
2) General -> Existing Projects Into Workspace -> Next
3) Seleccionar HEADrootproyecto
4) Finish

Crear el proyecto Ant:

1) Seleccionar New -> Project. Bajo “General” elegir “Project” y en el nombre poner “ant”
2) Pulsar botón derecho del ratón en el proyecto y seleccionar New -> File
3) Cuando aparezca el nuevo diálogo, pulsar en el botón de Advanced y seleccionar “Link to file in the file system”
4) Ir al fichero build.xml localizado en el directorio HEADroot
5) Para construir el proyecto, ponerse encima de Build.xml con el botón derecho del ratón y seleccionar Run As… -> Ant Build

Nota: Si se reciben errores en la compilación, hay que elegir java-6-sun en lugar de java-6-opensdk en Preferences -> Java -> Installed JREs.

…y eso es todo. Para muestra “un botón”, digo unas imágenes 😉

Resultado de la compilación:


Y la versión resultante:

(*) Me confundí con la URL, la siguiente funciona correctamente: http://svn.alfresco.com/repos/alfresco-open-mirror/alfresco

Crear una acción para enviar documentos a un ContentStore distinto

Tras la conversación con Toni (blyx) sobre el aspecto storeSelector en Alfresco ECM 3.2 y las distintas posibilidades que podemos usar para automatizar el movimiento de documentos. Se me ocurre una que puede ser crear una acción para que mueva determinados documentos a, por ejemplo, una NAS, pero de forma interactiva.

Lo primero es configurar el nuevo “storeNAS” donde estará montada la NAS:

Fichero: storeNAS-content-store-selector-context.xml (siempre dentro de alfresco/extension)



<?xml version=’1.0′ encoding=’UTF-8′?>

<!DOCTYPE beans PUBLIC ‘-//SPRING//DTD BEAN//EN’ ‘http:// www.springframework.org/dtd/spring-beans.dtd’>

<!– Define the new file stores —>

<beans>

<bean id=”fileContentStoreNAS” class=”org.alfresco.repo.content.filestore.FileContentStore”>

<constructor-arg>

<value>${dir.root}/storeNAS</value>

</constructor-arg>

</bean>

<!– Declare the mapping between store names and store instances —>

<bean id=”storeSelectorContentStore” parent=”storeSelectorContentStoreBase”>

<property name=”defaultStoreName”>

<value>default</value>

</property>

<property name=”storesByName”>

<map>

<entry key=”default”>

<ref bean=”fileContentStore” />

</entry>

<entry key=”storeNAS”>

<ref bean=”fileContentStoreNAS” />

</entry>

</map>

</property>

</bean>

<!– Point the ContentService to the ‘selector’ store —>

<bean id=”contentService” parent=”baseContentService”>

<property name=”store”>

<ref bean=”storeSelectorContentStore” />

</property>

</bean>

<!– Add the other stores to the list of stores for cleaning —>

<bean id=”eagerContentStoreCleaner” class=”org.alfresco.repo.content.cleanup.EagerContentStoreCleaner” init-method=”init”>

<property name=”eagerOrphanCleanup” >

<value>${system.content.eagerOrphanCleanup}</value>

</property>

<property name=”stores” >

<list>

<ref bean=”fileContentStore” />

<ref bean=”fileContentStoreNAS” />

</list>

</property>

<property name=”listeners” >

<ref bean=”deletedContentBackupListeners” />

</property>

</bean>

</beans>

Ahora necesitamos configurar nuestra acción, eso lo realizamos en el fichero web-client-config-custom.xml y además de la acción configuramos también el aspecto:

Fichero: web-client-config-custom.xml



<config evaluator=”aspect-name” condition=”cm:storeSelector”>

<property-sheet>

<show-property name=”cm:storeName” />

</property-sheet>

</config>



<config evaluator=”string-compare” condition=”Action Wizards”>

<aspects>

<aspect name=”cm:storeSelector”/>

</aspects>

</config>

<config>

<actions>

<!– Launch Add Aspect Dialog —>

<action id=”add_store”>

<label>Add Store</label>

<image>/images/icons/add.gif</image>

<action>dialog:addStore</action>

</action>

<!– Add action to more actions menu for each space —>

<action-group id=”space_browse_menu”>

<action idref=”add_store” />

</action-group>

</actions>

</config>

Para crear nuestra propia acción asignamos al mismo fichero web-client-config-custom.xml la acción con la llamada al script:

<config>

<actions>

<action id=”sendStoreNAS”>

<label>Enviar a NAS</label>

<image>/images/icons/new_edition_icon.gif</image>

<script>/Company Home/Data Dictionary/Scripts/ContentStoreNAS.js</script>

<params>

<param name=”id”>#{actionContext.id}</param>

</params>

</action>

<action-group id=”document_browse_menu”>

<action idref=”sendStoreNAS” />

</action-group>

</actions>

</config>

Y por último el código en jscript que subiremos a Empresa/Diccionario de datos/Scripts:

Fichero: ContentStoreNAS.js

var document = search.findNode( “workspace://SpacesStore/” + args[“id”]);

document.addAspect(“cm:storeSelector”);

document.properties[“cm:storeName”] = “storeNAS”;

document.save();

var ret = “<html>” +

<title></title>” +

<body>” +

<script>history.back();</script>” +

</body>” +

</html>“;

ret;

Ahora para cada documento podemos enviarlo al ContentStore desde el menú emergente de más acciones.



Todavía queda alguna forma más para tratar los documentos con distintos almacenes, según las necesidades y requisitos, todo es cuestión de ponerse…

Usando WebDrive como cliente WebDAV con Alfresco

De muchos es sabido que no todos los protocolos se comportan igual ante servidores que ofertan sus servicios sobre clientes heterogéneos. Es el caso del cliente de Windows para WebDAV y sobre todo cuando se accede a servidores de WebDAV como el ofrecido por Alfresco ECM.

Uno de los problemas de crear un acceso vía WebDAV desde Windows XP a Alfresco ECM 3.2 es que, por ejemplo, cuando se intenta abrir un documento en formato PDF desde el mismo recurso compartido y el lector por defecto es el Acrobat Reader, se produce un error.

… creamos el acceso desde el cliente WebDAV de Windows:

… abrimos directamente el documento PDF… ¡error!


Parece ser que el problema puede ser de Alfresco, del cliente WebDAV de Windows o del propio Acrobat Reader… bien, para descartar que sean el primero y el tercero, lo mejor es buscar un programa de terceros que haga de cliente WebDAV y probar sobre este. Para ello he descargado el programa WebDrive (http://www.webdrive.com/) que permite crear unidades y conectar por WebDAV, sFTP, FTP, etc.

Una vez descargado de la web (la versión trial/free) e instalado (siguiente, siguiente, etc.) se procede a crear una unidad con los datos de conexión con el servicio WebDAV de Alfresco:

… volvemos a probar abrir el documento PDF desde este nuevo recurso y… ¡voilá!


A priori, parece que este programa se comporta mejor con servidores WebDAV, al menos con el ofrecido por Alfresco ECM.

Nota: He probado también con tildes y eñes y no ha dado error al acceder.

Personalizar variables de arranque de Java en Apache-Tomcat

En muchas ocasiones utilizamos instancias de Apache-Tomcat en las que utilizamos las variables JAVA_OPTS con valores similares. Para poder configurar esta parte de la instalación podemos usar un fichero que generalmente no viene creado dentro del propio Apache-Tomcat pero que, si es encontrado se usa, llamado setenv.sh (sistemas unix) o setenv.bat (sistemas windows). De esta forma podemos pasar este fichero entre nuestras distintas instalaciones con unas básicas modificaciones.

El fichero que uso actualmente para mis instalaciones de Alfresco bajo Apache-Tomcat contiene las variables necesarias para optimizar el funcionamiento de la JVM de Sun.

Aquí está el contenido de dicho fichero con sus respectivos comentarios:

# Entorno de ejecución
# 9/06/2009 (Fernando González)

# Variables
LD_LIBRARY_PATH=/usr/local/apr/lib
JAVA_HOME=”/opt/java64/jdk1.6.0_14″
JRE_HOME=”${JAVA_HOME}/jre”
CATALINA_HOME=”/opt/alfresco/tomcat5525alfresco320″
CATALINA_BASE=”${CATALINA_HOME}”
GC_LOG=”${CATALINA_HOME}/logs/gc.log”
CATALINA_TMPDIR=”${CATALINA_HOME}/temp”
ALFRESCO_HOME=”${CATALINA_HOME}”

JAVA_OPTS=””
JAVA_OPTS=”-Djava.library.path=/usr/local/apr/lib”

# Server Hotspot VM
JAVA_OPTS=”${JAVA_OPTS} -server”

# Modelo de datos de x bits -d32/-d64
JAVA_OPTS=”${JAVA_OPTS} -d64″

# Heap Size
JAVA_OPTS=”$JAVA_OPTS -XX:SurvivorRatio=8 -XX:TargetSurvivorRatio=90 -XX:MaxTenuringThreshold=31″
JAVA_OPTS=”${JAVA_OPTS} -Xms512m -Xmx640m”
JAVA_OPTS=”${JAVA_OPTS} -Xss128k”

# Perm Size – Total permanent generation
JAVA_OPTS=”${JAVA_OPTS} -XX:PermSize=128m -XX:MaxPermSize=128m”

# Young Generation
JAVA_OPTS=”${JAVA_OPTS} -XX:+UseParNewGC”

# Old Generation – Low Pause Collector (default: Mark-Compact Collector)
JAVA_OPTS=”${JAVA_OPTS} -XX:+UseConcMarkSweepGC”

# Permanent Generation – Compact Mark Sweeping Collector
JAVA_OPTS=”${JAVA_OPTS} -XX:+CMSClassUnloadingEnabled”

# Intervalo en milisegundos para GC
JAVA_OPTS=”${JAVA_OPTS} -Dsun.rmi.dgc.server.gcInterval=3600000 -Dsun.rmi.dgc.client.gcInterval=3600000″

# Codificación
JAVA_OPTS=”${JAVA_OPTS} -Dfile.encoding=UTF-8″

# Log para acciones de GC
CATALINA_OPTS=”${CATALINA_OPTS} -Xloggc:${GC_LOG}”

# Sincronización basada en hilo LWP
CATALINA_OPTS=”${CATALINA_OPTS} -Xconcurrentio”

# Comprobaciones adicionales
CATALINA_OPTS=”${CATALINA_OPTS} -Xcheck:jni”

# Monitorización JMX
CATALINA_OPTS=”${CATALINA_OPTS} -Djava.rmi.server.hostname=127.0.0.1 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9004 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.password.file=$JAVA_HOME/jre/lib/management/jmxremote.access”

# Parámetros para Alfresco desde java
JAVA_OPTS=”${JAVA_OPTS} -Dalfresco.home=${ALFRESCO_HOME}”

Plugin para Pidgin “now listening” en Spotify

He visto un plugin para mi pidgin que presenta la canción que estás escuchando actualmente en spotify (instalado en wine, por supuesto).

Se encuentra aquí: http://developer.pidgin.im/wiki/ThirdPartyPlugins

Se llama “pilt spotify” y según su README es simplemente compilarlo con make, aunque me han salido unos errores en mi Ubuntu 9.10. Estos errores han sido simplemente falta de librerías principalmente así que se instalan:

sudo aptitude install glibc-2.10-1 sudo aptitude install libglib2.0-dev sudo aptitude install libpurple-dev sudo aptitude install xorg-dev

Pero hecho esto, se compila todo menos el plugin, ¿por qué?, bueno, parece ser que la versión de la librería libpurple-dev es distinta de la que depende libpurple0 (en mi caso la 2.6.2 en lugar de ser la 2.6.3 que es la que necesito).

Así pues, en http://archive.getdeb.net/getdeb/ubuntu/jaunty/li/ se baja la buena libpurple-dev_2.6.3-1~getdeb1_all.deb y se instala.

Con “aptitude show libpurple-dev” se verifica que ahora la versión es la buena y se vuelve a compilar con “make”.

Por último se copia spotify_playing.so en el “home” del usuario, dentro de .purple/plugins y listo, solo queda arrancar Pidgin y activar el complemento.

Recomiendo seguir el README y en caso de problemas sobre librerías continuar a partir de ahí con este artículo.

Autenticación NTLM (SSO) en share de Alfresco 3.1

Para la autenticación por NTLM de la nueva interface “share” de Alfresco hay que seguir los siguientes pasos:

A) Modificar webapps/share/WEB-INF/web.xml para activar las líneas y filtros referentes a la autenticación NTLM (de igual forma que en mi post anterior Autenticación NTLM en Alfresco)

B) Copiar webapps/share/WEB-INF/classes/alfresco/webscript-framework-config.xml como shared/classes/alfresco/web-extension/webscript-framework-config-custom.xml

C) Añadir lo siguiente (desde el hasta ):



[…]

alfresco
Alfresco – user access
Access to Alfresco Repository WebScripts that require user authentication
alfresco
http://localhost:8080/alfresco/wcs
user
true

[…]

Reiniciar el servidor y listo. Hay que tener en cuenta siempre las recomendaciones y configuraciones de los posts anteriores en cuanto a navegadores y sistemas.

Para más información se puede ir a la wiki de Alfresco.

Single Sign On (SSO) en Alfresco con NTLM (Windows)

En el artículo anterior se vió la forma de configurar la autenticación NTLM (Autenticación NTLM en Alfresco) tanto vía WebClient (web) como vía CIFS (unidades compartidas de Windows). De hecho se ha visto una configuración denominada “passthru” en la que los usuarios se buscan directamente en la SAM de Windows, ya sea 2000/2003/… Server, o el mismo Windows XP que también contiene la suya.

Bien, pero, si el cliente es desde windows y nos hemos identificado con un usuario que ya existe en Alfresco, lo ideal es que no vuelva a preguntar por esa autenticación y envíe los datos de usuario/password (o cadena MD4) de nuevo, si no que el mismo Internet Explorer los envíe de forma automática y por tanto se esté autenticado. Esto es lo que se conoce como Single Sign On (SSO).

Alfresco permite este sistema de autenticación “automatizada” o de “autentícate una vez solamente” en determinadas configuraciones. Una de ellas es a través de NTLM siempre que el sistema utilice NTLMv1. En el caso que nos ocupa, con una instalación de Alfresco Enterprise 3.1 SP1 en una máquina Linux Ubuntu 9.10 y una base de usuarios en Windows XP, accediendo desde el propio Windows XP autenticados previamente con una cuenta que existe en Alfresco.

Los ficheros a configurar son los mismos que anteriormente, o sea, web.xml y ntlm-authentication-context.xml

Muy bien, ya están configurados, pero entonces, ¿por qué se me solicita siempre usuario y contraseña desde Internet Explorer si estoy autenticado con un usuario y contraseña que ya están en Alfresco)

La respuesta está en base a dos configuraciones que hay que revisar:

1. Uso de NTLMv1 desde Windows. Para ello hay que realizar los siguientes pasos en Windows:

a) Ir a “Panel de control->Herramientas administrativas->Política de seguridad local”
b) Seleccionar la carpeta “Políticas locales”
c) Ir a “Opciones de seguridad”
d) Seleccionar “Network Security : nivel de autenticación del controlador LAN”
e) Comprobar (o en su caso establecerla) que está en la opción de “Enviar LM & NTLM – usar seguridad de sesión NTLMv2 si se negocia”

2. Acceso desde Internet Explorer. El navegador seguirá visualizando la ventana de autenticación porque, evidentemente, no se fía de realizar un acceso de forma automática sin el consentimiento del usuario. Para ello en Internet Explorer hay que seguir los siguientes pasos:

a) Ir a “Herramientas->Opciones de Internet…->Seguridad”
b) Seleccionar “Sitios de confianza”
c) Pulsar en el botón “Sitios..”
d) Introducir (Agregar) la URL del sitio al que se accede (del servidor donde está Alfresco), p.e. http://172.26.0.6:8080/alfresco (desactivar “Requerir comprobación del servidor (https)…” si no es una URL segura)

Con esto ya obtenemos SSO desde Windows con Internet Explorer desde la versión 6.

Para comprobar que funciona solo hay que activar en log4j.xml la depuración de NTLM:

log4j.logger.org.alfresco.web.app.servlet.NTLMAuthenticationFilter=debug
log4j.logger.org.alfresco.repo.webdav.auth.NTLMAuthenticationFilter=debug

Cuando autentique correctamente dará un resultado como el que sigue:

11:50:37,178 DEBUG [app.servlet.NTLMAuthenticationFilter] New NTLM auth request from 172.26.0.13 (172.26.0.13:3072) SID:A28CADB932CA4EFB87283284B9C29990
11:50:37,238 DEBUG [app.servlet.NTLMAuthenticationFilter] Received type1 [Type1:0xa208b207,Domain:WRKGRP,Wks:XPPRO]
11:50:37,239 DEBUG [app.servlet.NTLMAuthenticationFilter] Client domain WRKGRP
11:50:37,429 DEBUG [app.servlet.NTLMAuthenticationFilter] Sending NTLM type2 to client – [Type2:0x80000203,Target:PT043A,Ch:6ce8db32e9dccc27]
11:50:37,459 DEBUG [app.servlet.NTLMAuthenticationFilter] Received type3 [Type3:,LM:947bde8ff03d7b972817a6dc0232eddeba5c294ad9a337a2,NTLM:4a532d7bbd01f1ef2300a8fc91b54fbcad5e11db6a94f284,Dom:XPPRO,User:fegor,Wks:XPPRO]
11:50:37,555 User:fegor DEBUG [app.servlet.NTLMAuthenticationFilter] Updated cached NTLM details
11:50:37,556 User:fegor DEBUG [app.servlet.NTLMAuthenticationFilter] User logged on via NTLM, [fegor,Wks:XPPRO,Dom:XPPRO,AuthSrv:PT043A,Fri Dec 18 11:50:37 GMT+01:00 2009]

“Rizando el rizo”…

Bueno, pero , ¿que pasa con Fire Fox?, este navegador por defecto no es capaz de autenticar vía NTLM…

Por defecto no, pero podemos “forzarlo”, ¿como?, solo hay que seguir los siguientes pasos:

a) Poner en la URL de Fire Fox “about:config” y aceptar la entrada.
b) Buscar la cadena “network.automatic-ntlm-auth.trusted-uris” e introducir como valor la URL de Alfresco. P.e. http://172.26.0.6:8080/alfresco

Con esta configuración podremos tener acceso SSO en Fire Fox 3 desde un cliente Windows.

Esta configuración (al igual que la del artículo anterior) han sido probadas tanto en la versión 2.1 (SP7) como en la 3.1 (SP1) de Alfresco Enterprise.