Posts Tagged 'bbdd'

Visualizando sentencias SQL

QueryScope es una herramienta que para la visualización de sentencias SQL en diagramas de burbujas de colores que muestran las características más importantes de la query con el fin de aportar pistas para tunearla.

El diagrama generado es interactivo y resume las tablas que participan en la query, los tamaños, los índices y los joins. Además también permite comparar consultas de forma gráfica.

No lo he probado aún porque requiere del JDK 1.6 y no lo tengo instalado en el portátil desde donde escribo. En cuanto lo estudie en condiciones comentaré algo más. Tiene buena pinta.

Visto en Dzone.com

—- Actualización: 16:26 El programa no es software libre. Forma parte de los productos alphaWorks de IBM.

Nueva Refcardz disponible para descargar – JPA

La gente de DZone acaba de publicar una nueva refcardz. Las refcardz son unas excelentes guías de referencia rápida sobre diferentes temas relacionados con la programación. Esta vez es sobre JPA (Getting started with JPA ).

Precisamente llevo toda la mañana tratando de resolver un problemilla que tengo con OpenJPA… así que la guía me viene de maravilla 😉

Ejemplo básico de autenticación contra BBDD usando Spring Security (parte II)

Continuo con la segunda parte del ejemplo comenzado ayer.

Una vez conseguida la auntenticación contra un usuario cargado en memoria por Acegi el siguiente paso sería preparar la infraestructura de base de datos contra la que se va a realizar la nueva comprobación de credenciales. Como mínimo la base de datos ha de almacenar, como es lógico, el nombre de usuario y la password de cada uno de los usuarios. Además, cada uno de ellos ha de tener un perfil asociado para en función de este y de las reglas del filtro se permita o no el acceso a determinados paths.

Desde la página oficial de Spring Security nos sugieren este modelo de BBDD (para la autenticacion basta con la tabla users y authorities):

El script de creación de la BBDD se puede encontrar en la página de Spring Security pero es una implementación para Hypersonic. Yo voy a usar MySQL así que para este ejemplo ejecutaré este otro script sacado del foro de Spring:

DROP TABLE IF EXISTS contacts;
DROP TABLE IF EXISTS authorities;
DROP TABLE IF EXISTS users;
DROP TABLE IF EXISTS acl_permission;
DROP TABLE IF EXISTS acl_object_identity;

CREATE TABLE users (
	username varchar(50) NOT NULL,
	password varchar(50) NOT NULL,
	enabled bool NOT NULL,
	
	constraint PK_Username primary key (username)
) ENGINE=InnoDB;


CREATE TABLE authorities (
	username varchar(50) NOT NULL,
	authority varchar(50) NOT NULL,
	
	constraint FK_Username foreign key (username) references users(username),
	constraint IX_AuthUsername unique key (username, authority)
) ENGINE=InnoDB;
        

CREATE TABLE acl_object_identity (
  	id int NOT NULL auto_increment,
  	object_identity varchar(250) NOT NULL,
  	parent_object int,
  	acl_class varchar(250) NOT NULL,
  	
  	index (parent_object),
  	
  	constraint PK_Id primary key (id),
	constraint FK_ParentObject foreign key (parent_object) references acl_object_identity(id)

) ENGINE=InnoDB;


CREATE TABLE acl_permission (
  	id int NOT NULL auto_increment,
  	acl_object_identity int NOT NULL,
  	recipient varchar(100) NOT NULL,
  	mask int NOT NULL,
  	
  	constraint PK_Id primary key (id),
	constraint FK_ACLIdentity foreign key (acl_object_identity) references acl_object_identity(id),
	constraint IX_URecipient unique key (acl_object_identity, recipient)

) ENGINE=InnoDB;

INSERT INTO users VALUES('pepe','pepe',1);

INSERT INTO authorities VALUES('pepe','ROLE_ADMINISTRADOR);

Creo la BBDD y ejecuto el script. Ahora hay que definir un datasource usando Spring. Para ello creo (por separar conceptos) un nuevo fichero de contexto que llamo applicationContext-acegi-security.xml y lo coloco en el raíz de la carpeta WEB-INF.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
        <property name="location"><value>classpath:/databaseMySQL.properties</value></property>    
    </bean>
    
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		<property name="driverClassName"><value>${driver}</value></property>
		<property name="url"><value>${url}</value></property>
		<property name="username"><value>${username}</value></property>
		<property name="password"><value>${password}</value></property>
		<property name="defaultReadOnly"><value>${defaultReadOnly}</value></property>				
		<property name="maxActive"><value>${maxActive}</value></property>
		<property name="maxWait"><value>${maxWait}</value></property>
		<property name="validationQuery"><value>${validationQuery}</value></property>
	</bean>	

</beans>

Una vez creado se referencia añadiéndolo al parámetro de contexto contextConfigLocation en el web.xml que quedaría así:

<context-param>
		<param-name>contextConfigLocation</param-name>

		<param-value>
			/WEB-INF/applicationContext-acegi-security.xml /WEB-INF/applicationContext-acegi-datasource.xml
		</param-value>
	</context-param>

El jar de Commons BDCP se puede descargar href=”http://commons.apache.org/downloads/download_dbcp.cgi”>aquí. También hace falta el Commons Pool. Por supuesto también es necesario añadir el driver JDBC de MySQL al directorio de librerias.

También hay que crear el fichero .properties del que obtiene los parámetros: databaseMySQL.properties.

driver=com.mysql.jdbc.Driver
username=*****
password=*****
url=jdbc:mysql://localhost:3306/pruebas
initialSize=5
maxActive=5
maxWait=500
maxIdle=3
minIdle=1
validationQuery=SELECT 'ok' from dual
testOnBorrow=true
defaultReadOnly=false

El siguiente paso es añadir el siguiente fragmento de código al fichero applicationContext-acegi-security.xml. En el se hace referencia al datasource creado previamente y se pasan dos parámetros clave para la autenticación:

  • usersByUsernameQuery: SQL para obtener los datos del usuario. Lo que espera obtener Acegi es el username la password y si el usuario es enabled o no (los as)
  • authoritiesByUsernameQuery:SQL para obtener el ROL del usuario obtenido de la query del parámetro usersByUsernameQuery
<bean id="authenticationDao"
	      class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">
		<property name="dataSource">
			<ref bean="dataSource"/>
		</property>
		
	<property name="usersByUsernameQuery">
			<value>select USERNAME as username, PASSWORD as password, ENABLED as enabled FROM users WHERE username =? </value>
			</property>
		<property name="authoritiesByUsernameQuery">
		<value>select USERNAME as username, authority as rolename FROM authorities WHERE username =? </value>
		</property>
	</bean>

Y ya está. Ya se puede probar. Tan sólo quedan un par de detalles por zanjar: la encriptación de la password.

Añadir la propiedad passwordEncoder a el bean daoAuthenticationProvider:

    	<property name="passwordEncoder">
      		<ref bean="passwordEncoder" />
    	</property>

y el correspondiente bean, en este caso utilizado Md5 como algoritmo de encriptación:

<bean id="passwordEncoder"
   		class="org.acegisecurity.providers.encoding.Md5PasswordEncoder"/>

Aquí se puede encontrar el javadoc del paquete encoding.

—- Actualización: (18 Agosto de 2008)

La información del usuario logueado se guarda en el atributo de sesión ACEGI_SECURITY_CONTEXT. A partir de este atributo se puede obtener el login del usuario. Yo, lo que hago normalmente en una aplicación real, es sustituir lo que en el ejemplo he llamado EstoyDentro.do por un action, que a partir del login validado por Acegi, consulte el resto en BBDD (nombre, apellido, etc) y luego lo meta en sesión. Posteriormente hago un forward a donde corresponda.

Este es un snippet de como obtener el login:

SecurityContext contexto = 
(SecurityContext)request.getSession().getAttribute("ACEGI_SECURITY_CONTEXT");

String login = ((org.acegisecurity.userdetails.User)
							(context.getAuthentication().getPrincipal())).getUsername();

Y esto es todo amigos… próximamente en Hermosodía:

  • Ejemplo de TestNG
  • Histórico de BBDD

Ejemplo básico de autenticación contra BBDD usando Spring Security (parte I)

Spring Security antes conocido como Acegi es una API open source que provee de servicios de autenticación y autorización a las aplicaciones basadas en Spring. Desde su primera release se ha convertido en una de las mejores opciones y más extendidas para este fin.

Spring Security es una API muy potente y con muchas posibilidades. Permite la autenticación contra LDAP, Certificados digitales, etc. El ejemplo que viene a continuación muestra los pasos a seguir para la correcta autenticación de un usuario de una aplicación Web creada con Struts 1 (aunque es lo de menos) contra una base de datos.

  1. Paso 0 – Preliminares: Como punto de partida para el desarrollo del ejemplo haré uso del ejemplo struts-blank que viene en la página oficial de Struts 1. Lo descargo y lo descomprimo. El ejemplo simplemente contiene un index.jsp que redirige a una acción de Struts llamada Welcome.do. Lo voy a modificar para convertir el Welcome.do a un formulario que solicite el usuario y la password, para que, a través de Acegi sean validados contra la BBDD y en función de si las credenciales son o no válidas redirijir al usuario a una página que ponga “Estás dentro” o por el contrario a una página de error.
  2. Paso 1 – Creación del formulario de login: Editamos la jsp Welcome.jsp añadiendole un formulario como este:
    <form action="../j_acegi_security_check.do" method="post">
    	<input type="text" name="j_username">
    	<input type="password" name="j_password">
            <input type="submit">
    </form>
    

    Es importante tener en cuenta los nombres de los parámetro y el action. Los nombres aquí puestos son los que espera recibir Acegi por defecto así que si se cambian no se realizará la validación.

  3. Paso 2 – Creación de la jsp que se verá una vez autenticados: La llamo por ejemplo “EstoyDentro.jsp” y añado un texto. A continuación creo una nueva definición en los action mappings del struts-config.xml llamada EstoyDentro que redirige a la nueva jsp.
    <action
                path="/EstoyDentro"
                forward="/pages/EstoyDentro.jsp"/>
    
  4. Paso 3 – Añadir las librerias correspondientes al proyecto: Se obtienen de http://www.acegisecurity.org/downloads.html y se añaden en la carpeta lib.
  5. Paso 4 – Creación del fichero applicationContext-acegi-security.xml: Creo un fichero llamado applicationContext-acegi-security.xml en el directorio /WEB-INF. Este fichero contiene toda la información de contexto necesaria para que Acegi funcione y tiene esta pinta:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
    <!-- https://hermosodia.wordpress.com - Ejemplo básico de autenticación contra BBDD usando Spring Security -->
    
    <beans>    
       <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
          <property name="filterInvocationDefinitionSource">
             <value>
    	    	CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
    	    	PATTERN_TYPE_APACHE_ANT
    	    	/**=httpSessionContextIntegrationFilter, authenticationProcessingFilter, anonymousProcessingFilter, exceptionTranslationFilter, filterSecurityInterceptor	    	
             </value>
          </property>
        </bean>
    
      <bean id="httpSessionContextIntegrationFilter" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter">
          <property name="context">
    	      <value>org.acegisecurity.context.SecurityContextImpl</value>
          </property>
      </bean>
    
       <bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
          <property name="authenticationManager"><ref bean="authenticationManager"/></property>
          <property name="authenticationFailureUrl"><value>/Welcome.do?error=true</value></property>
          <property name="defaultTargetUrl"><value>/EstoyDentro.do</value></property>
          <property name="alwaysUseDefaultTargetUrl"><value>true</value></property>
          <property name="filterProcessesUrl"><value>/j_acegi_security_check.do</value></property>
       </bean>
    
       <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
          <property name="providers">
           	<list>
                <ref bean="daoAuthenticationProvider"/>
    			<ref local="anonymousAuthenticationProvider"/>
            </list>
          </property>
         </bean>
       	  	<bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
        	<property name="userDetailsService">
        		<ref bean="memoryAuthenticationDao"/>
        	</property>
      	</bean>
      	<bean id="memoryAuthenticationDao" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
      <property name="userMap">
        <value>
          pepe=pepe,ROLE_ADMINISTRADOR
        </value>
      </property>
    </bean>
      
    
    	
       <bean id="anonymousAuthenticationProvider" class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider">
          <property name="key"><value>foobar</value></property>
       </bean>
    
       <bean id="anonymousProcessingFilter" class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter">
          <property name="key"><value>foobar</value></property>
          <property name="userAttribute"><value>anonymousUser,ROLE_ANONYMOUS</value></property>
       </bean>
    
       <bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
          <property name="authenticationEntryPoint"><ref local="authenticationProcessingFilterEntryPoint"/></property>
       </bean>
       <bean id="authenticationProcessingFilterEntryPoint" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
    		  <property name="loginFormUrl"><value>/Welcome.do</value></property>
    		  <property name="forceHttps"><value>false</value></property>
       </bean>
       
       
       <bean id="filterSecurityInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
          <property name="authenticationManager"><ref bean="authenticationManager"/></property>
          <property name="accessDecisionManager"><ref local="httpRequestAccessDecisionManager"/></property>
          <property name="objectDefinitionSource">
             <value>
    			    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
    			    PATTERN_TYPE_APACHE_ANT
    			     /welcome.do*=ROLE_ANONYMOUS
    			     /estoydentro.do*=ROLE_ADMINISTRADOR			    
    			    /*.do*=ROLE_ADMINISTRADOR
    	     </value>
          </property>
       </bean>
    
       <bean id="httpRequestAccessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">
          <property name="allowIfAllAbstainDecisions"><value>false</value></property>
          <property name="decisionVoters">
             <list>
                <ref bean="roleVoter"/>
             </list>
          </property>
       </bean>
    
      <bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter">
      		
      </bean>
       <bean id="loggerListener" class="org.acegisecurity.event.authentication.LoggerListener"/>
       
    </beans>
    

    Con este XML básico permitimos el acceso a /EstoyDentro.do a un usuario con el rol ROLE_ADMINISTRADOR. De momento el sistema se autentica contra un usuario definido en bean “memoryAuthenticationDao” dentro del propio XML este modo es muy últil para hacer pruebas en tiempo de desarrollo (posteriormente lo haremos contra BBDD).

    El bean “filterSecurityInterceptor” es el encargado de filtrar las entradas a ciertas urls en función del rol dado. Así pues, en el ejemplo se permite el acceso a /Welcome.do a cualquier usuario anónimo, por el contrario, sólo puede acceder a /EstoyDentro.do un usuario con el rol ROLE_ADMINISTRADOR. Debido al uso de CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON, los paths por los que filtrar han de estar en minúscula.

    Además de estos beans es importante tener en cuenta las propiedades de este otro “authenticationProcessingFilter”.

    • authenticationFailureUrl: Es la url a donde hay que redirigir la petición en caso de autenticación fallida. En el ejemplo nos redirige a la misma página que contiene el formulario de login pero con un parámetro para indicar que la autenticación ha fallado y mostrar el mensaje correspondiente al usuario /Welcome.do?error=true
    • defaultTargetUrl: Es la url a la que se redigirá la petición en caso de que el usuario se haya autenticado correctamente.
  6. Paso 5 – Referenciar al applicationContext-acegi-security.xml creado: Añadimos las siguientes líneas de código al fichero web.xml.
    <context-param>
    		<param-name>contextConfigLocation</param-name>
    
    		<param-value>
    			/WEB-INF/applicationContext-acegi-security.xml
    		</param-value>
    	</context-param>
    	
        <filter>
            <filter-name>Acegi Filter Chain Proxy</filter-name>
            <filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>
            <init-param>
    
                <param-name>targetClass</param-name>
                <param-value>org.acegisecurity.util.FilterChainProxy</param-value>
            </init-param>
        </filter>
    
        <filter-mapping>
          <filter-name>Acegi Filter Chain Proxy</filter-name>
          <url-pattern>/*</url-pattern>
    
        </filter-mapping>
    	
    	<!--
    	  - Loads the root application context of this web app at startup.
    	  - The application context is then available via 
    	  - WebApplicationContextUtils.getWebApplicationContext(servletContext).
        -->
    	<listener>
    		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    	</listener>
    
  7. Paso 6 – Prueba de la aplicación: Despliego la aplicación en el servidor y la veo a través de navegador. El index.jsp me redirije a Welcome.do y este me muestra el formulario. Introduzco el usuario y la password indicada en el applicationContext-acegi-security.xml y tras aceptar… pues el sistema me da paso a EstoyDentro.do.

No más por hoy. Ya tengo un ejemplo de autenticación de una aplicación Struts contra Acegi con datos cargados en memoria. En la parte 2 que publicaré presumiblemente mañana ampliaré el ejemplo para logear al usuario contra una BBDD. También mostraré los pasos necesarios para la desencriptación de la password.

Me voy a echar un trujas y a planchar la oreja. Mañana será otro hermoso día 😉

—–

Actualización (15 Agosto 2008): Ya está lista la segunda parte. Puedes obtenerla aquí.

Generar modelo ER a partir de SQL

En mi búsqueda de una herramienta open source medianamente decente para el modelado de diagramas entidad/relación he encontrado una muy interesante que hace justo lo contrario llamada SQLFairy.

SQLFairy – SQL::Translator es un conjunto de módulos de programados en Perl para la manipulación de esquemas de base de datos. Además de ingeniería inversa tiene otra serie de funcionalidades muy interesantes, conversión de CREATES entre diferentes dialectos (p.e de código MySQL a Oracle), visualización de esquemas, creación de documentación, etc

En Ubuntu su instalación es muy sencilla dado que se encuentra en los repositorios de serie:

sudo apt-get install sqlfairy

El siguiente comando genera un fichero png (esquema.png) con el modelo ER a partir de un fichero SQL (MySQL) llamado ddl.sql

sqlt-diagram -d=MySQL -o=esquema.png ddl.sql --color

Este es un fragmento del resultado:


Add to Technorati Favorites
Clicky Web Analytics Clicky

Flickr Photos