jueves, febrero 24, 2011
Links útiles sobre Spring
El SpringSource Team Blog no deja de postear diversos artículos sobre Spring 3.1 y de la serie Grean Beans (Spring en general). Aquí va una recopilación:
Green Beans
Putting the Spring in Your Step (and Application)
Getting Started with Spring MVC
Getting Started with Spring in your Service Tier
Getting Started with Maven and Spring
Getting Started with Enterprise Messaging and Spring
Getting Started with Spring Integration
Spring 3.1
Spring 3.1 M1: Introducing @Profile
Unified Property Management
Introducing FeatureSpecification support
MVC Namespace Enhancements and @Configuration
Cache Abstraction
domingo, abril 25, 2010
Seminario en la Semana Informática
El día 27 de Abril, mi colega Pedro Molina y yo daremos una charla sobre frameworks y MDD. La charla será dentro del evento Semana Informática 2010: Productividad y flexibilidad de desarrollo basada en frameworks y generación de código.
Habiendo contribuido en numerosas ocasiones al desarrollo de frameworks para instituciones de lo mas diversas, el reto está en saber transmitir la necesidad de tales frameworks, la complejidad que conlleva su desarrollo y los beneficios en productividad que se logran.
Pero tampoco hay que olvidar una parte fundamental de lo que se pretende lograr con un framework: la flexibilidad en los desarrollos. De nada nos sirve estandarizar la forma de construir aplicaciones, y el aporte de servicios de infraestructura muy robustos (¿eso es un framework de desarrollo, verdad?), si cada vez que cambia la tecnología tenemos que cambiar el framework.
Si ante cada cambio de tecnología nuestro framework va quedando obsoleto, la capacidad de adaptarnos a las necesidades del negocio van siendo cada vez menores, hasta tal punto de convertirnos en un obstáculo para el mismo. Y nuestro objetivo como informáticos es lograr que informática esté alineada siempre al 100% con el negocio, no ser el obstáculo del cambio.
En este punto es donde los beneficios de la generación de código se hacen patentes. Desde Spring Roo, hasta la generación mediante modelos, de lo que se trata es de "meta-programar".
Como es que después de mas de 30 años de ordenadores, sigamos por ejemplo dedicando jornadas enteras a desarrollar un simple mantenimiento de una tabla? Como es que no hemos logrado todavía decir "HAL: hazme un mantenimiento de la tabla Cliente"?
Realmente no tengo la respuesta a porqué, pero si sé que el 80% del código de una aplicación es repetible y se puede modelizar y generar, por lo que deberíamos dedicar mas esfuerzo a meta-programar y menos en mantenimientos.
Y también sé que me gustaría luego dedicarme tranquilamente al otro 20%.
jueves, abril 08, 2010
Verificar firma con OpenSAML
Suponiendo una llamada webservice que contenga una Assertion SAML firmada, como verificamos esa firma? CXF provee "interceptores" para incluir código antes y después de una invocación a webservice.
Primero debemos configurar (con Spring en este caso) la invocación:
<jaxws:client id="clientWS" serviceClass="es.mycompany.MyService" address="http://localhost:8080/app/services/myservice"> <jaxws:dataBinding> <ref bean="aegisBean" /> </jaxws:dataBinding> <jaxws:inInterceptors> <ref bean="clientWS.InInterceptor" /> </jaxws:inInterceptors> </jaxws:client> <bean id="clientWS.InInterceptor" class="es.mycompany.MyInterceptor"> <constructor-arg> <map> <entry key="action" value="Timestamp Signature"/> <entry key="passwordCallbackClass" value="es.mycompany.MyPasswordCallback"/> <entry key="signaturePropFile" value="keystore.properties"/> </map> </constructor-arg> </bean>
Luego creamos nuestro fichero de propiedades del keystore ("keystore.properties"):
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin org.apache.ws.security.crypto.merlin.keystore.type=jks org.apache.ws.security.crypto.merlin.keystore.alias=MyAlias org.apache.ws.security.crypto.merlin.keystore.password=MyPassword org.apache.ws.security.crypto.merlin.file=keystore.jks
Y finalmente la clase encargada de dar las contraseñas de acceso a los certificados. Esta clase es claramente mejorable, pero sirve como ejemplo:
public class MyPasswordCallback implements CallbackHandler { private MapTeniendo todo configurado, solo nos queda el código del interceptor, que a su vez se apoya en una clase de utilidades:passwords = new HashMap (); public STSPasswordCallback() { passwords.put("MyAlias", "MyPassword"); } public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { for (int i = 0; i < callbacks.length; i++) { WSPasswordCallback pc = (WSPasswordCallback) callbacks[i]; String pass = passwords.get(pc.getIdentifier()); if (pass != null) { pc.setPassword(pass); return; } } } }
public class MyInterceptor extends WSS4JInInterceptor { private String issuer = "http://www.mycompany.com"; public MyInterceptor() { super(); } public MyInterceptor(MapComo ven, todo el trabajo lo hace la línea trustEngine.validate(assertion.getSignature(), criteriaSet);, solo hay que llegar hasta ella con los datos adecuados.properties) { super(properties); } protected void doReceiverAction(int doAction, RequestData reqData) throws WSSecurityException { // Get SOAP Header SOAPMessage message = ((org.apache.cxf.binding.soap.SoapMessage) reqData.getMsgContext()).getContent(javax.xml.soap.SOAPMessage.class); SOAPHeader soapHeader = message.getSOAPHeader(); // Get Assertion XML XPathUtils xu = new XPathUtils(); Element xmlAssertion = (Element) xu.getValueNode("//saml2:Assertion", soapHeader); // Unmarshall Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(xmlAssertion); Assertion assertion = (Assertion) unmarshaller.unmarshall(xmlAssertion); // Get Handler properties String sigPropFile = getString(WSHandlerConstants.SIG_PROP_FILE, reqData.getMsgContext()); String callback = getString(WSHandlerConstants.PW_CALLBACK_CLASS, reqData.getMsgContext()); // Verify SAMLUtils.verifySignature(assertion, issuer, sigPropFile, callback); super.doReceiverAction(doAction, reqData); } public void handleMessage(SoapMessage message) throws Fault { super.handleMessage(message); } } public class SAMLUtils { public static void verifySignature(Assertion assertion, String issuer, String sigPropFile, String callback) throws WSSecurityException { X509Credential cred = getX509Credential(sigPropFile, callback); StaticCredentialResolver credResolver = new StaticCredentialResolver(cred); KeyInfoCredentialResolver kiResolver = SecurityHelper.buildBasicInlineKeyInfoResolver(); ExplicitKeySignatureTrustEngine trustEngine = new ExplicitKeySignatureTrustEngine(credResolver, kiResolver); CriteriaSet criteriaSet = new CriteriaSet(); criteriaSet.add(new EntityIDCriteria(issuer)); criteriaSet.add(new UsageCriteria(UsageType.SIGNING)); criteriaSet.add(new MetadataCriteria(IDPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS)); try { trustEngine.validate(assertion.getSignature(), criteriaSet); } catch (SecurityException e) { throw new WSSecurityException(e.getMessage()); } } public static X509Credential getX509Credential(String sigPropFile, String callback) throws WSSecurityException { PrivateKey privateKey = null; X509Certificate[] certs = null; Crypto crypto = crypto = CryptoFactory.getInstance(sigPropFile); try { CallbackHandler cbhandler = getPasswordCallBack(callback); WSPasswordCallback cb = new WSPasswordCallback(crypto.getDefaultX509Alias(), WSPasswordCallback.SIGNATURE); cbhandler.handle(new Callback[] { cb }); privateKey = crypto.getPrivateKey(crypto.getDefaultX509Alias(), cb.getPassword()); certs = crypto.getCertificates(crypto.getDefaultX509Alias()); } catch (Exception e) { throw new WSSecurityException(e.getMessage()); } if (certs.length != 1) { throw new WSSecurityException("Couldn't get the (" + crypto.getDefaultX509Alias() + ") signature certificate."); } X509Credential cred = SecurityHelper.getSimpleCredential(certs[0], privateKey); return cred; } public static CallbackHandler getPasswordCallBack(String callback) throws WSSecurityException { CallbackHandler cbHandler = null; try { Class cbClass = Loader.loadClass(callback); cbHandler = (CallbackHandler) cbClass.newInstance(); } catch (Exception e) { throw new WSSecurityException("WSHandler: cannot create instance of password callback: " + callback, e); } return cbHandler; } }
lunes, octubre 26, 2009
Receta CXF, WSS4J y Spring Security
Como utilizar la seguridad de Spring Security para autenticar un usuario/contraseña de un servicio web implementado con CXF mediante WSS4J (Java WS-Security de Apache):
En el aplication context de spring, primero definimos los namespaces, importamos los xml de CXF y definimos el "Interceptor" que gestionará la seguridad:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:cxf="http://cxf.apache.org/core" xmlns:util="http://www.springframework.org/schema/util" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd" > <!-- Load CXF modules from cxf.jar --> <import resource="classpath:META-INF/cxf/cxf.xml" /> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" /> <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> <bean id="WSS4JInInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor"> <property name="properties"> <map> <entry key="action" value="UsernameToken Timestamp"/> <entry key="passwordType" value="PasswordDigest"/> <entry key="passwordCallbackRef"> <bean class="my.company.SecurityInPasswordHandler"/> </entry> </map> </property> </bean> </beans>
Y luego agregamos el interceptor a los webservices que necesiten seguridad:
<jaxws:endpoint id="salaWebService" implementor="#salaService" address="/salas"> <jaxws:inInterceptors> <ref bean="WSS4JInInterceptor"/> </jaxws:inInterceptors> </jaxws:endpoint>
Asumiendo que tenemos el siguiente servicio:
@WebService @SOAPBinding public interface SalaService { @WebResult(name = "sala") public abstract Sala get(@WebParam(name = "id") Long id); } @Service("salaService") @WebService(serviceName = "SalaService", portName = "SalaPort", endpointInterface = "my.company.service.SalaService") public class SalaServiceImpl implements SalaService { public Sala get(Long id) { return (Sala) executor.execute(SalaBusinessOperations.GET, new Long(id)); } }
Y que CXF está configurado en el web.xml de la siguiente forma:
<servlet> <servlet-name>CXFServlet</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping>
La seguridad de spring debería estar configurada, por ejemplo, con lo siguiente:
<http > <intercept-url pattern="/services/**" access="ROLE_ANONYMOUS" /> <intercept-url pattern="/**" access="ROLE_USER" /> <logout/> <anonymous/> </http>
Finalmente podemos dedicarnos a la clase que gestionará la seguridad:
public class SecurityInPasswordHandler implements CallbackHandler { @Autowired private AuthenticationManager authenticationManager; @Autowired private UserDetailsService userService; public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException, AuthenticationException { WSPasswordCallback pwdCallback = (WSPasswordCallback) callbacks[0]; int usage = pwdCallback.getUsage(); if ((usage == WSPasswordCallback.USERNAME_TOKEN) || (usage == WSPasswordCallback.USERNAME_TOKEN_UNKNOWN)) { String password = pwdCallback.getPassword(); if (usage == WSPasswordCallback.USERNAME_TOKEN) { UserDetails userDetails = userService.loadUserByUsername(pwdCallback.getIdentifier()); password = userDetails.getPassword(); } Authentication authentication = new UsernamePasswordAuthenticationToken(pwdCallback.getIdentifier(), password); authentication = authenticationManager.authenticate(authentication); //throws AuthenticationException SecurityContextHolder.getContext().setAuthentication(authentication); // Return the password to the caller pwdCallback.setPassword(password); } } }
Con esto logramos gestionar passwords enviadas en plano (PasswordText) y encriptadas (PasswordDigest). En ambos casos creando un SecurityContext para que la petición tenga los roles del usuario y puedan utilizarse las anotaciones "@Secured" de Spring Security.
miércoles, agosto 26, 2009
OSGi/JTA
Existe un problema al utilizar JTA (Java Transaction API) en OSGi: la implementación JTA que ofrece el bundle "0" (el del runtime OSGi) es la del JDK y está incompleta.
Para solucionar esto hay seguir dos pasos:
1: Colocar un jar de JTA con el MANIFEST.MF de OSGi en la carpeta "lib/ext" del JRE. El Jar se puede obtener del repositorio de SpringSource: com.springsource.javax.transaction-1.1.0.jar
2: Modificar la propiedad "org.osgi.framework.system.packages" del runtime para agregar los packages de la versión "1.1.0": "javax.transaction, javax.transaction;version=1.1.0, javax.transaction.xa, javax.transaction.xa;version=1.1.0"
De hecho esta solución nos permite también ofrecer nuestros propios packages como parte del bundle "0", solo debemos agregarlos a la propiedad arriba mencionada.
Para solucionar esto hay seguir dos pasos:
1: Colocar un jar de JTA con el MANIFEST.MF de OSGi en la carpeta "lib/ext" del JRE. El Jar se puede obtener del repositorio de SpringSource: com.springsource.javax.transaction-1.1.0.jar
2: Modificar la propiedad "org.osgi.framework.system.packages" del runtime para agregar los packages de la versión "1.1.0": "javax.transaction, javax.transaction;version=1.1.0, javax.transaction.xa, javax.transaction.xa;version=1.1.0"
De hecho esta solución nos permite también ofrecer nuestros propios packages como parte del bundle "0", solo debemos agregarlos a la propiedad arriba mencionada.
viernes, marzo 13, 2009
Workast
Tanto tiempo sin escribir ha hecho de mi conciencia algo molesto, por lo que mi primer post será ni mas ni menos que una justificación!
Estos últimos meses he estado dedicado a un proyecto personal, Open Source (como no podía ser de otra manera), de microblogging.
El proyecto en cuestión es Workast y para explicarlo, nada mejor que una comparación: Twitter.
El "problema" con Twitter, aunque parezca una contradicción, es su naturaleza pública. Si bien eso lo ha llevado a donde hoy está, en las empresas no siempre es bien visto debido a que la información que allí se vuelca es visible para todos.
Así han surgido alternativas como laconi.ca con la que cualquier empresa puede instalar dentro de sus fronteras un servidor de microbloging para sus empleados. También hay servicios como Yammer, gratuitos hasta que se quieren administrar, momento en el cual cobran a la empresa por esa posibilidad.
Esto me ha llevado a plantearme la posibilidad de hacer un software yo mismo y devolver un poco de todo lo que tomamos cada día de la comunidad Open Source.
Por supuesto me ha servido también para probar diferentes alternativas a las problemáticas que van surgiendo, y aprender en el camino.
¿Que hay hecho hasta ahora?
5700+ líneas de Java mas algunas mas de javascript (en ohloh.net la cantidad de líneas javascript es desproporcionada, ya que el 99% es de bibliotecas de terceros).
¿Y que hacen esas 5700 líneas?

Mas pantallas aquí.
¿Como?
- Escribiendo lo que te pase por la cabeza en formato wiki
- Dejando eventos para formar un calendario
- Comentando lo que otros escriben
- Organizando lo que te parece útil mediante etiquetas
- Siguiendo a otra gente para que aparezca en tu vista de novedades
- Creando y escribiendo dentro de grupos, para organizar mejor las novedades
- Filtrando las novedades por etiqueta, texto o tipo de actividad
¿Y con qué tecnología está desarrollado?
- Spring framework
- Hibernate
- Hibernate Validator (JSR-303)
- RESTEasy (JAX-RS)
- jQuery
- MySQL/HSQL
- Joda Time
- info.bliki
Próximos pasos
- Investigar Spring 3.0, con su soporte para REST y Bean Validation
- Completar el roadmap
- Actualizar este blog con las novedades que vayan ocurriendo en el desarrollo
Luego de este resumen, queda por decir que ya hay una versión descargable aquí (alpha), y que todos los comentarios y sugerencias que me hagáis llegar son más que bienvenidos.
Estos últimos meses he estado dedicado a un proyecto personal, Open Source (como no podía ser de otra manera), de microblogging.
El proyecto en cuestión es Workast y para explicarlo, nada mejor que una comparación: Twitter.
El "problema" con Twitter, aunque parezca una contradicción, es su naturaleza pública. Si bien eso lo ha llevado a donde hoy está, en las empresas no siempre es bien visto debido a que la información que allí se vuelca es visible para todos.
Así han surgido alternativas como laconi.ca con la que cualquier empresa puede instalar dentro de sus fronteras un servidor de microbloging para sus empleados. También hay servicios como Yammer, gratuitos hasta que se quieren administrar, momento en el cual cobran a la empresa por esa posibilidad.
Esto me ha llevado a plantearme la posibilidad de hacer un software yo mismo y devolver un poco de todo lo que tomamos cada día de la comunidad Open Source.
Por supuesto me ha servido también para probar diferentes alternativas a las problemáticas que van surgiendo, y aprender en el camino.
¿Que hay hecho hasta ahora?
5700+ líneas de Java mas algunas mas de javascript (en ohloh.net la cantidad de líneas javascript es desproporcionada, ya que el 99% es de bibliotecas de terceros).
¿Y que hacen esas 5700 líneas?

Mas pantallas aquí.
¿Como?
- Escribiendo lo que te pase por la cabeza en formato wiki
- Dejando eventos para formar un calendario
- Comentando lo que otros escriben
- Organizando lo que te parece útil mediante etiquetas
- Siguiendo a otra gente para que aparezca en tu vista de novedades
- Creando y escribiendo dentro de grupos, para organizar mejor las novedades
- Filtrando las novedades por etiqueta, texto o tipo de actividad
¿Y con qué tecnología está desarrollado?
- Spring framework
- Hibernate
- Hibernate Validator (JSR-303)
- RESTEasy (JAX-RS)
- jQuery
- MySQL/HSQL
- Joda Time
- info.bliki
Próximos pasos
- Investigar Spring 3.0, con su soporte para REST y Bean Validation
- Completar el roadmap
- Actualizar este blog con las novedades que vayan ocurriendo en el desarrollo
Luego de este resumen, queda por decir que ya hay una versión descargable aquí (alpha), y que todos los comentarios y sugerencias que me hagáis llegar son más que bienvenidos.
viernes, junio 27, 2008
Suscribirse a:
Entradas (Atom)