Latest Activity

Apache Syncope 1.2 tutorial - part I

Colm O hEigeartaigh - Thu, 11/06/2014 - 13:26
Apache Syncope is a powerful and flexible open source tool to manage and orchestrate user identities for the enterprise. Last year, I wrote a series of four tutorials on Apache Syncope. The first covered how to create an Apache Syncope project, how to set up a MySQL database for internal storage, and how to deploy Apache Syncope to Apache Tomcat. The second covered how to import user identities and attributes from a database (Apache Derby) into Syncope. The third covered how to import users and roles from an LDAP backend (Apache DS) into Syncope. Finally, the fourth tutorial covered the REST API of Apache Syncope, as well as a set of Apache CXF-based testcases to demonstrate how to use the REST API of Apache Syncope for authentication and authorization.

This will be the first post in a new set of tutorials for Apache Syncope, with a focus on updating the previous set of tutorials (based on Syncope 1.1) with some updated features and new functionality that is available in the recently released 1.2.0 release. In this post we will cover how to use the new UI installer for creating a Apache Syncope project and deploying it to a container. This tutorial can be viewed as a more user-friendly alternative to the first tutorial of the previous series. Please also see the Syncope documentation on using the installer.

1) Set up a database for Internal Storage

The first step in setting up a standalone deployment of Apache Syncope is to decide what database to use for Internal Storage. Apache Syncope persists internal storage to a database via Apache OpenJPA. In this article we will set up MySQL, but see here for more information on using PostgreSQL, Oracle, etc. Install MySQL in $SQL_HOME and create a new user for Apache Syncope. We will create a new user "syncope_user" with password "syncope_pass". Start MySQL and create a new Syncope database:

  • Start: sudo $SQL_HOME/bin/mysqld_safe --user=mysql
  • Log on: $SQL_HOME/bin/mysql -u syncope_user -p
  • Create a Syncope database: create database syncope; 

2) Set up a container to host Apache Syncope

The next step is to figure out in what container to deploy Syncope to. In this demo we will use Apache Tomcat, but see here for more information about installing Syncope in other containers. Install Apache Tomcat to $CATALINA_HOME. Now we will add a datasource for internal storage in Tomcat's 'conf/context.xml'. When Syncope does not find a datasource called 'jdbc/syncopeDataSource', it will connect to internal storage by instantiating a new connection per request, which carries a performance penalty. Add the following to 'conf/context.xml':

<Resource name="jdbc/syncopeDataSource" auth="Container"
    type="javax.sql.DataSource"
    factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
    testWhileIdle="true" testOnBorrow="true" testOnReturn="true"
    validationQuery="SELECT 1" validationInterval="30000"
    maxActive="50" minIdle="2" maxWait="10000" initialSize="2"
    removeAbandonedTimeout="20000" removeAbandoned="true"
    logAbandoned="true" suspectTimeout="20000"
    timeBetweenEvictionRunsMillis="5000" minEvictableIdleTimeMillis="5000"
    jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;
    org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"
    username="syncope_user" password="syncope_pass"
    driverClassName="com.mysql.jdbc.Driver"
    url="jdbc:mysql://localhost:3306/syncope?characterEncoding=UTF-8"/>

Uncomment the "<Manager pathname="" />" configuration in context.xml as well. The next step is to enable a way to deploy applications to Tomcat using the Manager app. Edit 'conf/tomcat-users.xml' and add the following:

<role rolename="manager-script"/>
<user username="manager" password="s3cret" roles="manager-script"/>

Next, download the JDBC driver jar for MySQL and put it in Tomcat's 'lib' directory. As we will be configuring a connector for a Derby resource in a future tutorial, also download the JDBC driver jar for Apache Derby and put it in Tomcat's 'lib' directory as well.

3) Run the Installer

Download and run the installer via 'java -jar syncope-installer-1.2.0-uber.jar'. You need to enter some straightforward values such as the installation path of the project, the Apache Maven home directory, the groupId/artifactId of the project, the directories where logs/bundles/configuration are stored.


Next, select "MySQL" as the database technology from the list, and give "syncope_user" and "syncope_pass" as the username + password, or whatever you have configured earlier when setting up MySQL. Select "Tomcat" as the application server (make sure the 'syncopeDataSource' is checked), and enter values for the address, port, manager username and password:


The installer will then create a Apache Syncope project + deploy it to Tomcat:


When the installer has finished, startup a browser and go to "localhost:8080/syncope-console", logging in as "admin/password". You should see the following:

Categories: Colm O hEigeartaigh

Security semantics of SAML SubjectConfirmation methods in Apache WSS4J/CXF

Colm O hEigeartaigh - Mon, 11/03/2014 - 17:27
A recent blog post covered two new security advisories issued for Apache CXF in relation to SAML tokens. In particular, one advisory dealt with the enforcement of the security semantics of SAML SubjectConfirmation methods when used with the TransportBinding:
There are different security requirements associated with SAML
SubjectConfirmation methods. These security requirements are not properly enforced in Apache CXF when used with the TransportBinding, leaving endpoints that rely on SAML for authentication vulnerable to types of spoofing attacks.In this post I will recap the security requirements that are associated with SAML SubjectConfirmation methods in the latest CXF releases:
  • Holder-of-Key: If the subject confirmation method is "holder-of-key", there must be some proof-of-possession of the key associated with the subject of the assertion. CXF will enforce that either the key was used to sign some portion of the SOAP request, or alternatively the subject credential of the SAML Assertion must match a client certificate credential when TLS with client authentiction is used.
  • Sender-Vouches: If the subject confirmation method is "sender-vouches", then CXF will enforce that the SAML Assertion and SOAP Body are signed by the same signature. Alternatively, it will check that TLS with client authentication is used.
  • Bearer: The SAML Assertion must be signed (with an internal XML Signature) by default. This can be configured in the latest WSS4J releases.
In addition, the SamlAssertionValidator in WSS4J now enforces that at least one of the standard SubjectConfirmation methods (as listed above) is present. It is also possible to specify a given SubjectConfirmation method that is required.
Categories: Colm O hEigeartaigh

Using Apache JMeter to load test Apache CXF endpoints

Colm O hEigeartaigh - Fri, 10/31/2014 - 18:32
Apache JMeter is a graphical tool that can be used to load-test your web applications. I created a new project in my github repo that creates a web application with a number of CXF endpoints, as well as a JMeter configuration file that can be used to load test the endpoints. The benefit of doing this kind of testing is to figure out how responsive various (security) protocols might be under load. In addition, the project uncovered a couple of threading issues surrounding policy handling, which were fixed by Dan Kulp in CXF 3.0.1.

The endpoints that are exposed in the application are:
  • /doubleit/services/doubleitnosecurity - No security at all. This can be used to test throughput over plaintext and TLS.
  • /doubleit/services/doubleittransport - This uses a Transport binding with a UsernameToken supporting token. The UsernameToken is just validated by a simple CallbackHandler on the service side. 
  • /doubleit/services/doubleitsymmetric - This uses a Symmetric binding with a UsernameToken supporting token. The UsernameToken is just validated by a simple CallbackHandler on the service side. 
  • /doubleit/services/doubleitsymmetricstreaming - This is the same as per the symmetric case above, except that it uses the new streaming WS-Security implementation available in Apache CXF 3.0.0. 
  • /doubleit/services/doubleitasymmetric - This uses a Asymmetric binding. Authentication is established by a certificate chain. 
  • /doubleit/services/doubleitasymmetricstreaming - Same as for the asymmetric case above, except that it uses the new streaming WS-Security implementation available in Apache CXF 3.0.0. 
Simply build the project with "mvn clean install" and drop the resulting .war file into your container (e.g. Apache Tomcat). Then start up JMeter + import the configuration file and run the tests.

    Categories: Colm O hEigeartaigh

    JSR-370: Even Better JAX-RS on the way

    Sergey Beryozkin - Thu, 10/30/2014 - 11:29
    No doubt JAX-RS 2.0 (JSR-339) has been, is and will be a success - a lot has been written  about the top features JAX-RS 2.0 offers. It is still very much a relevant story for many developers who have their REST services being migrated to JAX-RS 2.0, it is not always easy for a given production to switch to a new specification's API fast.

    But JAX-RS 2.0 is not the end of JAX-RS as such. So the fact JSR-370 (JAX-RS 2.1) is now active is a very good news for all of us working with or interested in JAX-RS.
    Have a look at the "Request" section and check the list of the improvements and new features that the specification will cover. Good stuff. Note the effort will be made to have JAX-RS applications much better prepared for supporting Web-based UI frontends. Another thing to note is the fact it will be Java 8 based so expect Java 8 features making themselves visible in JAX-RS 2.1 API, Marek and Santiago will come up with some very cool API ideas.

    All is great in the JAX-RS space. Explore it and enjoy !

    Categories: Sergey Beryozkin

    Two new security advisories for Apache CXF

    Colm O hEigeartaigh - Fri, 10/24/2014 - 20:10
    Two new security advisories have been released for Apache CXF, please see the CXF security advisories page for the details:
    • CVE-2014-3623: Apache CXF does not properly enforce the security semantics of SAML SubjectConfirmation methods when used with the TransportBinding
    • CVE-2014-3584: Apache CXF JAX-RS SAML handling is vulnerable to a Denial of Service (DoS) attack
    If you are using SAML SSO or else SAML tokens with the WS-SecurityPolicy Transport binding you should upgrade to either CXF 2.7.13 or 3.0.2.
    Categories: Colm O hEigeartaigh

    Apache CXF Authentication and Authorization test-cases IV

    Colm O hEigeartaigh - Thu, 10/23/2014 - 16:36
    This is the fourth in a series of posts on authentication and authorization test-cases for web services using Apache CXF. The first focused on different ways to authenticate and authorize UsernameTokens for JAX-WS services. The second looked at more advanced examples such as using Kerberos, WS-Trust, XACML, etc. The third looked at different ways of achieving SSO in CXF for both JAX-WS and JAX-RS services. This post gives some examples of authenticating and authorizing JAX-RS services in Apache CXF. I also included the SSO examples relevant to JAX-RS from the previous post. The projects are:
    • cxf-jaxrs-xmlsecurity: This project shows how to use XML Signature (and Encryption) to secure JAX-RS services. In particular, see the AuthenticationTest.
    • cxf-jaxrs-sts: This project demonstrates how to use HTTP/BA for authentication for JAX-RS, where the credentials are dispatched as a UsernameToken are dispatched to an STS instance for authentication. In addition, the project shows how to authorize the request by asking the STS for a SAML Token containing the roles of the user.
    • cxf-kerberos: This project (covered previously for JAX-WS) has been updated with a test that shows how to use Kerberos with JAX-RS.
    • cxf-saml-sso: This project shows how to leverage SAML SSO with Apache CXF to achieve SSO for a JAX-RS service. CXF supports the POST + redirect bindings of SAML SSO for JAX-RS endpoints. As part of this demo, a mock CXF-based IdP is provided which authenticates a client using HTTP/BA and issues a SAML token using the CXF STS. Authorization is also demonstrated using roles embedded in the issued SAML token. 
    • cxf-fediz-federation-sso: This project shows how to use the new CXF plugin of Apache Fediz 1.2.0 to authenticate and authorize clients of a JAX-RS service using WS-Federation. This feature will be documented more extensively at a future date, and is considered experimental for now. Please play around with it and provide feedback to the CXF users list.
    Categories: Colm O hEigeartaigh

    Apache CXF Fediz 1.1.2 released

    Colm O hEigeartaigh - Wed, 10/22/2014 - 12:32
    Apache CXF Fediz 1.1.2 has been released. Apache CXF Fediz is a Single Sign-On (SSO) solution based on the WS-Federation Passive Requestor Profile. It consists of an Identity Provider (IdP) which leverages the Apache CXF STS to issue tokens, as well as a number of container-specific plugins (Jetty, Tomcat, Spring, etc.) to enable SSO for web applications. The issues fixed in the new release include an upgrade to CXF 2.7.13, support for claims mapping in the STS, kerberos authentication support in the IdP, amongst other fixes.
    Categories: Colm O hEigeartaigh

    Kerberos Credential Delegation support in Apache CXF

    Colm O hEigeartaigh - Tue, 10/21/2014 - 15:25
    Apache CXF provides full support for integrating Kerberos with JAX-WS and JAX-RS services. A previous tutorial (here and here) described how to set up Kerberos with WS-Security in CXF, where the client obtains a Kerberos service ticket and encodes it in the security header of the request, and where it is validated in turn by the service. In this post we will discuss support for kerberos credential delegation for JAX-WS clients and services in Apache CXF. For more information on using kerberos with JAX-RS please consult the CXF documentation.

    1) Kerberos Client Configuration

    CXF provides a number of JAX-WS properties that can be used to configure Kerberos on the client side (documented here under "Kerberos Configuration Tags"). Essentially there are two different ways of doing it. The client must explicitly allow kerberos credential delegation by setting a property.

    1.1) Create and configure a KerberosClient Object directly

    The KerberosClient in the CXF WS-Security runtime module is used to retrieve a kerberos ticket. It can be configured by setting various properties and then referenced via the JAX-WS property:
    • ws-security.kerberos.client - A reference to the KerberosClient class used to obtain a service ticket.
    The "requestCredentialDelegation" property of the KerberosClient must be set to "true" to allow credential delegation. Here is an example in Spring:

    <bean class="org.apache.cxf.ws.security.kerberos.KerberosClient" id="kerberosClient">
            <constructor-arg ref="cxf"/>
            <property name="contextName" value="bob"/>
            <property name="serviceName" value="bob@service.ws.apache.org"/>
            <property name="requestCredentialDelegation" value="true"/>
    </bean>

    <jaxws:client name="{service}port" createdFromAPI="true">
            <jaxws:properties>
                <entry key="ws-security.kerberos.client" value-ref="kerberosClient"/>
            </jaxws:properties>
    </jaxws:client>

    1.2) Use JAX-WS properties to configure Kerberos

    Rather than use the KerberosClient above, it is possible to configure Kerberos via JAX-WS properties:
    • ws-security.kerberos.jaas.context - The JAAS Context name to use for Kerberos.
    • ws-security.kerberos.spn - The Kerberos Service Provider Name (spn) to use.
    • ws-security.kerberos.is.username.in.servicename.form - Whether the Kerberos username is in servicename form or not.
    • ws-security.kerberos.use.credential.delegation - Whether to use credential delegation or not in the KerberosClient.
    • ws-security.kerberos.request.credential.delegation - Whether to request credential delegation or not in the KerberosClient.
    The latter property must be set to "true" on the client side to allow kerberos credential delegation.

    2) Kerberos Service Configuration

    A JAX-WS service validates a kerberos ticket received in the security header of a request via a KerberosTokenValidator. Here is an example:

    <bean id="kerberosValidator"
               class="org.apache.wss4j.dom.validate.KerberosTokenValidator">
            <property name="contextName" value="bob"/>
            <property name="serviceName" value="bob@service.ws.apache.org"/>
    </bean>
    <jaxws:endpoint ...>
            <jaxws:properties>
                <entry key="ws-security.bst.validator" value-ref="kerberosValidator"/>
            </jaxws:properties>
    </jaxws:endpoint>
       
    3) Using Kerberos Credential Delegation

    After a service has validated a kerberos token sent by the client, it can obtain another kerberos token "on behalf of" the client, assuming the client enabled credential delegation in the first place. To use the client credential for delegation the "useDelegatedCredential" property of the KerberosClient must be set to "true" (see here), or else the JAX-WS property "ws-security.kerberos.use.credential.delegation" must be set to "true" if not configuring Kerberos via the KerberosClient Object.

    To see how a concrete use-case for this functionality, take a look at the KerberosDelegationTokenTest in the CXF STS advanced systests. Here we have a backend service which requires a SAML Token issued by an STS. However, the clients only know how to obtain a Kerberos token. So we have an intermediary service which requires a Kerberos token. The clients enable credential delegation + send a ticket to the Intermediary. The Intermediary validates the ticket, then uses it to obtain a Kerberos token "OnBehalfOf" the client, which in turn is used to authenticate to the STS + retrieve a SAML Token, which is then forwarded on to the backend service.
    Categories: Colm O hEigeartaigh

    Integration Testing for STS Extensions with Jetty

    Jan Bernhardt - Thu, 10/16/2014 - 12:04
    Recently I had to develop some extensions (ClaimHandler, Validator) to the CXF STS. My problem at first was, how to write an integration test that proves the correct implementation of my extensions.

    At first I placed my Mockup classes and web config in the src/main folder from my maven project and added the jetty plugin to my pom.xml file. This way I was able to start my REST MockupService simply by typing mvn jetty:run on the console. After starting the service I was able to execute my test classes directly from Eclipse. But this approach did not satisfy me at all, because now I had lots of files in my main project folder, which would not be needed once I build and deploy my STS extensions to another STS installation. Somehow I needed to move all files (Mockup Service, Spring beans.xml, web.xml, etc.) to the test project folder.

    In this post I'll explain how to setup you maven pom file so that you can use Jetty in your integration test phase if your packaging goal is not a war file but a simple jar file instead and all your web configuration and classes are located in your test folder.

    There are two Blogs which I found very helpful to get my use case up and running:
    1. Run Jetty in the Maven life-cycle
    2. End-to-End Client-Server Integration Testing with Maven – Project Setup
    First of all I moved my complete src/main/webapp folder to src/test/webapp as well as src/main/resources to src/test/resources since I needed these files only for testing. The same was true for some of my classes in src/main/java which I moved to src/test/java. Now my src/main/ folder only contained my Java classes which I needed to provide my new STS extension.

    Next I modified my pom.xml file and changed the packaging from war to jar. My goal was to add this maven project later as a dependency to another project which would result as a lib in the STS war archive.
    Allocating dynamic network ports to avoid test failures caused by port collisionsTo get a dynamic port binding for my test services, I added a nice maven helper to my build allocating free ports for me:
    <project>
        . . .
        <build>
            . . .
            <plugins>
                . . .
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>build-helper-maven-plugin</artifactId>
                    <version>1.5</version>
                    <executions>
                        <execution>
                            <id>reserve-network-port</id>
                            <goals>
                                <goal>reserve-network-port</goal>
                            </goals>
                            <phase>process-test-resources</phase>
                            <configuration>
                                <portNames>
                                    <portName>jettyServerPort</portName>
                                    <portName>jettyServerStopPort</portName>
                                </portNames>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            <plugins>
        <build>
    <project>
    To ensure that my test classes can know the correct location of my Mock Services I simply set these dynamic values as a system property, which can be picked up in my test class:
    <project>
        . . .
        <build>
            . . .
            <plugins>
                . . .
                <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>2.8.1</version>
    <executions>
    <execution>
    <id>integration-test</id>
    <goals>
    <goal>integration-test</goal>
    </goals>
    <configuration>
    <systemPropertyVariables>
    <service.url>http://localhost:${jettyServerPort}/myRestService</service.url>
    <sts.url>http://localhost:${jettyServerPort}/SecurityTokenService/UT</sts.url>
    </systemPropertyVariables>
    </configuration>
    </execution>
    <execution>
    <id>verify</id>
    <goals>
    <goal>verify</goal>
    </goals>
    </execution>
    </executions>
    </plugin>
            <plugins>
        <build>
    <project>Jetty Plugin ConfigurationAnd here comes the really interesting part of telling Jetty to run with classes and configuration files from the src/test project folder:
    <project>
        . . .
        <build>
            . . .
            <plugins>
                . . .
                <plugin>
    <groupId>org.mortbay.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <version>8.1.5.v20120716</version>
    <configuration>
    <systemProperties>
    <systemProperty>
    <name>java.security.auth.login.config</name>
    <value>login.jaas</value>
    </systemProperty>
    <systemProperty>
    <name>service.url</name>
    <value>http://localhost:8080/myRestService</value>
    </systemProperty>
    </systemProperties>
    <scanIntervalSeconds>5</scanIntervalSeconds>
    <webAppConfig>
    <resourceBases>
    <resourceBase>${project.basedir}/src/test/webapp</resourceBase>
    </resourceBases>
    </webAppConfig>
    <useTestScope>true</useTestScope>
    <stopKey>STOP</stopKey>
    <stopPort>${jettyServerStopPort}</stopPort>
    </configuration>
    <executions>
    <execution>
    <id>start-jetty</id>
    <phase>pre-integration-test</phase>
    <goals>
    <goal>start</goal>
    </goals>
    <configuration>
    <scanIntervalSeconds>0</scanIntervalSeconds>
    <daemon>true</daemon>
    <connectors>
    <connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
    <port>${jettyServerPort}</port>
    <maxIdleTime>60000</maxIdleTime>
    </connector>
    </connectors>
    <systemProperties>
    <systemProperty>
    <name>java.security.auth.login.config</name>
    <value>login.jaas</value>
    </systemProperty>
    <systemProperty>
    <name>service.url</name>
    <value>http://localhost:${jettyServerPort}/myRestService</value>
    </systemProperty>
    </systemProperties>
    </configuration>
    </execution>
    <execution>
    <id>stop-jetty</id>
    <phase>post-integration-test</phase>
    <goals>
    <goal>stop</goal>
    </goals>
    </execution>
    </executions>
    </plugin>
            <plugins>
        <build>
    <project>
    I tried testing first with version 9.2.3.v20140905 of the Jetty plugin, but for some reasons I could not discover so quickly the SelectChannelConnector would not work as expected. My test would always run at port 8080 instead of a dynamically picked port. Therefore I switched back to version 8.1.5.v20120716 and all was running as desired.
    The most important parts to mention here is to set the resourceBase in the configuration to ${project.basedir}/src/test/webapp as well as setting useTestScope to true.

    Since I still wanted to use the port 8080 when running mvn jetty:run but a dynamic port when running mvn verify, I had to override the port settings accordingly.

    After these changes I was able to build my extensions including the automated integration test, but without any test related code in my src/main/ folder.
    Categories: Jan Bernhardt

    CXF becomes friends with Tika and Lucene

    Sergey Beryozkin - Wed, 10/15/2014 - 11:59
    You may have been thinking for a while: would it actually be cool to get some experience with Apache Lucene and Apache Tika and enhance the JAX-RS services you work upon along the way ? Lucene and Tika are those cool projects people are talking about but as it happens there has never been an opportunity to use them in your project...

    Apache Lucene is a well known project where its community keeps innovating with improving and optimizing the capabilities of various text analyzers. Apache Tika is a cool project which can be used to get the metadata and content out of binary resources with formats such as PDF, ODT, etc, with lots of other formats being supported. As a side note, Apache Tika is not only a cool project, it is also a very democratic project where everyone is welcomed from the get go - the perfect project to start your Apache career if you think of starting involved into one of the Apache projects.

    Now, a number of services you have written may be supporting uploads of the binary resources, for example, you may have a JAX-RS server accepting multipart/form-data uploads.

    As it happens, Lucene plus Tika is what one needs to be able to analyze the binary content easily and effectively. Tika would give you the metadata and the content, Lucene will tokenize it and help search over it. As such you can let your users search and download only those PDF or other binary resources which match the search query. It is something your users will appreciate.

    CXF 3.1.0 which is under the active development offers a utility support for working with Tika and Lucene. Andriy Redko worked on improving the integration with Lucene and introducing a content extraction support with the help of  Tika. It is all shown in a nice jax_rs/search demo which offers a Bootstrap UI for uploading, searching and downloading of PDF and ODT files. The demo will be shipped in the CXF distribution.  

    Please start experimenting today with the demo (download CXF 3.1.0-SNAPSHOT distribution), let us know what you think, and get your JAX-RS project to the next level.

    You are also encouraged to experiment with Apache Solr which offers an  advanced search engine on top of Lucene, with Tika also being utilized.

    Enjoy!      






    Categories: Sergey Beryozkin

    Using JAAS with Apache CXF

    Colm O hEigeartaigh - Tue, 10/14/2014 - 15:14
    Apache CXF supports a wide range of tokens for authentication (SAML, UsernameTokens, Kerberos, etc.), and also offers different ways of authenticating these tokens. A standard way of authenticating a received token is to use a JAAS LoginModule. This article will cover some of the different ways you can configure JAAS in CXF, and some of the JAAS LoginModules that are available.

    1) Configuring JAAS in Apache CXF

    There are a number of different ways to configure your CXF web service to authenticate tokens via JAAS. For all approaches, you must define the System property "java.security.auth.login.config" to point towards your JAAS configuration file.

    1.1) JAASLoginInterceptor

    CXF provides a interceptor called the JAASLoginInterceptor that can be added either to the "inInterceptor" chain of an endpoint (JAX-WS or JAX-RS) or a CXF bus (so that it applies to all endpoints). The JAASLoginInterceptor typically authenticates a Username/Password credential (such as a WS-Security UsernameToken or HTTP/BA) via JAAS. Note that for WS-Security, you must tell WSS4J not to authenticate the UsernameToken itself, but just to process it and store it for later authentication via the JAASLoginInterceptor. This is done by setting the JAX-WS property "ws-security.validate.token" to "false".

    At a minimum it is necessary to set the "contextName" attribute of the JAASLoginInterceptor, which references the JAAS Context Name to use. It is also possible to define how to retrieve roles as part of the authentication process, by default CXF assumes that javax.security.acl.Group Objects are interpreted as "role" Principals. See the CXF wiki for more information on how to configure the JAASLoginInterceptor. After successful authentication, a CXF SecurityContext Object is created with the name and roles of the authenticated principal.

    1.2) JAASAuthenticationFeature

    Newer versions of CXF also have a CXF Feature called the JAASAuthenticationFeature. This simply wraps the JAASLoginInterceptor with default configuration for Apache Karaf. If you are deploying a CXF endpoint in Karaf, you can just add this Feature to your endpoint or Bus without any additional information, and CXF will authenticate the received credential to whatever Login Modules have been configured for the "karaf" realm in Apache Karaf.

    1.3) JAASUsernameTokenValidator

    As stated above, it is possible to validate a WS-Security UsernameToken in CXF via the JAASLoginInterceptor or the JAASAuthenticationFeature by first setting the JAX-WS property "ws-security.validate.token" to "false". This tells WSS4J to avoid validating UsernameTokens. However it is possible to also validate UsernameTokens using JAAS directly in WSS4J via the JAASUsernameTokenValidator. You can configure this validator when using WS-SecurityPolicy via the JAX-WS property "ws-security.ut.validator".

    2) Using JAAS LoginModules in Apache CXF

    Once you have decided how you are going to configure JAAS in Apache CXF, it is time to pick a JAAS LoginModule that is appropriate for your authentication requirements. Here are some examples of LoginModules you can use.

    2.1) Validating a Username + Password to LDAP / Active Directory

    For validating a Username + Password to an LDAP / Active Directory backend, use one of the following login modules:
    • com.sun.security.auth.module.LdapLoginModule: Example here (context name "sun").
    • org.eclipse.jetty.plus.jaas.spi.LdapLoginModule: Example here (context name "jetty"). Available via the org.eclipse.jetty/jetty-plus dependency. This login module is useful as it's easy to retrieve roles associated with the authenticated user.
    2.2) Validating a Kerberos token

    Kerberos tokens can be validated via:
    • com.sun.security.auth.module.Krb5LoginModule: Example here.
    2.3) Apache Karaf specific LoginModules

    Apache Karaf contains some LoginModules that can be used when deploying your application in Karaf:
    • org.apache.karaf.jaas.modules.properties.PropertiesLoginModule: Authenticates Username + Passwords and retrieves roles via "etc/users.properties".
    • org.apache.karaf.jaas.modules.properties.PublickeyLoginModule: Authenticates SSH keys and retrieves roles via "etc/keys.properties".
    • org.apache.karaf.jaas.modules.properties.OsgiConfigLoginModule: Authenticates Username + Passwords and retrieves roles via the OSGi Config Admin service.
    • org.apache.karaf.jaas.modules.properties.LDAPLoginModule: Authenticates Username + Passwords and retrieves roles from an LDAP backend.
    • org.apache.karaf.jaas.modules.properties.JDBCLoginModule:  Authenticates Username + Passwords and retrieves roles from a database.
    • org.apache.karaf.jaas.modules.properties.SyncopeLoginModule: Authenticates Username + Passwords and retrieves roles via the Apache Syncope IdM.
    See Jean-Baptiste Onofré's excellent blog for a description of how to set up and test the SyncopeLoginModule. Note that it is also possible to use this LoginModule in other containers, see here for an example.
    Categories: Colm O hEigeartaigh

    Using the Talend PDP ouside of an OSGi Container

    Jan Bernhardt - Tue, 10/14/2014 - 10:05
    In a previous post I've explained how to setup a demo application using SAML token for authentication and XACML for authorization in context of REST services.
    In this blog I'm going to explain how to setup the Talend PDP ouside of the OSGi container in which it is usually located, so that you are able to use the PDP co-located to your demo application in any JavaEE container. This is especially helpful if your application cannot easily being deployed into the Talend runtime, but requires lots of authorization requests. In these cases it will be best to have the PDP co-located with your app, completely avoiding expensive network calls.

    This post continues with the demo application described in my previous post. To follow this post you should first read my other post.

    All you need to do to get the PDP dependencies into your demo application war file is to add the following dependency to your to your pom.xml file:
    <dependency>
        <groupId>org.talend.esb.authorization</groupId>
        <artifactId>tesb-xacml-pdp-rt</artifactId>
        <version>5.4.1</version>
    </dependency>
    This dependency is available to Talend Enterprise Edition only!
    If you do not want to use Talend EE you could also use the HERAS-AF implementation directly. But in this case you will be missing some of the extensions which are only provided by Talend. Standalone PDP Next you can setup the PDP as a REST service, taking XACML requests in and returning XACML responses in your /src/main/webapp/WEB-INF/beans.xml file. In this case the demo service will use the localhost network interface to comunicate with the PDP.
    <?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:cxf="http://cxf.apache.org/core" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="
            http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
            http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">

        <import resource="classpath:META-INF/cxf/cxf.xml" />

        <context:property-placeholder />
        <context:annotation-config />
        <bean class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer" />
        <bean class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer" />

        <jaxrs:server id="services" address="/">
            <jaxrs:serviceBeans>
                <bean id="helloWorldService" class="org.talend.example.rest.HelloWorld" />
            </jaxrs:serviceBeans>
            <jaxrs:providers>
                <bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
                <bean id="samlHandler" class="org.apache.cxf.rs.security.saml.SamlHeaderInHandler" />
            </jaxrs:providers>
            <jaxrs:properties>
                <entry key="ws-security.signature.properties" value="alice.properties" />
            </jaxrs:properties>
            <jaxrs:inInterceptors>
                <bean class="org.talend.esb.authorization.xacml.rt.pep.CXFXACMLAuthorizingInterceptor" id="XACMLInterceptor">
                    <property name="pdpAddress" value="http://localhost:8080/pdp/authorize" />
                    <property name="requireRoles" value="false" />
                </bean>
            </jaxrs:inInterceptors>
        </jaxrs:server>

        <bean id="prpBean" class="org.talend.esb.authorization.xacml.pdp.herasaf.FilePolicyRetrievalPoint">
            <property name="policyURL" value="WEB-INF/pdp-policy.xml" />
        </bean>
       
        <bean id="pdpBean" class="org.talend.esb.authorization.xacml.pdp.herasaf.HerasAFPolicyDecisionPoint">
            <property name="policyRetrievalPoint" ref="prpBean" />
        </bean>

        <bean id="pdpServiceBean" class="org.talend.esb.authorization.xacml.pdp.service.PolicyDecisionPointService">
            <property name="policyDecisionPoint" ref="pdpBean" />
        </bean>

        <jaxrs:server address="/pdp/">
            <jaxrs:serviceBeans>
                <ref bean="pdpServiceBean" />
            </jaxrs:serviceBeans>
        </jaxrs:server>
      
    </beans> 
    In the above sample the PDP uses a file policy retrieval point to load its authorization policies. The policy file could look like this:
    <?xml version="1.0" encoding="UTF-8"?>
    <Policy PolicyId="ExamplePolicy"
              RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:permit-overrides"
              xmlns="urn:oasis:names:tc:xacml:2.0:policy:schema:os" >
        <Target>
          <Resources>
            <Resource>
              <ResourceMatch MatchId="urn:oasis:names:tc:xacml:1.0:function:string-regexp-match">
                <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">/hello/echo/Sierra.*</AttributeValue>
                <ResourceAttributeDesignator DataType="http://www.w3.org/2001/XMLSchema#string"
                                             AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id"/>
              </ResourceMatch>
            </Resource>
          </Resources>
        </Target>
        <Rule RuleId="ExecuteRule" Effect="Permit">
          <Target>
            <Actions>
              <Action>
                <ActionMatch MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                  <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">GET</AttributeValue>
                  <ActionAttributeDesignator DataType="http://www.w3.org/2001/XMLSchema#string"
                                             AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id"/>
                </ActionMatch>
              </Action>
            </Actions>
          </Target>
        </Rule>
      </Policy>
    The above policies only allows GET request to the echo service which are starting with Sierra. This makes it easy to test your PDP endpoint. Calling the first URL should be successfull whereas the second should fail:
    1.  http://localhost:8080/hello/echo/SierraTangoNevada
    2. http://localhost:8080/hello/echo/TangoNevada
    Co-Located SetupTo switch from network connection to direct PDP invocation you need to modify your beans.xml as follows:
    <?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:cxf="http://cxf.apache.org/core" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="
            http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
            http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">

        <import resource="classpath:META-INF/cxf/cxf.xml" />

        <context:property-placeholder />
        <context:annotation-config />
        <bean class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer" />
        <bean class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer" />

        <jaxrs:server id="services" address="/">
            <jaxrs:serviceBeans>
                <bean id="helloWorldService" class="org.talend.example.rest.HelloWorld" />
            </jaxrs:serviceBeans>
            <jaxrs:providers>
                <bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
                <bean id="samlHandler" class="org.apache.cxf.rs.security.saml.SamlHeaderInHandler" />
            </jaxrs:providers>
            <jaxrs:properties>
                <entry key="ws-security.signature.properties" value="alice.properties" />
            </jaxrs:properties>
            <jaxrs:inInterceptors>
                <bean class="org.talend.esb.authorization.xacml.rt.pep.CXFXACMLAuthorizingInterceptor" id="XACMLInterceptor">
                    <property name="policyDecisionPoint" ref="pdpBean"/>
                    <property name="requireRoles" value="false" />
                </bean>
            </jaxrs:inInterceptors>
        </jaxrs:server>
       
        <bean id="prpBean" class="org.talend.esb.authorization.xacml.pdp.herasaf.RBACRegistryAtomPolicyRetrievalPoint">
           <property name="registryAtomUrl" value = "http://localhost:8040/services/XacmlRegistryAtom"/>
           <property name="policyCachingStrategy" value ="InMemory"/>
           <property name="cacheConfiguration" value="pdp-ehcache.xml"/>
           <property name="loadPermissionPoliciesOnInit" value="true"/>
           <property name="policyReloadInterval" value="10"/>
           <property name="validatePolicies" value="false"/>
           <property name="authentication" value="NO"/>
           <!--property name="username" value="tesb"/>
           <property name="password" value="tesb"/-->
        </bean>

        <bean id="pdpBean" class="org.talend.esb.authorization.xacml.pdp.herasaf.HerasAFPolicyDecisionPoint">
            <property name="policyRetrievalPoint" ref="prpBean" />
        </bean>

    </beans>
    In the above sample I replaced the file policy retrieval point with the Talend policy store retrieval point, thus being able to fetch authorization policies from a central server location. Since these policies will be cached in the PDP the network overhead will be quite low.I also removed the code to setup a remote accessible PDP endpoint but instead I injected the PDP instance directly to the XACML PEP interceptor of the demo application.
    Categories: Jan Bernhardt

    Identity Federation - Identity Mapping vs. Claim Mapping

    Jan Bernhardt - Mon, 10/13/2014 - 16:38
    Identity and claim mapping become important, when the target realm (A) of a web application is not equal to the home realm (B) of the user. In this case a SAML token from the user (issuer B) cannot directly be validated at the web application (trusting issuer A only). The relaying party IDP of the web application (in realm A) is able to exchange the SAML token from the (trusted) home realm (B) into a SAML token applicable for the target realm (A). This exchange can be based either on identity mapping or on claim mapping. In this post I'm going to explain what's the difference between these two mapping styles and when to use which alternative.

    <!-- TODO: add picture here -->
    When the relaying party IDP (A) requests a SAML token on behalf of the user (B) at its STS (A) for a specific application (A), then the relaying party IDP send the SAML token previously received from the users home IDP (B) to its STS (A). The STS validates the SAML token and detects that it was issued from another (trusted) security realm (B). Depending on the STS configuration the new SAML token can be created based on an identity or claim mapping.
    Identity MappingIdentity mapping is usually required if a user is registered in both (target and home realm) security domains with an individual user each. These users can be managed in both security domains independently. They do not need to share the same username, password or other kind of user attributes like assigned roles.

    A good example of this use case can be illustrated by Google and YouTube. Before Google acquired YouTube most users had a normal Google account as well as an independent YouTube account. After the acquisition, Google implemented an identity mapping so that a user with an active Google session (due to previous login) could login to YouTube and Google would ask the user if he/she wants to link both accounts. If the user agreed, he/she was now able to login to Google only, but at the same time he/she could use YouTube without re-authentication and with all settings, playlists, etc. which have been related to their former YouTube account.

    For identity mapping the following constrains apply:
    • Independent user account (including attributes) per security domain
    • Each account is under local administration
    • A mapping needs to be defined between account names
    • No attributes are mapped from one identity to the other
    Claim MappingIn case of claim mapping a user is completely managed and under the control of only one domain. Users do not need to be known and managed in other security domains. This reduces the need for identity synchronization and confidential information like user credentials do not need to be propagated to other security domains.

    When the STS receives a SAML token from another (trusted) security realm it does not need to look up a matching identity in his own security domain, but instead creates a new SAML token valid for the target security realm but with the same username as in the provided SAML token from the other domain. If user specific attributes (claims) are of interest for the target domain, the STS can simply copy these attributes into the newly created SAML token or execute a more complex mapping where original values do not need to match new claims neither in number, name nor value. If such a mapping is required, the STS needs to be configured accordingly. See my other post about how this can be done.

    A simple claim mapping could be implemented in a way that role claims from a SAML token are also included (one to one) in the newly created SAML token. Alternatively a mapping could be defined to map role claims from one domain into different role claims for the target realm.

    For claim mapping the following constrains apply:
    • User account is only available and managed within its home realm
    • No user account information is stored in the target realm
    • If claims are needed in target realm, they need to be mapped accordingly
    Categories: Jan Bernhardt

    New Apache WSS4J releases

    Colm O hEigeartaigh - Thu, 10/09/2014 - 11:46
    Apache WSS4J 1.6.17 and 2.0.2 have been released. WSS4J 2.0.2 picks up some bug fixes via Apache Santuario and BouncyCastle dependency upgrades, in particular the latter upgrade fixes some Kerberos issues. Both releases contain some changes to how SAML tokens are processed that will be described in a forthcoming blog post.

    I also added a new Security Advisories page to the WSS4J website. For the moment it just contains some links and information on downstream security advisories that might be relevant to users of WSS4J.
    Categories: Colm O hEigeartaigh

    Some recent WS-Trust client topics in Apache CXF

    Colm O hEigeartaigh - Wed, 10/08/2014 - 15:50
    There are a number of minor new features and changes in recent versions of Apache CXF with respect to the client side of WS-Trust, which will be documented in this post.

    1) STSClient configuration

    CXF's STSClient is responsible for communicating with a Security Token Service (STS) via the WS-Trust protocol, in order to issue/validate/renew/etc. a security token. To support WS-Trust on the client side in CXF, it is necessary to construct an STSClient instance, and then reference it via the JAX-WS property key "ws-security.sts.client". Here is a typical example in spring.

    However, there are some alternatives to configuring an STSClient per JAX-WS client object (see the CXF documentation for additional information). Strictly speaking these alternatives have been available in previous versions of CXF, however some bugs were fixed in the latest releases to enable them to work properly:

    a) If no STSClient is directly configured on the JAX-WS client, then the CXF runtime will look for an STSClient bean with a name that corresponds to the Endpoint name with the suffix ".sts-client". Here is an example:

    <bean id="stsClient" class="org.apache.cxf.ws.security.trust.STSClient"
        name="{http://www.example.org/contract/DoubleIt}DoubleItTransportSAML1Port.sts-client"
        abstract="true"
    >

    b) If no STSClient is configured either directly on the client, or else via the approach given in (a) above, then the security runtime tries to fall back to a "default" client. All that is required here is that the name of the STSClient bean should be "default.sts-client". Here is an example:

    <bean id="stsClient" class="org.apache.cxf.ws.security.trust.STSClient"
        name="default.sts-client"
        abstract="true"
    >

    2) Falling back to Issue after a failed Renew

    When a cached SecurityToken is expired, the STSClient tries to renew the token. However, not all STS instances support the renewal binding of WS-Trust. Therefore a new configuration parameter was introduced:
    • SecurityConstants.STS_ISSUE_AFTER_FAILED_RENEW ("ws-security.issue.after.failed.renew") -  Whether to fall back to calling "issue" after failing to renew an expired token. The default is "true".
     3) Renewing security tokens that are "about to" expire

    There is a potential issue when a cached security token is "about to" expire. The CXF client will retrieve the cached token + check to see whether the token is expired or not. If it is expired, then it renews the token. If the token is valid, then it uses it in the service request. However, if the security token expires "en route" to the service, then the service will reject the token, and the service invocation will fail.

    In CXF 2.7.13 and 3.0.2, support has been added to forcibly renew tokens that are about to expire, rather than risk letting them expire en route. A new configuration parameter has been introduced:
    • SecurityConstants.STS_TOKEN_IMMINENT_EXPIRY_VALUE ("ws-security.sts.token.imminent-expiry-value") - The value in seconds within which a token is considered to be expired by the client, i.e. it is considered to be expired if it will expire in a time less than the value specified by this tag.
    The default value for this parameter for CXF 3.0.2 is "10", meaning that if a security token will expire in less than 10 seconds, it will be renewed by the client. For CXF 2.7.13, the default value is "0" for backwards compatibility reasons, meaning that this functionality is disabled.
    Categories: Colm O hEigeartaigh

    Apache CXF Authentication and Authorization test-cases III

    Colm O hEigeartaigh - Tue, 10/07/2014 - 16:45
    This is the third in a series of posts on authentication and authorization test-cases for web services using Apache CXF. The first post focused on authenticating and authorizing web service requests that included a username and password (WS-Security UsernameToken and HTTP/BA). The second article looked at more sophisticated ways of performing authentication and authorization, such as using X.509 certificates, using a SecurityTokenService (STS), using XACML and using Kerberos. This article will build on the previous articles to show how to perform Single Sign On (SSO) with Apache CXF.

    The projects are as follows:
    • cxf-shiro: This project uses Apache Shiro for authenticating and authorizating a UsernameToken, as covered in the first article. However, it also now includes an SSOTest, which shows how to use WS-SecureConversation for SSO. In this scenario an STS is co-located with the endpoint. The client sends the UsernameToken to the STS for authentication using Apache Shiro. The STS returns a token and a secret key to the client. The client then makes the service request including the token and using the secret key to sign a portion of the request, thus proving proof-of-possession. The client can then make repeated invocations without having to re-authenticate the UsernameToken credentials.
    • cxf-sts:  This project shows how to use the CXF SecurityTokenService (STS) for authentication and authorization, as covered in the second article. It now includes an SSOTest to show how to achieve SSO with the STS. It demonstrates how the client caches the token after the initial invocation, and how it can make repeated invocations without having to re-authenticate itself to the STS.
    • cxf-saml-sso: This project shows how to leverage SAML SSO with Apache CXF to achieve SSO for a JAX-RS service. CXF supports the POST + redirect bindings of SAML SSO for JAX-RS endpoints. As part of this demo, a mock CXF-based IdP is provided which authenticates a client using HTTP/BA and issues a SAML token using the CXF STS. Authorization is also demonstrated using roles embedded in the issued SAML token. 
    • cxf-fediz-federation-sso: This project shows how to use the new CXF plugin of Apache Fediz 1.2.0 to authenticate and authorize clients of a JAX-RS service using WS-Federation. This feature will be documented more extensively at a future date, and is considered experimental for now. Please play around with it and provide feedback to the CXF users list.
    Categories: Colm O hEigeartaigh

    Encrypt ConfigAdmin properties values in Apache Karaf

    Jean-Baptiste Onofré - Fri, 10/03/2014 - 18:41
    Apache Karaf loads all the configuration from etc/*.cfg files by default, using a mix of Felix FileInstall and Felix ConfigAdmin. These files are regular properties file looking like: Some values may be critical, and so not store in plain text. It could be critical business data (credit card number, etc), or technical data (password to […]
    Categories: Jean-Baptiste Onofré

    STS Claim Mappings using JEXL Scripts

    Jan Bernhardt - Wed, 10/01/2014 - 10:17
    Before CXF version 2.7.13 it was quite difficult to use claim mappings in the STS, because CXF did not provide any generic claim mapping solution but instead required custom Java code for each claim mapping. Beginning of version 2.7.13 (not yet released) CXF comes with a JexlClaimsMapper which allows to define claim mappings at configuration time with Java Expression Language (JEXL).
    Also a new feature in CXF which goes hand in hand with the JexlCaimsMapper is a special ClaimUtils class providing methods for common claim handling tasks.

    In this blog I'll write about:
    • How to setup claim mappings in the STS
    • Basic JEXL Claim Handling
    • Several JEXL Claim Mapping Samples
    STS Claim Mapping SetupThe best and fastest way to setup a claim mapping scenario in my opinion is to use the CXF Fediz HelloWorld demonstrator. You can also take a look at my previous blog where I described how to setup the demo app, as well as the IDP and STS. Of course you can omit the Kerberos related steps.

    Once you have the basic HelloWorld Sample up and running, I'll explain how to switch from identity mapping to a claim mapping next.
    IDP Setup First of all you need to tell the IDP in realm B that you need claims for realm A. To do so you must set the requestedClaims property in your idp-realmA bean in idp-config-realmb.xml. Your result should look like the following:
    <beans >
        . . .
        <bean id="idp-realmA" class="org.apache.cxf.fediz.service.idp.model.ServiceConfig">
            <property name="realm" value="urn:org:apache:cxf:fediz:idp:realm-A" />
            <property name="protocol" value="http://docs.oasis-open.org/wsfed/federation/200706" />
            <property name="serviceDisplayName" value="Resource IDP Realm A" />
            <property name="serviceDescription" value="Resource IDP Realm A" />
            <property name="role" value="SecurityTokenServiceType" />
            <property name="tokenType" value="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0" />
            <property name="lifeTime" value="3600" />
            <property name="requestedClaims">
                <util:list>
                    <bean class="org.apache.cxf.fediz.service.idp.model.RequestClaim">
                        <property name="claimType" value="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" />
                        <property name="optional" value="false" />
                    </bean>
                    <bean class="org.apache.cxf.fediz.service.idp.model.RequestClaim">
                        <property name="claimType" value="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" />
                        <property name="optional" value="false" />
                    </bean>
                    <bean class="org.apache.cxf.fediz.service.idp.model.RequestClaim">
                        <property name="claimType" value="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" />
                        <property name="optional" value="false" />
                    </bean>
                    <bean class="org.apache.cxf.fediz.service.idp.model.RequestClaim">
                        <property name="claimType" value="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role" />
                        <property name="optional" value="false" />
                    </bean>                                               
                </util:list>
            </property>
        </bean>
    </beans>

    In your idp-config-realma.xml you need to change the federationType of your trusted-idp-realmB bean from FederateIdentity to FederateClaims:

    Since version 1.2 of Fediz the federationType value has changed to FEDERATE_CLAIMS respectively FEDERATE_IDENTITY<beans >
        . . .
    <bean id="trusted-idp-realmB" class="org.apache.cxf.fediz.service.idp.model.TrustedIDPConfig">
    <property name="realm" value="urn:org:apache:cxf:fediz:idp:realm-B" />
    <property name="cacheTokens" value="true" />
    <property name="url" value="https://localhost:${realmB.port}/fediz-idp-remote/federation" />
    <property name="certificate" value="realmb.cert" />
    <property name="trustType" value="PEER_TRUST" />
    <property name="protocol" value="http://docs.oasis-open.org/wsfed/federation/200706" />
    <property name="federationType" value="FederateClaims" />
    <property name="name" value="REALM B" />
    <property name="description" value="IDP of Realm B" />
    </bean>
    </beans>
    STS Setup In case that your STS pom.xml file does not include the JEXL dependency you can either add this dependency to your STS or alternatively you can just add this library to your Tomcat lib folder.
    <dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-jexl</artifactId>
    <version>2.1.1</version>
    </dependency>Next you need to update the STS of your relaying party IDP (Realm-A). Here you need to modify the relationship between REALMA and REALMB. For this scenario it would be sufficient to update only the second releationship in the cxf-transport.xml file, but to make the relationship homogeneous I'll set both relationships type from FederateIdentity to FederateClaims. In addition to that I need to add my claimsMapper bean with the JexlClaimsMapper implementation and set the claimsMapper instead of the identityMapper in my relationships.
    <beans >
        . . .
    <bean id="claimsMapper" class="org.apache.cxf.sts.claims.mapper.JexlClaimsMapper">
    <constructor-arg value="claimMapping.script" />
    </bean>

    <util:list id="relationships">
    <bean class="org.apache.cxf.sts.token.realm.Relationship">
    <property name="sourceRealm" value="REALMA" />
    <property name="targetRealm" value="REALMB" />
    <property name="claimsMapper" ref="claimsMapper" />
    <property name="type" value="FederatedClaims" />
    </bean>
    <bean class="org.apache.cxf.sts.token.realm.Relationship">
    <property name="sourceRealm" value="REALMB" />
    <property name="targetRealm" value="REALMA" />
    <property name="claimsMapper" ref="claimsMapper" />
    <property name="type" value="FederatedClaims" />
    </bean>
    </util:list>
    </beans>
    At last you need to add your claimMapping.script (could be any name you want) to your WEB-INF folder of your STS (or any other location that you chose for your JexlClaimsMapper). The content of the claimMapping.script will be discussed in the following sections.
    Basic JEXL Claim HandlingThe following variables will be available within your custom JEXL script and can be used to determine the outcome of the claim mapping process:
    • sourceClaims
      is a ClaimCollection containing all claims provided from the requester IDP/STS (e.g. REALMB) at which the user was authenticated first (e.g. via username/password).
    • targetClaims
      is a ClaimCollection in which you need to add all claims that you want to be available after the claim mapping for your target application.
    • sourceRealm
      Realm ID of the requester IDP/STS (e.g. REALMB)
    • targetRealm
      Realm ID of the relaying party IDP/STS (e.g. REALMA)
    • claimsParameters
      ClaimsParameter containing additional context information like the STS issuer name and applies to address.
    JEXL also supports registration of custom classes to be used within your script. This makes it possible to transfer complex code to a Java class and thus simplifying your script code. By default the ClaimUtils class will be available via the following syntax: claims:<methodname>(<parameter>...). This util class provides several convenience methods to simplify claim handling like getting claims from a specific type out of a ClaimCollection, mapping claim values, etc. You will find several samples in the following section.

    The last statement in your script should always return the targetClaims!
    Each claim can contain an issuer and an originalIssuer attribute. By calling the

    claims:updateIssuer(targetClaims, "new issuer")

    method you can set your current STS as the issuer of the targetClaims as well as setting the originalIssuer (in your targetClaims) which was the issuer in your sourceClaims. Since the claimsParameters are also available within your JEXL script you can set the current STS issuer name in your claims via claimsParameters.stsProperties.issuer instead of using a static String like "new issuer".
    Claim Mapping SamplesIn this section I'll show you some common scenarios that you might need, when you want to operate your IDP/STS in claim mapping mode.
    Copy AllIf all claims regardless of the type and value shall be copied from the original SAML token into the newly generated token the following expression would be sufficient:
    {
    // Update claim issuer
    targetClaims = claims:updateIssuer(sourceClaims, claimsParameters.stsProperties.issuer);

    // Return all claims
    return targetClaims;
    }
    Copy Roles OnlyA simple JEXL script to copy all roles from the source SAML token which was contained in the onBehalfOf token request to the requested target SAML token could look like the following:
    {
    // Get all role claims
    var roleClaimType = 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role';
    var roleClaim = claims:get(sourceClaims, roleClaimType);

    // Copy role claims for new token
    targetClaims = claims:add(targetClaims, roleClaim);

    // Update claim issuer
    targetClaims = claims:updateIssuer(targetClaims, claimsParameters.stsProperties.issuer);

    // Return new claims
    return targetClaims;
    }Role Value FilterThe following sample can be used in a scenario when your source role claim contains all role values comma separated in a single claim value and you want the target claim to contain distinct role values which match a specific regular expression (e.g. start with 'ROLE_'):
    {
    // Get role claim
    var roleClaimType = 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role';
    var roleClaim = claims:get(sourceClaims, roleClaimType);

    // Split multi role values
    roleClaim = claims:multiToSingleValue(roleClaim, ",");

    // Filter role values
    roleClaim = claims:filterValues(roleClaim, "ROLE_.*");

    // Add mapped role claims for new token
    targetClaims = claims:add(targetClaims, roleClaim);

    // Update claim issuer
    targetClaims = claims:updateIssuer(targetClaims, claimsParameters.stsProperties.issuer);

    // Return new claims
    return targetClaims;
    }
    Map Role ClaimsThe following sample shows a role mapping with a custom map (originalRoleName => newRoleName):
    {
    // Role value mapping
    var roleClaimType = 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role';
    var roleClaim = claims:get(sourceClaims, roleClaimType);
    var roleMappings = { "admin" : "administrator", "manager" : "manager" };
    var mappedRoles = claims:mapValues(roleClaim, roleMappings, false);

    // Add mapped role claims for new token
    targetClaims = claims:add(targetClaims, mappedRoles);

    // Update claim issuer
    targetClaims = claims:updateIssuer(targetClaims, claimsParameters.stsProperties.issuer);

    // Return new claims
    return targetClaims;
    }
    Claim MergesIt is also possible to define script variables to improve readability. The following sample shows a many-too-one claim mapping whereby the first and last name of a person is transformed into a fullname claim, as well as copying all email addresses from the source SAML token:
    {
    // Merge firstname and lastname to fullname claim
    var delimiter = ' ';
    var firstNameClaimType = 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname';
    var lastNameClaimType = 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname';
    var fullNameClaimType = 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name';
    var fullNameClaim = claims:merge(sourceClaims, fullNameClaimType, delimiter, firstNameClaimType, lastNameClaimType);

    // Simple claim copy
    var emailClaimType = 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/mail';
    var emailClaim = claims:get(sourceClaims, emailClaimType);

    // Add fullname claim and email claim for new token
    targetClaims = claims:add(targetClaims, fullNameClaim, emailClaim);

    // Update claim issuer
    targetClaims = claims:updateIssuer(targetClaims, claimsParameters.stsProperties.issuer);

    // Return new claims
    return targetClaims;
    }
    More complex SampleThe following sample shows a more "real life" sample of how roles claims are transferred from one domain to another by changing the role claim type, filtering for app specific roles, mapping one to many and normalizing the result:
    {
        // Get roles
        var sourceRoleClaimType = 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role';
        var roleClaims = claims:get(sourceClaims, sourceRoleClaimType);

        // Update role claim type
        var targetRoleClaimType = 'http://schemas.mycompany.com/security/authorization/claims/role';
        roleClaims = claims:setType(roleClaims, targetRoleClaimType);
       
        // Normalize role claim values
        roleClaims = claims:singleToMultiValue(roleClaims, ",");

        // Application role filter
        roleClaims = claims:filterValues(roleClaims, 'AppName_[a-zA-Z_]+');

        // Map role claims
        var roleMappings = {
            "AppName_Agent"            : "AppName_User, Agent",
            "AppName_Broker_DE"         : "AppName_User, AppName_Broker",
            "AppName_Partner_Agents"   : "AppName_User, AppName_Partner, External"
            };
        roleClaims = claims:mapValues(roleClaims, roleMappings, false);
        roleClaims = claims:singleToMultiValue(roleClaims, ", ");

        // Remove duplicates
        if (roleClaims != null) {
            var distinctValues = new("java.util.LinkedHashSet", roleClaims.values);
            roleClaims.values.clear();
            roleClaims.values.addAll(distinctValues);
        }

        // Collect claims for new token
        if (roleClaims != null && roleClaims.values.size() > 0) {
            targetClaims = claims:add(targetClaims, roleClaims);
        }

        // Set correct issuer
        targetClaims = claims:updateIssuer(targetClaims, claimsParameters.stsProperties.issuer);

        // Return new claims
        return targetClaims;
    }

    Plain JEXL OnlyIf you do not want to use any util classes in your JEXL script you can also script more complex cases directly within your script. The following sample shall give you just an idea on who this could look like:
    {
    // Role value mapping
    var roleClaimType = 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role';
    var roleMappings = { "admin" : "administrator", "manager" : "manager" };

    for (c : sourceClaims) {
    if(c.claimType == roleClaimType) {
    var mappedValues = new("java.util.ArrayList");
    for (v : c.values) {
    v = v.toUpperCase();
    var newValue = roleMappings.get(v);
    if (newValue != null) {
    mappedValues.add(newValue);
    }
    }
    c.values = mappedValues;
    targetClaims.add(c);
    }
    }

    // Set correct issuer
    for (c : targetClaims) {
    if(c.originalIssuer == null) {
    c.originalIssuer = c.issuer;
    }
    c.issuer = claimsParameters.stsProperties.issuer;
    }

    // Return new claims
    return targetClaims;
    }
    Categories: Jan Bernhardt

    SSO with Fediz IDP and Kerberos

    Jan Bernhardt - Mon, 09/29/2014 - 14:13
    Colm O hEigeartaigh extended Fediz IDP just recently to allow browser-based Kerberos authentication at the IDP. In this blog I'm going to explain how to setup your system environment to provide WS-Federation based SSO for a normal web application:
    • Prepare your Active Directory
    • Installing the Fediz Demo Application
    • Installing Fediz IDP and a Kerberos enabled STS
    • Enable Kerberos for your Browser
    Preparing Active DirectoryTo setup my test environment I needed a Active Directory service providing my test users and Kerberos support. After installing a Windows Server 2008 R2 Enterprise Edition server, I added the Active Directory feature according to a well written post, which I found on the internet.
    Adding users and groupsAfter that I created two new security groups:
    • manager
    • employee
    For being able to choose trivial passwords for my test users, I disabled the global password policy as well as the local password policy.

    After that I added the following users to my active directory:
      • alice@MYDOMAIN.COM
      • bob@MYDOMAIN.COM
      • idp/idp-host.mydomain.com@MYDOMAIN.COM

        I also added Alice to the group manager and employee, as well as Bob to the group employee only.
        Adding Service Principal Name to the IDP userIf a browser requests a Kerberos token for a webpage the Kerberos token will always be requested for the following ServicePrincipalName: HTTP/my.idp-website.com.
        Therefore I need to add the matching SPN to my AD user idp/myhost.mydomain.com@MYDOMAIN.COM.
        You need to enter the following command on a console at your domain controller:

        C:\> setspn -A HTTP/idp-host.mydomain.com idp/idp-host.mydomain.com
        C:\> setspn -A HTTP/idp-host idp/idp-host.mydomain.com

        If your IDP Server is accessible via multiple domain names (only DNS A-Records are considered), you should also add multiple SPNs to your IDP user.
        You can use the following command to validate that you set the correct SPNs:

        C:\> setspn -L HTTP/*

        You should also make sure that you have a SPN set only once! You can validate this with the following command:

        C:\> setspn -Q

        It is very important, that you also add the correct DNS names for your IDP in your Windows DNS Server. You cannot use an IP address directly for the IDP server. If you do so your browser will not request a correct Kerberos ticket for your IDP!Extracting service private key from Kerberos
        I used username/password authentication for the IDP user in the STS Kerberos token validator, which does not require to extract a keytab file from your Active Directory server. If you do use this keytab file you do not need to provide username/password instead.
        The STS needs access to its own keytab file for being able to validate the Kerberos authentication of the user. Therefore we need to extract the private key to a file.

        ktpass -princ idp/idp-host.mydomain.com@MYDOMAIN.COM -mapuser MYDOMAIN\IdpMyHost -pass password -crypto All -kvno 0 -ptype KRB5_NT_PRINCIPAL -out c:\temp\IdpMyHost.keytab

        The extracted keytab file must be transfered to the server where the IDP and STS will be installed.
        Installing Demo ApplicationDownload and setup Apache Tomcat 7 as usual.
         
        After that you must define a fediz_config.xml configuration file for the Fediz plugin in the conf folder from Tomcat. You can find further steps to setup Tomcat on the Apache website.

        <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
        <FedizConfig>
        <contextConfig name="/fedizhelloworld">
        <audienceUris>
        <audienceItem>urn:org:apache:cxf:fediz:fedizhelloworld</audienceItem>
        </audienceUris>
        <certificateStores>
        <trustManager>
        <keyStore file="ststrust.jks" password="storepass" type="JKS" />
        </trustManager>
        </certificateStores>
        <trustedIssuers>
        <issuer certificateValidation="PeerTrust" />
        </trustedIssuers>
        <maximumClockSkew>1000</maximumClockSkew>
        <protocol xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:type="federationProtocolType" version="1.0.0">
        <realm>urn:org:apache:cxf:fediz:fedizhelloworld</realm>
        <issuer>https://localhost:9443/fediz-idp/federation</issuer>
        <roleDelimiter>,</roleDelimiter>
        <roleURI>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role</roleURI>
        <claimTypesRequested>
        <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role" optional="false" />
        </claimTypesRequested>
        </protocol>
        </contextConfig>
        </FedizConfig>

        Now you can download the the latest version of Fediz from github. Next you need to build all Fediz dependencies with maven and copy them to the lib/fediz folder of your Tomcat installation. Go to cxf-fediz/plugins/tomcat and execute the following command:

        mvn clean install

        You must also update the common.loader property in conf/catalina.properties:

        common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar,${catalina.home}/lib/fediz/*.jar
        Next you can build the example web application. Go to cxf-fediz/examples/simpleWebapp and build your webapp again with maven:

        mvn clean install

        You must then copy the war file of the example web application to your Tomcat webapps folder.

        Now you can start your relying party Tomcat container.

        If you open http://localhost:8080/fedizhelloworld/ in your browser you should see a "Hello World" message.
        If you go to http://localhost:8080/fedizhelloworld/secure/fedservlet you will be redirected to the IDP which we will setup next.
        Installing Fediz IDP & STSTomcat SetupMake sure that the JDK has unlimited security policies installed. Since we already have a running Tomcat 7 installation for the relying party we will just copy that installation and deleting the fedizhelloworld web application from the webapps/ folder as well as the fediz_config.xml configuration file in the conf/ folder. If we plan to run both Tomcat Server on the same machine we must also update the server ports in the conf/server.xml file.
        <Connector port="9443" protocol="org.apache.coyote.http11.Http11Protocol"
        maxHttpHeaderSize="65536"
        maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
        keystoreFile="idp-ssl-server.jks"
        keystorePass="tompass"
        truststoreFile="idp-ssl-server.jks"
        truststorePass="tompass"
        truststoreType="JKS"
        SSLVerifyClient="optional"
        clientAuth="want"
        sslProtocol="TLS" />

        It is very important that you increase the default max header size from tomcat. Otherwise some of your users will get a 401 Bad Request Error if the Kerberos token is bigger than 8kb.
        You must also set clientAuth to want and configure a trust-store, if you run IDP and STS in the same Tomcat container, because the STS requires x509 client authentication.
        Since the IDP uses JPA (since version 1.2) to store its configuration settings, we must also download the matching JDBC driver and place the driver to our Tomcat lib folder. Next we must set the domain name or IP address of the KDC Kerberos server. This we can do best by setting a JVM parameter via CATALINA_OPTS by creating or updating the setenv.bat respectively setenv.sh in the Tomcat bin folder:
        set CATALINA_OPTS=%CATALINA_OPTS% "-Djava.security.krb5.kdc=192.168.1.10 -Djava.security.krb5.realm=MYDOMAIN.COM -Djava.security.auth.login.config=file:/C:/Fediz-IDP-A/webapps/fediz-idp/WEB-INF/kerberos.jaas -Dsun.security.krb5.debug=true"If you are planing on running your IDP/STS Tomcat container as a system service, you must modify the service.bat file to ensure that you set the required Kerberos JVM parameter correctly. Otherwise your Tomcat will start without these parameters and Kerberos authentication will fail.SSL CertificateProviding a trusted SSL Certificate for the IDP helps to avoid irritating warnings from the browser when users access the IDP via a HTTPs connection. Since all computer of a Active Directory Domain share common trusted domain certificates, we can create a new webserver key at the AD which will be trusted by all participants of the domain.
        The certificate is only trusted at the Internet Explorer by default. To extend this trust to Firefox as well, you need to install the domain certificate manually into the trusted issuer store of Firefox.To do this you must define a certificate webserver policy at the AD server which allows the export of a private key. Next we need to create a new private/public key pair at the server with the common name (CN) being equal to the domain name of our IDP. After creating the certificate we need to export the key pair to a PKCS #12 file format. I like to use the KeyStore Explorer best to manage Java keystores. The KeyStore Explorer is also able to import the keypair export from the AD server. To set the correct key for the IDP Tomcat server, you need to replace the mytomidpkey key in the idp-ssl-server.jks keystore.
        Download or Build the IDP/STSYou can either download the IDP/STS from Apache webpage or you can build the IDP and STS again with maven. If you build your services from code, you can also update the configuration files before you build your war files. In that case you do not need to modify them later on. If you want to use Maven to build your own services execute the following command: mvn clean install -Pkerberos After deploying the fediz-idp.war and fediz-idp-sts.war to tomcat, you need to update the following configuration files according to your needs.
        STS ConfigurationThe kerberos.jaas file must be updated for the STS to match with our Kerberos idp principal:
        idp {
        com.sun.security.auth.module.Krb5LoginModule required
        refreshKrb5Config=true
        storeKey=true
        principal="idp/idp-host.mydomain.com@MYDOMAIN.COM";
        };
        Make sure that the cxf-transport.xml file imports the kerberos.xml file, which should already be the case if you build the STS with the kerberos Maven profile. Most changes required to enable Kerberos Authentication and Active Directory Claim Handling needs to be configured in the kerberos.xml file. You need to add the LDAP Claim Handler as well as the Kerberos Token Validator. If you use a kerberos keytab file for the IDP you do not need to set a callbackHandler for the kerberos token validator but the location to your keytab file instead.
        <?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: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.0.xsd
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util-2.0.xsd
        http://cxf.apache.org/jaxws
        http://cxf.apache.org/schemas/jaxws.xsd">

        <util:list id="claimHandlerList">
        <ref bean="claimsHandlerA" />
        <ref bean="claimsHandlerB" />
        </util:list>

        <bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource">
        <property name="url" value="ldap://ad-host.mydomain.com:389" />
        <property name="userDn"
        value="CN=IDP,OU=People,DC=mydomain,DC=com" />
        <property name="password" value="secretPwd" />
        </bean>

        <bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
        <constructor-arg ref="contextSource" />
        </bean>

        <util:map id="claimsToLdapAttributeMapping">
        <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role" value="memberOf" />
        <entry key="http://schemas.zurich.com/security/authorization/de/2013/05/claims/role" value="memberOf" />
        <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" value="givenName" />
        <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" value="sn" />
        <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" value="mail" />
        <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/country" value="c" />
        </util:map>

        <bean id="claimsHandlerA" class="org.apache.cxf.sts.claims.LdapClaimsHandler">
        <property name="ldapTemplate" ref="ldapTemplate" />
        <property name="claimsLdapAttributeMapping" ref="claimsToLdapAttributeMapping" />
        <property name="userNameAttribute" value="userPrincipalName" />
        <property name="userBaseDN" value="OU=People,DC=mydomain,DC=com" />
        <property name="realm" value="REALMA" />
        </bean>

        <bean id="kerberosValidator" class="org.apache.ws.security.validate.KerberosTokenValidator">
        <property name="contextName" value="idp"/>
        <property name="serviceName" value="HTTP/idp-host.mydomain.com@MYDOMAIN.COM"/>
        <property name="usernameServiceNameForm" value="true"/>
        <property name="spnego" value="true"/>
        <property name="callbackHandler">
        <bean class="com.sun.jndi.ldap.sasl.DefaultCallbackHandler">
        <constructor-arg index="0" value="idp/idp-host.mydomain.com@MYDOMAIN.COM"/>
        <constructor-arg index="1" value="secretPwd"/>
        <constructor-arg index="2" value="MYDOMAIN.COM"/>
        </bean>
        </property>
        </bean>

        <jaxws:endpoint id="transportSTSRealmAKerberos"
        implementor="#transportSTSProviderBean" address="/REALMA/STSServiceTransportKerberos"
        wsdlLocation="/WEB-INF/wsdl/ws-trust-1.4-service.wsdl"
        xmlns:ns1="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
        serviceName="ns1:SecurityTokenService" endpointName="ns1:TransportKerberos_Port">
        <jaxws:properties>
        <entry key="ws-security.bst.validator" value-ref="kerberosValidator"/>
        </jaxws:properties>
        </jaxws:endpoint>

        <jaxws:endpoint id="transportSTSRealmBKerberos"
        implementor="#transportSTSProviderBean" address="/REALMB/STSServiceTransportKerberos"
        wsdlLocation="/WEB-INF/wsdl/ws-trust-1.4-service.wsdl"
        xmlns:ns1="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
        serviceName="ns1:SecurityTokenService" endpointName="ns1:TransportKerberos_Port">
        <jaxws:properties>
        <entry key="ws-security.bst.validator" value-ref="kerberosValidator"/>
        </jaxws:properties>
        </jaxws:endpoint>

        </beans>
        IDP ConfigurationThe content of the security-config.xml file must be replaced with the content of security-config-kerberos.xml:
        <?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:security="http://www.springframework.org/schema/security"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

        <context:property-placeholder location="classpath:realm.properties"/>
        <context:component-scan base-package="org.apache.cxf.fediz.service.idp"/>

        <!-- Configure Spring Security -->
        <security:http auto-config="false" use-expressions="true" entry-point-ref="kerberosEntryPoint">
        <security:custom-filter after="CHANNEL_FILTER" ref="stsPortFilter" />
        <security:intercept-url pattern="/FederationMetadata/2007-06/FederationMetadata.xml" access="isAnonymous() or isAuthenticated()" />

        <!--<security:http-basic />-->
        <!--<security:form-login />-->
        <security:custom-filter ref="kerberosAuthenticationProcessingFilter" position="BASIC_AUTH_FILTER" />
        </security:http>

        <bean id="kerberosEntryPoint"
        class="org.apache.cxf.fediz.service.idp.kerberos.KerberosEntryPoint" />

        <bean id="kerberosAuthenticationProcessingFilter"
        class="org.apache.cxf.fediz.service.idp.kerberos.KerberosAuthenticationProcessingFilter">
        <property name="authenticationManager" ref="authenticationManager" />
        </bean>

        <security:authentication-manager alias="authenticationManager">
        <security:authentication-provider ref="stsAuthProvider" />
        </security:authentication-manager>

        <bean id="stsPortFilter" class="org.apache.cxf.fediz.service.idp.STSPortFilter" />

        <bean id="stsAuthProvider" class="org.apache.cxf.fediz.service.idp.STSAuthenticationProvider">
        <property name="wsdlLocation" value="https://localhost:0/fediz-idp-sts/${realm.STS_URI}/STSServiceTransportKerberos?wsdl"/>
        <property name="wsdlEndpoint" value="TransportKerberos_Port"/>
        <property name="wsdlService" value="SecurityTokenService"/>
        <property name="appliesTo" value="urn:fediz:idp"/>
        <property name="tokenType" value="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0"/>
        </bean>

        </beans>
        Enabling Kerberos Support for your browserBy default your browser will not send any Kerberos token to a normal Webpage. In IE you need to add the IDP URL to the list of trusted sides or even to local intranet sides. In Firefox you need to open about:config and add the IDP URL to network.negotiate-auth.delegation-uris and network.negotiate-auth.trusted-uris. I found this article from Oracle most helpful to setup my browser correctly.
        TroubleshootingYou can use the klist command at your client to verify that the correct Kerberos token are used on your local machine. klist purge will remove all cached Kerberos tokens on your computer. You can use Wireshark to analyse your web traffic. This is especially helpful to see what kind of token Kerbeidp-ssl-server.jksros/SPNEGO your browser is sending to the IDP. Fiddler is helpful to analyze if all the redirects from your Webapp to the IDP and back actually work as expected.
         Links
        • http://docs.fedoraproject.org/en-US/Fedora/html/Security_Guide/sect-Security_Guide-Single_Sign_on_SSO-Configuring_Firefox_to_use_Kerberos_for_SSO.html
        • http://superuser.com/questions/5161/windows-domain-authentication-with-firefox
        • http://www-01.ibm.com/support/knowledgecenter/SSCKBL_8.5.5/com.ibm.websphere.nd.multiplatform.doc/ae/tsec_SPNEGO_config_dc.html
        • http://blogs.iis.net/brian-murphy-booth/archive/2007/03/09/the-biggest-mistake-serviceprincipalname-s.aspx
        • http://www.novell.com/documentation/novellaccessmanager/adminguide/data/b9uctt5.html
        • http://www.oracle.com/technetwork/articles/idm/weblogic-sso-kerberos-1619890.html
        Categories: Jan Bernhardt

        Apache Santuario - XML Security for Java 2.0.2 release

        Colm O hEigeartaigh - Thu, 09/25/2014 - 17:33
        Apache Santuario - XML Security for Java 2.0.2 has been released. This is a minor release that fixes a couple of bugs with the streaming code and contains a few dependency upgrades.
        Categories: Colm O hEigeartaigh

        Pages

        Subscribe to Talend Community Coders aggregator