You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by jeffc <je...@bcbsil.com> on 2014/05/01 00:05:29 UTC

Re: PolicyException when using BST with custom ValueType

Lastly the Policy Interceptor:

It is this class I least understand all of what it is doing.  
The  WSSecSmSessionToken which extends WSSecBase actually build the BST
token and puts the Siteminder session token in it and then adds it to
security header.

package com.hcsc.security.sts;

import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.headers.Header;
import org.apache.cxf.helpers.CastUtils;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.helpers.XMLUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.interceptor.security.DefaultSecurityContext;
import org.apache.cxf.security.SecurityContext;
import org.apache.cxf.transport.http.AbstractHTTPDestination;
import org.apache.cxf.ws.policy.AssertionInfo;
import org.apache.cxf.ws.policy.AssertionInfoMap;
import org.apache.cxf.ws.security.policy.SP12Constants;
import org.apache.cxf.ws.security.wss4j.AbstractTokenInterceptor;
import org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.WSSConfig;
import org.apache.ws.security.WSSecurityEngineResult;
import org.apache.ws.security.WSSecurityException;
import org.apache.ws.security.handler.WSHandlerConstants;
import org.apache.ws.security.handler.WSHandlerResult;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.w3c.dom.Element;
import javax.security.auth.Subject;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class SmSessionAssertionInterceptor extends AbstractTokenInterceptor
{
    // class level logger
    private static final Logger logger =
LoggerFactory.getLogger(SmSessionAssertionInterceptor.class);
    // spring context
    ClassPathXmlApplicationContext context;
    // configuration holder
    Configuration config;

    public SmSessionAssertionInterceptor() {
        super();
        //context = new ClassPathXmlApplicationContext(new
String[]{"classpath*:applicationContext.xml"});

        //config = (Configuration) context.getBean("configurationManager");
    }

    protected void processToken(SoapMessage soapMessage) {
        // method's name
        String methodName = "processToken()";

        logger.info(methodName + ": entered.");

        Header h = findSecurityHeader(soapMessage, false);
        if (h == null)
            return;

        Element el = (Element) h.getObject();
        Element child = DOMUtils.getFirstElement(el);
        while (child != null) {
            if (WSConstants.BINARY_TOKEN_LN.equals(child.getLocalName())
                    && WSConstants.WSSE_NS.equals(child.getNamespaceURI())
                    &&
Constants.VALUE_TYPE_SMSESSION.equals(child.getAttribute(Constants.ATTR_NAME_VALUE_TYPE)))
{
                try {
                    final SmSessionTokenPrincipal princ =
getPrincipal(child, soapMessage);

                    if (princ != null) {
                        List<WSSecurityEngineResult> v = new
ArrayList<WSSecurityEngineResult>();

                        int action = WSConstants.BST;

                        v.add(0, new WSSecurityEngineResult(action, princ,
null, null, null));
                        List<WSHandlerResult> results =
CastUtils.cast((List<?>) soapMessage.get(WSHandlerConstants.RECV_RESULTS));

                        if (results == null) {
                            results = new ArrayList<WSHandlerResult>();
                            soapMessage.put(WSHandlerConstants.RECV_RESULTS,
results);
                        }

                        WSHandlerResult rResult = new WSHandlerResult(null,
v);
                        results.add(0, rResult);

                        assertTokens(soapMessage, princ, false);
                        soapMessage.put(WSS4JInInterceptor.PRINCIPAL_RESULT,
princ);

                        SecurityContext sc =
soapMessage.get(SecurityContext.class);

                        if (sc == null || sc.getUserPrincipal() == null) {
                            Subject subject =
createSubject(princ.getName());
                            soapMessage.put(SecurityContext.class,
createSecurityContext(princ, subject));
                        }
                    }
                }
                catch (WSSecurityException ex) {
                    throw new Fault(ex);
                }
            }
            child = DOMUtils.getNextElement(child);
        }

        logger.info(methodName + ": exiting...");
    }

    protected void addToken(SoapMessage soapMessage) {
        // method's name
        String methodName = "addToken()";

        logger.info(methodName + ": entered.");

        SmSessionToken token = assertTokens(soapMessage);
        logger.debug(methodName + ": token: [" + token + "]");

        Header h = findSecurityHeader(soapMessage, true);
        logger.debug(methodName + ": h: [" + h + "]");

        WSSecSmSessionToken builder = addSmSessionToken(soapMessage, token);
        logger.debug(methodName + ": builder: [" + builder + "]");

        if (builder == null) {
            AssertionInfoMap aim = soapMessage.get(AssertionInfoMap.class);
            logger.debug(methodName + ": aim: [" + aim + "]");
            Collection<AssertionInfo> ais =
aim.getAssertionInfo(Constants.QN_SMSESSION_TOKEN);
            logger.debug(methodName + ": ais: [" + ais + "]");

            for (AssertionInfo ai : ais)
                if (ai.isAsserted())
                    ai.setAsserted(false);

            return;
        }

        Element el = (Element) h.getObject();
        builder.prepare(el.getOwnerDocument());
        el.appendChild(builder.getSmSessionTokenElement());

        logger.info(methodName + ": exiting...");
    }

    protected WSSecSmSessionToken addSmSessionToken(SoapMessage message,
SmSessionToken token) {
        // method's name
        String methodName = "addSmSessionToken()";

        logger.info(methodName + ": entered.");

        String smSession =
"qau2xn3J4MRjG4kKVokU7In/410XJu5hS8aGPihhsAfKCVzhi/NTmG8lKMsXLBSVEsoMRBLexwSWUjT/eEFXXuk5xFPEKDAFu/uwKfwo+Ila2CydzdCppYRLE8nYUKnw9rq0KiwPWohJBkUH0asMCBrRueICl5ue3VeZA/L9MAhtX6cNbH20aNtlmqIT8E5ERIp+GxKVi60Bx4jI5DS4/znLvGOC1MYJy8n9eeK4Ddlm2qFaUuyrHFL5fcFFm1x4o1hDP3OvoUQ8aeFnTJuyQ8w0RjTjlrWA3MdSPeBQmxh2pYC4CmmyW7DtmgyrNMbPNs2Pn+YHQ2qYXMyFdxGqIenmXepFkmyqTobJ451krYRVprbUdMOi9J1spPhzpo9iApY1zgPtVOMmjGzYZkv2Vyfuo016ACNkc+TrWiyoOCjljLjMpvDRrBGG3balG7xhWV0hfaBSmrMSzn/OfFn2NG+8sCGMvHqmpuPlzq5Y0AEM+z21r7hEDTqRl8GZS1ksLsrz1D3qAN5Bl4q1fd/lKNUr4KnwCtgVuOYfhnNA/NcjboLLOPzSUPqHgkdavILA2RtXkr/Uqc7L2FEe4zfaFQfcZKsE5jB8xN86gQ4g2DRsptFR7Xmqzyqmb9Cfebj8zPfEziMdU5q+5g1E9Lv7p+pQCoHHVY5Yulb9A0/T6oj65k4JvSXNz74BzIIjVXwGXLzbS5HuEalgJNkYnbm7RdIm6zLgafSXvjripuQ6fG4ED96nYuPirn8RqQyDohLECXvEnM8ODT8D3yc/emJedvlQ88kvxZ22uS9UbSKhNqueUYOr0tyHkx0uVoCb8YcgbQMXNhUBsLvPO8jLPN0wHgxh8lCljlAeyc1wrnvARcfCaZFtmIRCz28U89ndmEdhmcJTQy2GQvwFKOHWNDKteRdPp4xn9lc5";

        WSSConfig wssConfig = (WSSConfig)
message.getContextualProperty(WSSConfig.class.getName());
        if (wssConfig == null) {
            wssConfig = WSSConfig.getNewInstance();
        }

        WSSecSmSessionToken builder = new WSSecSmSessionToken(wssConfig);

        builder.setTokenValue(smSession);

        logger.info(methodName + ": exiting...");

        return builder;
    }


    protected SmSessionToken assertTokens(SoapMessage soapMessage) {
        // method's name
        String methodName = "assertTokens()";
        // return object
        SmSessionToken smSessionToken = null;

        logger.info(methodName + ": entered.");

        try {
            smSessionToken = (SmSessionToken) assertTokens(soapMessage,
Constants.QN_SMSESSION_TOKEN, true);
        }
        catch (Exception e) {
            logger.error(methodName + ": exception caught: " +
e.getMessage());
        }
        finally {
            logger.debug(methodName + ": exiting...");
        }

        return smSessionToken;
    }

    protected SmSessionTokenPrincipal getPrincipal(Element tokenElement,
final SoapMessage message) throws WSSecurityException {
        // method's name
        String methodName = "getPrincipal()";
        // return object
        SmSessionTokenPrincipal principal;

        logger.info(methodName + ": entered.");

        String smSession = null;

        logger.debug(methodName + ": tokenElement: [" +
XMLUtils.toString(tokenElement) + "]");

        String valueType =
tokenElement.getAttribute(Constants.ATTR_NAME_VALUE_TYPE);
        logger.debug(methodName + ": valueType: [" + valueType + "]");

        if (valueType != null &&
valueType.equals(Constants.VALUE_TYPE_SMSESSION))
            smSession = tokenElement.getTextContent();

        logger.debug(methodName + ": smSession: [" + smSession + "]");

        try {
            boolean isValidEcho = true;

            if (!isValidEcho)
                throw new WSSecurityException("SMSESSION validation
failed...");

            principal = new SmSessionTokenPrincipal("eaa0001");
        }
        catch (Exception e) {
            logger.error(methodName + ": exception caught: " +
e.getMessage());
            throw new WSSecurityException(e.getMessage(), e);
        }
        finally {
            logger.debug(methodName + ": exiting...");
        }

        return principal;
    }

    private SmSessionToken assertTokens(SoapMessage message,
SmSessionTokenPrincipal princ, boolean signed) {
        // method's name
        String methodName = "assertTokens()";

        logger.info(methodName + ": entered.");

        AssertionInfoMap aim = message.get(AssertionInfoMap.class);
        Collection<AssertionInfo> ais =
aim.getAssertionInfo(Constants.QN_SMSESSION_TOKEN);

        SmSessionToken token = null;
        for (AssertionInfo ai : ais) {
            token = (SmSessionToken) ai.getAssertion();
            ai.setAsserted(true);
        }

        ais = aim.getAssertionInfo(SP12Constants.SUPPORTING_TOKENS);
        for (AssertionInfo ai : ais) {
            ai.setAsserted(true); // this flag determines the assertion
result
        }

        if (signed || isTLSInUse(message)) {
            ais =
aim.getAssertionInfo(SP12Constants.SIGNED_SUPPORTING_TOKENS);
            for (AssertionInfo ai : ais) {
                ai.setAsserted(true);
            }
        }

        logger.info(methodName + ": exiting...");

        return token;
    }

    protected Subject createSubject(String name) throws SecurityException {
        return null;
    }

    protected SecurityContext createSecurityContext(final Principal p,
Subject subject) {
        return new DefaultSecurityContext(p, subject);
    }
}




--
View this message in context: http://cxf.547215.n5.nabble.com/PolicyException-when-using-BST-with-custom-ValueType-tp5743444p5743552.html
Sent from the cxf-user mailing list archive at Nabble.com.

Re: PolicyException when using BST with custom ValueType

Posted by Colm O hEigeartaigh <co...@apache.org>.
Ok, what you have done sounds about right. As the SiteMinder token thing is
not standard, CXF will not parse that policy and hence policy validation
fails.

Colm.


On Wed, Apr 30, 2014 at 11:05 PM, jeffc <je...@bcbsil.com> wrote:

> Lastly the Policy Interceptor:
>
> It is this class I least understand all of what it is doing.
> The  WSSecSmSessionToken which extends WSSecBase actually build the BST
> token and puts the Siteminder session token in it and then adds it to
> security header.
>
> package com.hcsc.security.sts;
>
> import org.apache.cxf.binding.soap.SoapMessage;
> import org.apache.cxf.headers.Header;
> import org.apache.cxf.helpers.CastUtils;
> import org.apache.cxf.helpers.DOMUtils;
> import org.apache.cxf.helpers.XMLUtils;
> import org.apache.cxf.interceptor.Fault;
> import org.apache.cxf.interceptor.security.DefaultSecurityContext;
> import org.apache.cxf.security.SecurityContext;
> import org.apache.cxf.transport.http.AbstractHTTPDestination;
> import org.apache.cxf.ws.policy.AssertionInfo;
> import org.apache.cxf.ws.policy.AssertionInfoMap;
> import org.apache.cxf.ws.security.policy.SP12Constants;
> import org.apache.cxf.ws.security.wss4j.AbstractTokenInterceptor;
> import org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor;
> import org.apache.ws.security.WSConstants;
> import org.apache.ws.security.WSSConfig;
> import org.apache.ws.security.WSSecurityEngineResult;
> import org.apache.ws.security.WSSecurityException;
> import org.apache.ws.security.handler.WSHandlerConstants;
> import org.apache.ws.security.handler.WSHandlerResult;
> import org.springframework.context.support.ClassPathXmlApplicationContext;
> import org.w3c.dom.Element;
> import javax.security.auth.Subject;
> import javax.servlet.http.Cookie;
> import javax.servlet.http.HttpServletRequest;
> import java.security.Principal;
> import java.util.ArrayList;
> import java.util.Collection;
> import java.util.List;
> import org.slf4j.Logger;
> import org.slf4j.LoggerFactory;
>
>
> public class SmSessionAssertionInterceptor extends AbstractTokenInterceptor
> {
>     // class level logger
>     private static final Logger logger =
> LoggerFactory.getLogger(SmSessionAssertionInterceptor.class);
>     // spring context
>     ClassPathXmlApplicationContext context;
>     // configuration holder
>     Configuration config;
>
>     public SmSessionAssertionInterceptor() {
>         super();
>         //context = new ClassPathXmlApplicationContext(new
> String[]{"classpath*:applicationContext.xml"});
>
>         //config = (Configuration) context.getBean("configurationManager");
>     }
>
>     protected void processToken(SoapMessage soapMessage) {
>         // method's name
>         String methodName = "processToken()";
>
>         logger.info(methodName + ": entered.");
>
>         Header h = findSecurityHeader(soapMessage, false);
>         if (h == null)
>             return;
>
>         Element el = (Element) h.getObject();
>         Element child = DOMUtils.getFirstElement(el);
>         while (child != null) {
>             if (WSConstants.BINARY_TOKEN_LN.equals(child.getLocalName())
>                     && WSConstants.WSSE_NS.equals(child.getNamespaceURI())
>                     &&
>
> Constants.VALUE_TYPE_SMSESSION.equals(child.getAttribute(Constants.ATTR_NAME_VALUE_TYPE)))
> {
>                 try {
>                     final SmSessionTokenPrincipal princ =
> getPrincipal(child, soapMessage);
>
>                     if (princ != null) {
>                         List<WSSecurityEngineResult> v = new
> ArrayList<WSSecurityEngineResult>();
>
>                         int action = WSConstants.BST;
>
>                         v.add(0, new WSSecurityEngineResult(action, princ,
> null, null, null));
>                         List<WSHandlerResult> results =
> CastUtils.cast((List<?>) soapMessage.get(WSHandlerConstants.RECV_RESULTS));
>
>                         if (results == null) {
>                             results = new ArrayList<WSHandlerResult>();
>
> soapMessage.put(WSHandlerConstants.RECV_RESULTS,
> results);
>                         }
>
>                         WSHandlerResult rResult = new WSHandlerResult(null,
> v);
>                         results.add(0, rResult);
>
>                         assertTokens(soapMessage, princ, false);
>
> soapMessage.put(WSS4JInInterceptor.PRINCIPAL_RESULT,
> princ);
>
>                         SecurityContext sc =
> soapMessage.get(SecurityContext.class);
>
>                         if (sc == null || sc.getUserPrincipal() == null) {
>                             Subject subject =
> createSubject(princ.getName());
>                             soapMessage.put(SecurityContext.class,
> createSecurityContext(princ, subject));
>                         }
>                     }
>                 }
>                 catch (WSSecurityException ex) {
>                     throw new Fault(ex);
>                 }
>             }
>             child = DOMUtils.getNextElement(child);
>         }
>
>         logger.info(methodName + ": exiting...");
>     }
>
>     protected void addToken(SoapMessage soapMessage) {
>         // method's name
>         String methodName = "addToken()";
>
>         logger.info(methodName + ": entered.");
>
>         SmSessionToken token = assertTokens(soapMessage);
>         logger.debug(methodName + ": token: [" + token + "]");
>
>         Header h = findSecurityHeader(soapMessage, true);
>         logger.debug(methodName + ": h: [" + h + "]");
>
>         WSSecSmSessionToken builder = addSmSessionToken(soapMessage,
> token);
>         logger.debug(methodName + ": builder: [" + builder + "]");
>
>         if (builder == null) {
>             AssertionInfoMap aim = soapMessage.get(AssertionInfoMap.class);
>             logger.debug(methodName + ": aim: [" + aim + "]");
>             Collection<AssertionInfo> ais =
> aim.getAssertionInfo(Constants.QN_SMSESSION_TOKEN);
>             logger.debug(methodName + ": ais: [" + ais + "]");
>
>             for (AssertionInfo ai : ais)
>                 if (ai.isAsserted())
>                     ai.setAsserted(false);
>
>             return;
>         }
>
>         Element el = (Element) h.getObject();
>         builder.prepare(el.getOwnerDocument());
>         el.appendChild(builder.getSmSessionTokenElement());
>
>         logger.info(methodName + ": exiting...");
>     }
>
>     protected WSSecSmSessionToken addSmSessionToken(SoapMessage message,
> SmSessionToken token) {
>         // method's name
>         String methodName = "addSmSessionToken()";
>
>         logger.info(methodName + ": entered.");
>
>         String smSession =
>
> "qau2xn3J4MRjG4kKVokU7In/410XJu5hS8aGPihhsAfKCVzhi/NTmG8lKMsXLBSVEsoMRBLexwSWUjT/eEFXXuk5xFPEKDAFu/uwKfwo+Ila2CydzdCppYRLE8nYUKnw9rq0KiwPWohJBkUH0asMCBrRueICl5ue3VeZA/L9MAhtX6cNbH20aNtlmqIT8E5ERIp+GxKVi60Bx4jI5DS4/znLvGOC1MYJy8n9eeK4Ddlm2qFaUuyrHFL5fcFFm1x4o1hDP3OvoUQ8aeFnTJuyQ8w0RjTjlrWA3MdSPeBQmxh2pYC4CmmyW7DtmgyrNMbPNs2Pn+YHQ2qYXMyFdxGqIenmXepFkmyqTobJ451krYRVprbUdMOi9J1spPhzpo9iApY1zgPtVOMmjGzYZkv2Vyfuo016ACNkc+TrWiyoOCjljLjMpvDRrBGG3balG7xhWV0hfaBSmrMSzn/OfFn2NG+8sCGMvHqmpuPlzq5Y0AEM+z21r7hEDTqRl8GZS1ksLsrz1D3qAN5Bl4q1fd/lKNUr4KnwCtgVuOYfhnNA/NcjboLLOPzSUPqHgkdavILA2RtXkr/Uqc7L2FEe4zfaFQfcZKsE5jB8xN86gQ4g2DRsptFR7Xmqzyqmb9Cfebj8zPfEziMdU5q+5g1E9Lv7p+pQCoHHVY5Yulb9A0/T6oj65k4JvSXNz74BzIIjVXwGXLzbS5HuEalgJNkYnbm7RdIm6zLgafSXvjripuQ6fG4ED96nYuPirn8RqQyDohLECXvEnM8ODT8D3yc/emJedvlQ88kvxZ22uS9UbSKhNqueUYOr0tyHkx0uVoCb8YcgbQMXNhUBsLvPO8jLPN0wHgxh8lCljlAeyc1wrnvARcfCaZFtmIRCz28U89ndmEdhmcJTQy2GQvwFKOHWNDKteRdPp4xn9lc5";
>
>         WSSConfig wssConfig = (WSSConfig)
> message.getContextualProperty(WSSConfig.class.getName());
>         if (wssConfig == null) {
>             wssConfig = WSSConfig.getNewInstance();
>         }
>
>         WSSecSmSessionToken builder = new WSSecSmSessionToken(wssConfig);
>
>         builder.setTokenValue(smSession);
>
>         logger.info(methodName + ": exiting...");
>
>         return builder;
>     }
>
>
>     protected SmSessionToken assertTokens(SoapMessage soapMessage) {
>         // method's name
>         String methodName = "assertTokens()";
>         // return object
>         SmSessionToken smSessionToken = null;
>
>         logger.info(methodName + ": entered.");
>
>         try {
>             smSessionToken = (SmSessionToken) assertTokens(soapMessage,
> Constants.QN_SMSESSION_TOKEN, true);
>         }
>         catch (Exception e) {
>             logger.error(methodName + ": exception caught: " +
> e.getMessage());
>         }
>         finally {
>             logger.debug(methodName + ": exiting...");
>         }
>
>         return smSessionToken;
>     }
>
>     protected SmSessionTokenPrincipal getPrincipal(Element tokenElement,
> final SoapMessage message) throws WSSecurityException {
>         // method's name
>         String methodName = "getPrincipal()";
>         // return object
>         SmSessionTokenPrincipal principal;
>
>         logger.info(methodName + ": entered.");
>
>         String smSession = null;
>
>         logger.debug(methodName + ": tokenElement: [" +
> XMLUtils.toString(tokenElement) + "]");
>
>         String valueType =
> tokenElement.getAttribute(Constants.ATTR_NAME_VALUE_TYPE);
>         logger.debug(methodName + ": valueType: [" + valueType + "]");
>
>         if (valueType != null &&
> valueType.equals(Constants.VALUE_TYPE_SMSESSION))
>             smSession = tokenElement.getTextContent();
>
>         logger.debug(methodName + ": smSession: [" + smSession + "]");
>
>         try {
>             boolean isValidEcho = true;
>
>             if (!isValidEcho)
>                 throw new WSSecurityException("SMSESSION validation
> failed...");
>
>             principal = new SmSessionTokenPrincipal("eaa0001");
>         }
>         catch (Exception e) {
>             logger.error(methodName + ": exception caught: " +
> e.getMessage());
>             throw new WSSecurityException(e.getMessage(), e);
>         }
>         finally {
>             logger.debug(methodName + ": exiting...");
>         }
>
>         return principal;
>     }
>
>     private SmSessionToken assertTokens(SoapMessage message,
> SmSessionTokenPrincipal princ, boolean signed) {
>         // method's name
>         String methodName = "assertTokens()";
>
>         logger.info(methodName + ": entered.");
>
>         AssertionInfoMap aim = message.get(AssertionInfoMap.class);
>         Collection<AssertionInfo> ais =
> aim.getAssertionInfo(Constants.QN_SMSESSION_TOKEN);
>
>         SmSessionToken token = null;
>         for (AssertionInfo ai : ais) {
>             token = (SmSessionToken) ai.getAssertion();
>             ai.setAsserted(true);
>         }
>
>         ais = aim.getAssertionInfo(SP12Constants.SUPPORTING_TOKENS);
>         for (AssertionInfo ai : ais) {
>             ai.setAsserted(true); // this flag determines the assertion
> result
>         }
>
>         if (signed || isTLSInUse(message)) {
>             ais =
> aim.getAssertionInfo(SP12Constants.SIGNED_SUPPORTING_TOKENS);
>             for (AssertionInfo ai : ais) {
>                 ai.setAsserted(true);
>             }
>         }
>
>         logger.info(methodName + ": exiting...");
>
>         return token;
>     }
>
>     protected Subject createSubject(String name) throws SecurityException {
>         return null;
>     }
>
>     protected SecurityContext createSecurityContext(final Principal p,
> Subject subject) {
>         return new DefaultSecurityContext(p, subject);
>     }
> }
>
>
>
>
> --
> View this message in context:
> http://cxf.547215.n5.nabble.com/PolicyException-when-using-BST-with-custom-ValueType-tp5743444p5743552.html
> Sent from the cxf-user mailing list archive at Nabble.com.
>



-- 
Colm O hEigeartaigh

Talend Community Coder
http://coders.talend.com