Thursday, January 30, 2014

Camel cxfendpoint to ActiveMQ queue


  • cxfendpoint expects an outgoing message to be present in order to be sent back; if an out endpoint posting the message to an ActiveMQ  broker is used this will not happen and a timeout error will occur
  • By default output of cxfendpoint message  payload  is of java.io.InputStream. An outgoing ActiveMQ endpoint will just ignore the payload and will save just the headers.
Below is the solution to above mentioned problems 9this must be included in the master ActiveMQ configuration file):
<?xml version="1.0" encoding="UTF-8"?>
<!--
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
    this work for additional information regarding copyright ownership.
    The ASF licenses this file to You under the Apache License, Version 2.0
    (the "License"); you may not use this file except in compliance with
    the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-->

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:cxf="http://camel.apache.org/schema/cxf"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
       http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd">


      <bean id="jmsConnectionFactory" 
         class="org.apache.activemq.ActiveMQConnectionFactory">
         <property name="brokerURL" value="vm://amq-broker?create=false" />
      </bean>
       
      <bean id="pooledConnectionFactory" 
         class="org.apache.activemq.pool.PooledConnectionFactory" init-method="start" destroy-method="stop">
         <property name="maxConnections" value="8" />
         <property name="connectionFactory" ref="jmsConnectionFactory" />
      </bean>
       
      <bean id="jmsConfig" 
         class="org.apache.camel.component.jms.JmsConfiguration">
         <property name="connectionFactory" ref="pooledConnectionFactory"/>
         <property name="concurrentConsumers" value="10"/>
      </bean>
       
      <bean id="activemq" 
          class="org.apache.activemq.camel.component.ActiveMQComponent">
          <property name="configuration" ref="jmsConfig"/>
       
          <!-- if we are using transacted then enable CACHE_CONSUMER (if not using XA) to run faster
               see more details at: http://camel.apache.org/jms 
          <property name="transacted" value="true"/>
          <property name="cacheLevelName" value="CACHE_CONSUMER" />
         -->
      </bean>      

    <!-- camelContext is the Camel runtime, where we can host Camel routes -->    
    <cxf:cxfEndpoint id="server"
                     address="http://localhost:8085/OTRS/service"
                     endpointName="s:BasicHttpBinding_ChangeStateOperations"
                     serviceName="s:ChangeStateService"
                     wsdlURL="examples\conf\wsdl\server.wsdl"
                     xmlns:s="http://tempuri.org/"/>
    
    
    
    <camelContext xmlns="http://camel.apache.org/schema/spring">
         <route>
            <from uri="cxf:bean:server?dataFormat=MESSAGE"/>
                <transform>
                  <simple>${bodyAs(String)}</simple>
                </transform>
                <wireTap uri="activemq:topic:otrs.statusChanged"/>
                <wireTap uri="stream:out"/>
                <transform>
                    <simple>
                        <![CDATA[
    <?xml version="1.0" encoding="utf-8"?>
    <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
      <s:Body>
        <TestWm1Response xmlns="http://tempuri.org/" />
      </s:Body>
    </s:Envelope>
                        ]]>
                    </simple>
                </transform>
            <!--to uri="cxf:bean:ocalculator?dataFormat=MESSAGE"/-->
        </route>
    </camelContext>
</beans>

Camel cxfenpoint in ActiveMQ 5.9.0

Using cxfendpoints in ActiveMQ requires deplyment of dependent jars in lib\Camel subdirectory. By default just core, jms and spring (2.12.1 version) are deployed.
In order to obtain required jars:

  • create a Maven pom.xml file with the following content:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>


    <groupId>org.apache.camel</groupId>

    <version>2.12.1</version>


    <artifactId>camel-example-console</artifactId>
    <packaging>jar</packaging>
    <name>Camel cxf</name>
    <description>camel-cxf dependencies</description>

    <dependencies>

        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-cxf</artifactId>
            <version>2.12.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-stream</artifactId>
            <version>2.12.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http-jetty</artifactId>
            <version>2.7.8</version>
        </dependency>
        
        <dependency>
          <groupId>org.eclipse.jetty.aggregate</groupId>
          <artifactId>jetty-all-server</artifactId>
          <version>8.1.14.v20131031</version>
        </dependency>            
        <dependency>
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>jetty-websocket</artifactId>
          <version>8.1.14.v20131031</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- Allows the example to be run via 'mvn compile exec:java' -->
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <configuration>
                    <mainClass>org.apache.camel.example.console.CamelConsoleMain</mainClass>
                    <includePluginDependencies>true</includePluginDependencies>
                </configuration>
            </plugin>
        </plugins>

    </build>

</project>
  • run the following command: mvn dependency:copy-dependencies
  • find in target\dependencies all required dependencies
Remark: because camel-cxf 2.12.1 depends on cxf-rt-transports-http-jetty 2.7.8 some newer versions of jetty jars will be aslo downloaded which will interfere with ActiveMQ already deployed jars (jetty-all-server and jetty-websocket, version 7.6.9.v20130131, lib\web ) so also jetty-all-server and jetty-websocket dependencies are downloaded. If this is not done web console will not work.

Put all jars in lib\camel.

Friday, December 27, 2013

Spring SAML with ADFS

Running Spring SAML based SP against ADFS might result in errors like the following captured in ADFS Event Log:
System.IdentityModel.SignatureVerificationFailedException: MSIS0038: SAML Message has wrong signature. Issuer: 'xxx'.
It looks like MS update KB2843638 is the cause so try removing the update.
PS: MS relesed another update that solved the issue according to http://social.technet.microsoft.com/Forums/en-US/4acc04b7-aac7-43e9-ba50-9570503045f9/msis0038-saml-message-has-wrong-signature

jBPM and H2 database

By default jBPM uses a demo H2 database. When doing a new deployment the old database is still used since it is stored in user profile directory. If you want to start with a new, fresh copy just delete from  users\<user-name>jbpm.*.db files

Logging Rest calls in JBoss

Trying to use HTTP request logging will be of no use since REST calls use different content type than regular HTTP cals.
A custom server-side REST interceptor can do our job.

  • Create a maven based project and include dependencies to resteasy-jaxrs (groupId org.jboss.resteasy),resteasy-jaxb-provider (groupId org.jboss.resteasy) and servlet-api (groupId javax.servlet)
  • Create a class that contains our interceptor:

@Provider
@ServerInterceptor
public class RestEasyLogger implements PreProcessInterceptor, MessageBodyWriterInterceptor {

    Logger logger = Logger.getLogger(RestEasyLogger.class);

    @Context
    HttpServletRequest servletRequest;

    public ServerResponse preProcess(HttpRequest request,
            ResourceMethod resourceMethod) throws Failure,
            WebApplicationException {

        logger.info("Receiving request : " + servletRequest.getRequestURL().toString());

        BufferedInputStream bis = new BufferedInputStream(request.getInputStream());
        ByteArrayOutputStream buf = new ByteArrayOutputStream();
        String content = "";
        int result;
        try {
            result = bis.read();
            while (result != -1) {
                byte b = (byte) result;
                buf.write(b);
                result = bis.read();
            }
        } catch (IOException ex) {
            java.util.logging.Logger.getLogger(RestEasyLogger.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            content = buf.toString("UTF-8");
            ByteArrayInputStream bi = new ByteArrayInputStream(buf.toByteArray());
            request.setInputStream(bi);
        } catch (UnsupportedEncodingException ex) {
            java.util.logging.Logger.getLogger(RestEasyLogger.class.getName()).log(Level.SEVERE, null, ex);
        }

        logger.info("\t\t" + content);

        return null;
    }

    public void write(MessageBodyWriterContext mbwc) throws IOException, WebApplicationException {

        OutputStream oStream = mbwc.getOutputStream();
        ByteArrayOutputStream buf = new ByteArrayOutputStream();
        mbwc.setOutputStream(buf);
        mbwc.proceed();
        String content = buf.toString("UTF-8");
        oStream.write(buf.toByteArray());
        mbwc.setOutputStream(oStream);
        logger.info("\t\t" + content);

    }


  • Configure logging for our class in standalone-full.xml (or whatever configuration file you use for JBoss start-up)

         <subsystem xmlns="urn:jboss:domain:logging:1.1">
            <console-handler name="CONSOLE">
                <level name="INFO"/>
                <formatter>
                    <pattern-formatter pattern="%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n"/>
                </formatter>
            </console-handler>
            <periodic-rotating-file-handler name="FILE">
                <formatter>
                    <pattern-formatter pattern="%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n"/>
                </formatter>
                <file relative-to="jboss.server.log.dir" path="server.log"/>
                <suffix value=".yyyy-MM-dd"/>
                <append value="true"/>
            </periodic-rotating-file-handler>
            <periodic-rotating-file-handler name="FILE-RESTEASY">
                <formatter>
                    <pattern-formatter pattern="%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n"/>
                </formatter>
                <file relative-to="jboss.server.log.dir" path="rs.log"/>
                <suffix value=".yyyy-MM-dd"/>
                <append value="true"/>
            </periodic-rotating-file-handler>
            <logger category="com.arjuna">
                <level name="WARN"/>
            </logger>
            <logger category="org.apache.tomcat.util.modeler">
                <level name="WARN"/>
            </logger>
            <logger category="sun.rmi">
                <level name="WARN"/>
            </logger>
            <logger category="jacorb">
                <level name="WARN"/>
            </logger>
            <logger category="jacorb.config">
                <level name="ERROR"/>
            </logger>
            <logger category="ro.mycompany.jbpm.resteasy.logging.RestEasyLogger" use-parent-handlers="false">
                <level name="DEBUG"/>
                <handlers>
                    <handler name="FILE-RESTEASY"/>
                </handlers>
            </logger>
            <root-logger>
                <level name="INFO"/>
                <handlers>
                    <handler name="CONSOLE"/>
                    <handler name="FILE"/>
                </handlers>
            </root-logger>
        </subsystem>



  • Deploy the resulted jar inside the targeted war (inside WEB_INF\lib)
  • Do some REST calls; you should be able to see detailed info in standalone\log\rs.log

Thursday, October 31, 2013

Install and configure OpenAM for Spring SAML (on Windows)


  • assign a FQDN to 127.0.0.1 in hosts (like localhost.domain.home)
  • Install Tomcat as a service (7 at the moment this post was written)
  • Change the default HTTP port from 8080 to whatever value is required to avoid conflicts (in ...\Tomcat 7.0\conf\server.xml)
  • Restart the service
  • Download OpenAM distribution (I have used OpenAM-12.0.0-SNAPSHOT_nightly_20131021since the stable 10 version had a known issue on signing SAML assertions due to a problem in JDK 7_u25)
  • Extract distribution content, rename OpenAM-12.0.0-SNAPSHOT.war to openam.war
  • Copy openam.war to ...Tomcat 7.0\webapps
  • Browse to http://<server>:<port>/openam
  • Run the custom configuration (the default has a problem with generating the default domain for cookies) 
    • Use .domain.home as cockie domain (notice the leading dot)
    • Use the embedded LDAP (OpenDJ)
  • When the configuration is finnished login with amadmin/<password>
  • Choose "Create a hosted Identity Provider"
    • Choose the test signing key (or another if previously installed) if your SP requires signed/encripted assertions
    • Choose a name for the circle of trust
    • Press Configure
  • Add a SP in the same circle of trust:
    • Choose "Create a remote Service Provider"
    • Use the option to upload the metadata from a file (or specify on URL)
    • Press Configure
  • Configure attributes to be retrieved from data store
    • Go to Access Control->Top Level Realm->Data Stores->Embedded
    • Use the New Value/Add to add required (missing) attributes to be retrieved from the data store (like isMemberOf); 
      • attribute list is more generic and notr specific to the actual data store
      • use a LDAP browser to see actual attributes
  • Configure the mapping between required  assertion attributes (to be sent in SAML Response) and data store attributes:
    • Go to Federation->target IdP->Assertion Processing
    • In Attribute Mapper->Attribute map section use New Value->Add to add mappings (like isMemberOf=isMemberOf)
    • Save
  • Restart OpenAM or Tomcat; without restarting previously configured attribute mapping will not take place
Adding users:
  • Access Control->Top Level Realm
    • Group:add new groups
    • User: add/configure users
      • Be sure to fill in the field that the SP has configured as a potential Name ID (like email) otherwise an exception will be thrown (and recorded in OpenAM log) and an error will be sent back as a SAML Response

On non expected behavior check logs in openam configuration folder (default c:\openam): 
  • C:\openam\openam\debug
  • C:\openam\openam\log





Browsing OpenAM default LDAP store (OpenDJ)

When you need to configures attributes that will be sent in SAML response back to Service Provider you might need to know what actually is available and what are the specific names/formats.

For that purpose you need a LDAP browser (like Softera free tool).

  • Be sure OpenAM is started
  • Connect to embeded LADP using:
    • Host: localhost
    • Port: 50389
    • User Principal): cn=Directory Manager
    • Password: the password you initially configured for amadmin
  • Be sure to select (on object's properties): Display operational attributes/Display all