A "how to" guide to "delegate" kerberos token to REST based data source in Teiid

Version 2

    The usecase is, I have REST web service that is secured through SPNEGO/Kerberoes. The user can access though SSO when they are using the browser. Now, I need to access this web service from Teiid, where Teiid is also secured through same kerberos authentication. The requirement is to delagate the token negotiated during the JDBC login all the way to REST source, and avoid the second negotiation. To follow this you need basic operating knowledge of Teiid.

     

    Step 1: Create a REST Web Service

    In this guide my aim is to show you all the configuration needed to delegate kerberos token through Teiid JDBC to REST web service. For this purpose, I wrote article, in which I showed how to write a REST based service, secured by SPNEGO/kerberos. A practical "how-to" guide to implement kerberos authentication with Simple REST Web App. Please follow this article and create a sample web service, and test to make sure it works!

     

    Step 2: Create VDB

    Now we need to create VDB and required data sources to be consumed by the VDB. For my sample I used the following VDB

     

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <vdb name="kerberos" version="1">
    
        <description>Shows how to call REST Web with Kerberos Auth</description>
        <property name="cache-metadata" value="true"/>
    
        <model name="web">
            <source name="web" translator-name="rest" connection-jndi-name="java:/csdyn"/>        
             <metadata type="DDL"><![CDATA[
                CREATE FOREIGN PROCEDURE invoke(OUT result xml RESULT, IN binding string OPTIONS (ANNOTATION 'The invocation binding (HTTP, SOAP11, SOAP12).  May be set or allowed to default to null to use the default binding.'), IN action string OPTIONS (ANNOTATION 'With a SOAP invocation, action sets the SOAPAction.  With HTTP it sets the HTTP Method (GET, POST - default, etc.).'), IN request xml OPTIONS (ANNOTATION 'The XML document or root element that represents the request.  If the ExecutionFactory is configured in with a DefaultServiceMode of MESSAGE, then the SOAP request must contain the entire SOAP message.'), IN endpoint string OPTIONS (ANNOTATION 'The relative or abolute endpoint to use.  May be set or allowed to default to null to use the default endpoint address.'), IN stream boolean DEFAULT 'false' OPTIONS (ANNOTATION 'If the result should be streamed.'))
                OPTIONS (ANNOTATION 'Invokes a webservice that returns an XML result')
    
    
                CREATE FOREIGN PROCEDURE invokeHttp(OUT result blob RESULT, IN action string OPTIONS (ANNOTATION 'Sets the HTTP Method (GET, POST - default, etc.).'), IN request object OPTIONS (ANNOTATION 'The String, XML, BLOB, or CLOB value containing a payload (only for POST).'), IN endpoint string OPTIONS (ANNOTATION 'The relative or abolute endpoint to use.  May be set or allowed to default to null to use the default endpoint address.'), IN stream boolean DEFAULT 'false' OPTIONS (ANNOTATION 'If the result should be streamed.'), OUT contentType string)
                OPTIONS (ANNOTATION 'Invokes a webservice that returns an binary result')
            ]]> </metadata>
        </model>
    
        <model name="viewmodel" type="VIRTUAL">
             <metadata type="DDL"><![CDATA[
                 CREATE VIRTUAL PROCEDURE ping() RETURNS TABLE (msg string) AS 
                    select t.msg from 
                     (call web.invokeHTTP(action => 'GET', endpoint =>'http://primary.example.com:8080/kerberoes/hello/world')) w, 
                     XMLTABLE('/message' passing XMLPARSE(DOCUMENT w.result) columns msg string PATH 'text()') t;
            ]]> </metadata>
        </model>
    
        <translator name="rest" type="ws">
              <property name="DefaultBinding" value="HTTP"/>
              <property name="DefaultServiceMode" value="MESSAGE"/>
        </translator>
    </vdb>
    

     

    Step 3: Create Data Source

     

    Add the following xml fragment to resource-adapters subsystem in standalone-teiid.xml file

     

    <resource-adapter id="csdyn">
        <module slot="main" id="org.jboss.teiid.resource-adapter.webservice"/>
        <transaction-support>NoTransaction</transaction-support>
        <connection-definitions>
            <connection-definition class-name="org.teiid.resource.adapter.ws.WSManagedConnectionFactory" jndi-name="java:/csdyn" enabled="true" pool-name="csdyn">
                <config-property name="SecurityType">
                    Kerberos
                </config-property>
                <config-property name="EndPoint">
                 http/primary.example.com:8080/kerberoes/hello/world
                </config-property>
                <config-property name="ConfigName">
                    test
                </config-property>
                <config-property name="ConfigFile">
                    /home/rareddy/testing/jboss-eap-6.1/standalone/configuration/jboss-cxf-delegation.xml
                </config-property>
                <security>
                    <security-domain>passthrough-security</security-domain>
                </security>
            </connection-definition>
        </connection-definitions>
    </resource-adapter>
    

     

    We also need jboss-cxf-delegation.xml file above, the contents look like

     

    <beans xmlns="http://www.springframework.org/schema/beans"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:sec="http://cxf.apache.org/configuration/security"
            xmlns:http-conf="http://cxf.apache.org/transports/http/configuration"
            xsi:schemaLocation="http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd">
      
           <http-conf:conduit name="*.http-conduit">
               <http-conf:authorization>
                   <sec:AuthorizationType>Negotiate</sec:AuthorizationType>
               </http-conf:authorization>
           </http-conf:conduit>
    </beans>
    

     

    Note the "security-domain" in the data source configuration, what we are doing there is we are configuring the data source with security, so we need to define that in standalone-teiid.xml file in the "security" subsystem like below

     

    <security-domain name="passthrough-security" cache-type="default">
        <authentication>
            <login-module code="org.teiid.jboss.PassthroughIdentityLoginModule" flag="required" module="org.jboss.teiid">
                <module-option name="userName" value="guest"/>
                <module-option name="password" value="guest"/>
            </login-module>
        </authentication>
    </security-domain>
    

     

    I also attached my standalone-teiid.xml file for reference, but note that that may change as versions change, so only use for reference. Now the server is all set up.

     

    Step 4: Configure JDBC

     

    Follow the article How to implement Kerberos authentication with Teiid over JDBC and configure the JDBC client, and use VDB name defined above in your JDBC connection URL. Note you would not need to do any kerberos server tasks as you already covered them in the Step 1. Then issue a query like

     

    select t.* from (exec viewmodel.ping()) as t)
    

     

    You will see out put like

     

    Hello World! User=rareddy@EXAMPLE.COM
    

     

    That is data from the web service created in the Step 1, also shows the connected user.

     

    Hopefully that showed you how to configure Teiid to issue kerberos based REST call. Let me know if you got any suggestions

     

    Ramesh..