Friday, August 12, 2011

apache2: Could not reliably determine the server's fully qualified domain name

This error is caused by an apache miss configuration. Below are those cases where I have seen it and how I have corrected them:

Sometimes it is just about duplicated directive ServerName. If you use Virtual hosts do not include a global directive but instead just define it in the virtual hosts files, for example:
...
<VirtualHost  nestorurquiza.com:443>
 SSLEngine on
 DocumentRoot "/var/nestorurquiza-app"
 ServerName nestorurquiza.com
...

Your server IP must be mapped to the server domain in /etc/hosts. It cannot be a loopback IP. Provide a separated line for that entry. Do not include any other mapping for the IP. If you need more then add them *below* the entry:
...
192.168.0.137   nestorurquiza.com
192.168.0.137   nestorurquiza
...

Thursday, August 11, 2011

Install openssl in Ubuntu

sudo apt-get install libcurl4-openssl-dev

Using more than one certificate from the JVM for SSL Web Services LDAPS and more

There is one time when your JVM hosting your servlets will demand connecting to more than one SSL Web Service, an LDAPS, passing in some cases private keys, using in some cases different keystore files and more.

In those cases the typical System properties to set up the keystore and password will apparently not work. You can of course pass the properties as part of the java command line that starts the JVM but you can do the same programatically of course.
System.setProperty("javax.net.ssl.keyStore", "keystore path");
System.setProperty("", "keystore password");
System.setProperty("javax.net.ssl.keyStoreType", keystore type);

You will be tempted to get into a really complicated solution.

However there is a simple approach around this problem. If you are contraint about having just one keystore to host multiple certificates that should not be a big issue. After all it is a key "store". All you need to do is import all your certificates and keys in just one keystore following a procedure like the one I described before.

Again what you need to have clear is how you deal with your keys which might be encrypted with a password and that password must be the same you use for your keystore. At that point if you have let us say just one case for a key using a password you can just use the same for your keystore. If not then negotiate a new common password with your service providers. This is after all your client key, yes it is private but it is private to you. A simple phone call and an agreement on the new password will make the trick. Do not use an email for that though!

We recently spent several days troubleshooting issues like this just because I was relying on "that was already tested and it did not work". It demanded a new developer to take over the task so he could start fresh and try the most basic stuff. Simpler is after all better.

As always log traces are your friend when Google is not. Be sure to activate them for SSL when you are dealing with certificate issues:
-Djavax.net.debug=ssl,handshake

Wednesday, August 10, 2011

Premature Optimization is not Agile or should I say it is Evil

The team was having an issue after introducing JPASecurity in the project. Some feature suddenly broke so it must be JPASecurity which is buggy, still in its early phase, ...

Come on, this was working before so ...

Well the fact that your code is working does not mean it is correct. An Abstract class cannot be instantiated but with so much Dependency Injection and Inversion Of Control sometimes we lose control LOL.

An Abstract class is not to be used by any other than implementing classes. But what happens if the developer declares the class abstract and after that uses it as a JPA Entity? Of course this is a mistake, a common mistake I would say where the engineer thinks he is comming up with a great design that will save our lifes in the future, some kind of generalization up front that will address all details in the future, the silver bullet or a synonym (not about performance but about feature implementation) of what the Industry knows as Premature Optimization.

The class is declared Abstract and there is not a single implementation of it but somehow JPA Hibernate EntityManager.merge(Entity) will not complain (Probably because after all it uses a proxy and not the actual class). All goes "good" until one day when you actually try to use reflection on the entity for example if you introduce JPASecurity to provide ACL in your JPA entities.

At this point you will end up with exceptions like:
java.lang.SecurityException: java.lang.InstantiationException
 at net.sf.jpasecurity.util.ReflectionUtils.throwThrowable(ReflectionUtils.java:109)
 at net.sf.jpasecurity.util.ReflectionUtils.newInstance(ReflectionUtils.java:38)
 at net.sf.jpasecurity.mapping.DefaultClassMappingInformation.newInstance(DefaultClassMappingInformation.java:216)
 at net.sf.jpasecurity.entity.EntityPersister.createUnsecureObject(EntityPersister.java:250)
 at net.sf.jpasecurity.entity.AbstractSecureObjectManager.getUnsecureObject(AbstractSecureObjectManager.java:140)
 at net.sf.jpasecurity.entity.EntityPersister.getUnsecureObject(EntityPersister.java:240)
 at net.sf.jpasecurity.entity.EntityPersister.merge(EntityPersister.java:73)
 at net.sf.jpasecurity.persistence.DefaultSecureEntityManager.merge(DefaultSecureEntityManager.java:130)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)
 at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365)
 at $Proxy1122.merge(Unknown Source)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)
 at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
 at $Proxy1013.merge(Unknown Source)
 at com.nestorurquiza.dao.CrudDaoImpl.update(CrudDaoImpl.java:105)
 at com.nestorurquiza.service.impl.CrudServiceImpl.update(CrudServiceImpl.java:45)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)
 at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
 at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
 at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
 at $Proxy1037.update(Unknown Source)

This is most likely because the proxy does not implement the default contructor in which case the Abstract class is the one attempted to be instantiated originating the Exception.

But the bottom line of this post is to serve as a little bit of education to those young fellas who are catching up with programming and those experienced ones that love over bloated Enterprise Design up front.

Please guys, try to keep it simple and do not fear refactoring. Embrace change and hard work. You will find yourself applying patterns as a result of pragmatism rather than as a result of that new cool design you learned from GOF alike book on Patterns.

Tuesday, August 09, 2011

BHUB: Allow user and password from any URL

The BHUB philosophy is a unique entry point for all the business logic. A Controller makes that happen and there is no question on the big savings. The logic can be used from a CLI script (even pure curl can do the job), it can be of course croned, it can be used from any device (handhelds, desktops, appliances). You get for free every single security you applied in your web tier and I better stop right here because I have written about this several times.

The common way to interact with BHUB would be to get a session, security token from an entry point let us say a login service and from there on keep requesting using that information.

It would be ideal though that the entry point could be any page. In other words allow the first request to be actually not just login but a service request where you provide login information.

In order to accomplish this we will need to hook into Spring once again. Just a custom filter will do the trick. Declare it and assign some permissions for the URLs. In this case I want to allow direct access to certain role (the API role) and I will be opening that functionality to just the pure CLI Controllers which of course does not mean that we cannot allow this functionality for the complete BHUB Service Suite:

<beans:bean id="customLoginFilter" class="com.nestorurquiza.web.filter.CustomLoginFilter"/>
<custom-filter  before="FORM_LOGIN_FILTER" ref="customLoginFilter" /> 
<http auto-config="true" use-expressions="true" access-decision-manager-ref="accessDecisionManager" disable-url-rewriting="true">
  <intercept-url pattern="/cli/**" access="hasRole('ROLE_API')" />


Here is the Filter code.
package com.nestorurquiza.web.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
import org.springframework.security.web.util.TextEscapeUtils;

import com.nestorurquiza.utils.CsrfUtil;
import com.nestorurquiza.web.WebConstants;

/**
 * Allowing the creation of a session on the fly when requesting any URL
 * We authenticate the user if not authenticated in the case a user and password is provided 
 * @author nestor
 *
 */
public class CustomLoginFilter implements Filter 
{
    private static final Logger log = LoggerFactory.getLogger(CustomLoginFilter.class);
    
    @Autowired
    UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter;
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException 
    {
        HttpServletRequest httpRequest = ((HttpServletRequest) request);
        String uri = httpRequest.getRequestURI();
        if(! uri.contains(".")) {
            HttpServletResponse httpResponse = ((HttpServletResponse) response);
            SecurityContext securityContext = SecurityContextHolder.getContext();
            String method = httpRequest.getMethod();
            String userName = request.getParameter("j_username");
            if(userName != null && "POST".equals(method) && (securityContext == null || securityContext.getAuthentication() == null || !securityContext.getAuthentication().isAuthenticated())) {
                try {
                    Authentication auth = usernamePasswordAuthenticationFilter.attemptAuthentication(httpRequest, httpResponse);
                    securityContext.setAuthentication(auth);
                    SecurityContextHolder.setContext(securityContext);
                    httpRequest.getSession().setAttribute("SPRING_SECURITY_CONTEXT", securityContext);
                    httpRequest.getSession().setAttribute(UsernamePasswordAuthenticationFilter.SPRING_SECURITY_LAST_USERNAME_KEY, TextEscapeUtils.escapeEntities(userName));
                    if(auth.isAuthenticated()) {
                        //Initialize CSRF token
                        CsrfUtil.initializeCsrfToken(httpRequest);
                        //Set the token as an attribute in the request to make it pass the security check
                        httpRequest.setAttribute(WebConstants.CSRF_TOKEN, httpRequest.getSession().getAttribute(WebConstants.CSRF_TOKEN));
                    }
                } catch (Exception e){
                    log.info("User could not be authenticated. We go on ...");
                }
                
            }
        }
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() 
    {   

    }

    @Override
    public void init(FilterConfig config) throws ServletException 
    {
    
    }
    
    private Cookie getRememberMeCookie(Cookie[] cookies) {
        if (cookies != null)
          for (Cookie cookie : cookies) {
            if (AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY.equals(cookie.getName())) {
              return cookie;
            }
          }
        return null;
    }
}

Tainting LDAP data with Talend

Even though I solved this through the use of a nodeJS script I wanted to get the problem solved from Talend.

Here I discuss how to do it from Talend. There are still some outstanding issues.

As you can see in the picture I am reusing the list of white listed emails from a hashmap (tHashOutput_9). Only one connection is done to the input LDAP server which needs normalization (tNormalize) for group/uniquemember. A tJavaRow is responsible for adding a column containing just the uniquemember email for filtering purposes executed by tMap_1. tLDAPOutput_3 inserts the root elements while tLDAPOutput_1 and tLDAPOutput_2 insert users and groups respectively. Note that the latest two are in a separate subjob to be able to create the root entries before. Again the use of hashes allow to communicate both subjobs.


Install gcc in Ubuntu

The Linux sysadmin must build from sources from time to time. It makes sense then to have the C environment ready. In Ubuntu all you need to do is to follow the below commands:
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install build-essential
gcc --version

Followers