Latest Activity

Apache Fediz installation in a productive environment

Jan Bernhardt - Fri, 02/05/2016 - 21:19
In this article I'll explain to you what to do and what to be aware of, when you want to user Fediz IDP in production.

Basically you need to change all default passwords and certificates.

If you will use Tomcat as user Servlet container I'll also give you some tips how to secure tomcat best, so that an attacker will have a hard time breaking into your system.

IDP ChangesRemove Filesrm -f services\idp\src\main\resources\entities-realmb.xml
rm -f services\idp\src\main\resources\mystskey.cer
rm -f services\idp\src\main\resources\realm.properties
rm -f services\idp\src\main\resources\realma.cert
rm -f services\idp\src\main\resources\realmb.cert
rm -f services\idp\src\main\resources\stsKeystoreB.properties
rm -f services\idp\src\main\resources\stsrealm_a.jks
rm -f services\idp\src\main\resources\stsrealm_b.jks
rm -f services\idp\src\main\webapp\WEB-INF\idp-config-realma.xml
rm -f services\idp\src\main\webapp\WEB-INF\idp-config-realmb.xml
Rename Filesmv services\idp\src\main\resources\entities-realmA.xml services\idp\src\main\resources\entities-realm-myCompany.xml
mv services\idp\src\main\resources\stsKeystoreA.properties services\idp\src\main\resources\stsKeystoreMyCompany.properties
Modify Files
  • Change fediz-idp to idp as finalName in services\idp\pom.xml. This will hide your used IDP product within your URL and will make it easier if you will ever want to change to a different product.
  • Apply the following changes to your entities-realm-myCompany.xm
    • Rename all realmA settings to realmYourCompany
    • Change your realm identifier 
    • Use http:// or urn: at the beginning of your realm identifier to ensure interoperability with Microsoft ADFS
    • Change Keystore settings, especially the certificatePassword
    • Update stsUrl and idpUrl to reflect your installation
    • Remove fedizhelloworld from your applications
    • Remove oidc application if not used, or update passiveRequestorEndpointConstraint if oidc will be used
    • Remove or update all trustedIdps
  • Regenerate your own IDP SSL keys for services\idp\src\main\resources\idp-ssl-key.jks and store new certificate in services\idp\src\main\resources\idp-ssl-trust.jks. Remove all other certificates in idp-ssl-trust.jks
  • Update settings for your database in services\idp\src\main\resources\persistence.properties
  • Change passwords in services\idp\src\main\resources\stsKeystoreMyCompany.properties
  • Change usernames and passwords in services\idp\src\main\resources\users.properties. Use Bcrypt passwords instead of plaintext passwords.
  • Update wsdlLocation to reflect your STS URL in services\idp\src\main\webapp\WEB-INF\idp-servlet.xml
  • Ensure correct realm value within your services\idp\src\main\webapp\WEB-INF\web.xml
  • Apply the following changes within services\idp\src\main\webapp\WEB-INF\security-config.xml
    • Change realm identifier in federationEntryPoint
    • Enable bCryptPasswordEncoder
    • Enable form-login if desired and provide custom login screen in services/idp/src/main/webapp/WEB-INF/views/signinform.jsp
    • Remove all authentication alternatives, which you don't need
    • Change username and password in securityProperties if you need certificate based authentication
    • Remove all stsUPPortFilter settings, because they are only usefull for demo setups when your STS runs within the same Tomcat as your IDP.
    • Update all wsdlLocation to match your STS URL
Create Files
  • Provide your own keystore at services\idp\src\main\resources\stsrealm_myCompany.jks. This one should be the same as the one used later for the STS.
STS Changes Remove Filesrm -f services\sts\src\main\resources\stsrealm_a.jks
rm -f services\sts\src\main\resources\stsrealm_b.jks
rm -f services\sts\src\main\resources\realma.cert
rm -f services\sts\src\main\resources\realmb.cert
rm -f services\sts\src\main\webapp\WEB-INF\file.xml
rm -f services\sts\src\main\webapp\WEB-INF\passwords.xml
rm -f services\sts\src\main\webapp\WEB-INF\userClaims.xml
Rename Filesmv services\sts\src\main\resources\stsKeystoreA.properties services\sts\src\main\resources\stsKeystore.propertiesModify Files
  • Add dependency to services\sts\pom.xml (only needed if you want to use JEXL for claim mappings)
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-jexl</artifactId>
    <version>2.1.1</version>
    <scope>runtime</scope>
</dependency>
  • Change private key password in keystore and in Callbackhandler: services\sts\src\main\java\org\apache\cxf\fediz\service\sts\PasswordCallbackHandler.java 
  • Replace  with your own keystore.properties file.
  • Change passwords in services\sts\src\main\resources\stsTruststore.properties 
  • Change log level in services\sts\src\main\resources\log4j.properties 
  • Remove all certificates in services\sts\src\main\resources\ststrust.jks and add your own.
  • Change user accounts in services\sts\src\main\webapp\WEB-INF\passwords.xml 
  • Do the following changes within: services\sts\src\main\webapp\WEB-INF\cxf-transport.xml
    • Import file with user realm configuration, like ldap.xml
    • Change Relationship settings
    • Add Claim Hanlder (if needed)
    • Rename all realmA in text to realmYourCompany
    • Remove all realmB settings / beans / endpoints
Create Files
  • Add ClaimMapping Scripts (if needed)
    services\sts\src\main\resources\claimMapping-trusted-realm.script 
  • Add you own keystore services\sts\src\main\resources\stsrealm_myCompany.jks
Tomcat InstallationTomcat Home 
Only download and install Tomcat manually, if your distribution does not provide a tomcat installation. System based installation is usually better, because you will receive Tomcat (security) updates automatically with your other system updates!
1. Download latest Tomcat Version:
https://tomcat.apache.org/download-70.cgi

2. Extract Tomcat to /usr/share/

3. Create a symbolic link pointing to your latest tomcat download:
ln -s /usr/share/apache-tomcat-7.0.67 /usr/share/tomcat
Using of symbolic links will make it easier to switch to newer versions later on.
4. Restrict tomcat installation
# Create tomcat group
groupadd tomcat

# Set ownership of all files to root and provide tomcat access via group ownership
chown -R root:tomcat /usr/share/tomcat/

# Remove redundant files and folders
rm -f /usr/share/tomcat/bin/*.bat
rm -rf /usr/share/tomcat/temp
rm -rf /usr/share/tomcat/work
rm -rf /usr/share/tomcat/logs
rm -rf /usr/share/tomcat/webapps

# Make all normal files readonly
find /usr/share/tomcat/ -type f -exec chmod 640 {} +
chmod 750 /usr/share/tomcat/bin/*.sh

# Allow tomcat to access all tomcat folders
find /usr/share/tomcat/ -type d -exec chmod 770 {} +
IDP Tomcat SetupSetup a tomcat base environment for your IDP
# Create folders
mkdir /usr/share/tomcat-idp
mkdir /usr/share/tomcat-idp/conf
mkdir /usr/share/tomcat-idp/logs
mkdir /usr/share/tomcat-idp/temp
mkdir /usr/share/tomcat-idp/webapps
mkdir /usr/share/tomcat-idp/work

# Copy conf files
cp /usr/share/tomcat/conf/* /usr/share/tomcat-idp/conf/

# Copy your war file to webapps
cp ~/idp.war /usr/share/tomcat-idp/webapps/
Create a system startup script /etc/init.d/tomcat-idp file, with the following content:

#!/bin/bash
#
# tomcat7 This shell script takes care of starting and stopping Tomcat-IDP
# Forked from: https://gist.github.com/valotas/1000094
#
# chkconfig: - 80 20
#
### BEGIN INIT INFO
# Provides: tomcat-idp
# Required-Start: $network $syslog
# Required-Stop: $network $syslog
# Default-Start:
# Default-Stop:
# Description: Release implementation for Servlet 2.5 and JSP 2.1
# Short-Description: start and stop tomcat-idp
### END INIT INFO

## Source function library.
#. /etc/rc.d/init.d/functions
export CATALINA_HOME=/usr/share/tomcat
export CATALINA_BASE=/usr/share/tomcat-idp
export JAVA_HOME=/usr/java/default
export JAVA_OPTS="-Dfile.encoding=UTF-8 \
-Djava.net.preferIPv4Stack=true \
-Djava.net.preferIPv4Addresses=true \
-Dnet.sf.ehcache.skipUpdateCheck=true \
-XX:+DoEscapeAnalysis \
-XX:+UseConcMarkSweepGC \
-XX:+CMSClassUnloadingEnabled \
-XX:+UseParNewGC \
-XX:MaxPermSize=128m \
-Xms512m -Xmx512m"
export PATH=$JAVA_HOME/bin:$PATH
SHUTDOWN_WAIT=20
USER=tomcat-idp
tomcat_pid() {
echo `ps aux | grep org.apache.catalina.startup.Bootstrap | grep -v grep | awk '{ print $2 }'`
}

start() {
pid=$(tomcat_pid)
if [ -n "$pid" ]
then
echo "Tomcat is already running (pid: $pid)"
else
# Start tomcat
echo "Starting $USER"
ulimit -n 100000
umask 007
/bin/su -p -s /bin/sh $USER $CATALINA_HOME/bin/startup.sh
fi


return 0
}

stop() {
pid=$(tomcat_pid)
if [ -n "$pid" ]
then
echo "Stoping $USER"
/bin/su -p -s /bin/sh $USER $CATALINA_HOME/bin/shutdown.sh

let kwait=$SHUTDOWN_WAIT
count=0;
until [ `ps -p $pid | grep -c $pid` = '0' ] || [ $count -gt $kwait ]
do
echo -n -e "\nwaiting for processes to exit";
sleep 1
let count=$count+1;
done

if [ $count -gt $kwait ]; then
echo -n -e "\nkilling processes which didn't stop after $SHUTDOWN_WAIT seconds"
kill -9 $pid
fi
else
echo "$USER is not running"
fi

return 0
}

case $1 in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
pid=$(tomcat_pid)
if [ -n "$pid" ]
then
echo "$USER is running with pid: $pid"
else
echo "$USER is not running"
fi
;;
esac
exit 0
Register Tomcat for autostart:
chkconfig tomcat-idp onStart, Wait and Stop Tomcat
/etc/init.d/tomcat-idp start
tail -f /usr/share/tomcat-idp/logs/catalina.out
/etc/init.d/tomcat-idp stop
Your idp.war file should now be extracted.
Copy the idp keystore to your tomcat-idp root folder

cp /usr/share/tomcat-idp/webapps/idp/WEB-INF/classes/idp-ssl-key.jks /usr/share/tomcat-idp/
Adjust settings of /usr/share/tomcat-idp/server.xml
  • Remove all out-commented blockes to improve readability.
  • Change shutdown password to something more complex:

<server port="8005" shutdown="ComPlexWord">
  • Enable SSL Support
<connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol">
               maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
               keystoreFile="idp-ssl-key.jks"
               keystorePass="complexPassword"
               sslProtocol="TLS" />
  • Disable autoDeploy

<Host appbase="webapps" name="localhost"
            unpackWARs="true" autoDeploy="false">
. . .
</host>
Update file permissions
# Create tomcat-idp user
useradd -d /usr/share/tomcat-idp tomcat-idp
useradd -G tomcat tomcat-idp

# Set ownership of all files to root and provide tomcat-idp access via group ownership
chown -R root:tomcat-idp /usr/share/tomcat-idp/

# Make all normal files readonly
find /usr/share/tomcat-idp/ -type f -exec chmod 640 {} +

# Allow tomcat-idp to change all files in temp and work
find /usr/share/tomcat-idp/temp/ -type f -exec chmod 660 {} + 
find /usr/share/tomcat-idp/work/ -type f -exec chmod 660 {} +

# Allow tomcat-idp to access all tomcat folders
find /usr/share/tomcat-idp/ -type d -exec chmod 770 {} +

# Log files can only be appended by tomcat-idp but not read
chmod 730 /usr/share/tomcat-idp/logs

# Tomcat-IDP will not be able to deploy further applications by its own
chmod 750 /usr/share/tomcat-idp/webapps
Start Tomcat-IDP again and check if startup was successful
/etc/init.d/tomcat-idp start
tail -f /usr/share/tomcat-idp/logs/catalina.out
STS Tomcat Setup
It can be recommended to install the STS on a different / dedicated server. In this blog post I will assume that you install IDP and STS on the same machine and therefore need to change port configuration for your tomcat instance.
The STS Tomcat setup is almost the same as for the IDP.
Setup a tomcat base environment for your STS
# Create folders
mkdir /usr/share/tomcat-sts
mkdir /usr/share/tomcat-sts/conf
mkdir /usr/share/tomcat-sts/logs
mkdir /usr/share/tomcat-sts/temp
mkdir /usr/share/tomcat-sts/webapps
mkdir /usr/share/tomcat-sts/work

# Copy conf files
cp /usr/share/tomcat/conf/* /usr/share/tomcat-sts/conf/

# Copy your war file to webapps
cp ~/sts.war /usr/share/tomcat-sts/webapps/Create a system startup script /etc/init.d/tomcat-sts file, with the following content:

#!/bin/bash
#
# tomcat7 This shell script takes care of starting and stopping Tomcat-STS
# Forked from: https://gist.github.com/valotas/1000094
#
# chkconfig: - 80 20
#
### BEGIN INIT INFO
# Provides: tomcat-sts
# Required-Start: $network $syslog
# Required-Stop: $network $syslog
# Default-Start:
# Default-Stop:
# Description: Release implementation for Servlet 2.5 and JSP 2.1
# Short-Description: start and stop tomcat-sts
### END INIT INFO

## Source function library.
#. /etc/rc.d/init.d/functions
export CATALINA_HOME=/usr/share/tomcat
export CATALINA_BASE=/usr/share/tomcat-sts
export JAVA_HOME=/usr/java/default
export JAVA_OPTS="-Dfile.encoding=UTF-8 \
-Djava.net.preferIPv4Stack=true \
-Djava.net.preferIPv4Addresses=true \
-Dnet.sf.ehcache.skipUpdateCheck=true \
-XX:+DoEscapeAnalysis \
-XX:+UseConcMarkSweepGC \
-XX:+CMSClassUnloadingEnabled \
-XX:+UseParNewGC \
-XX:MaxPermSize=128m \
-Xms512m -Xmx512m"
export PATH=$JAVA_HOME/bin:$PATH
SHUTDOWN_WAIT=20
USER=tomcat-sts

tomcat_pid() {
echo `ps aux | grep org.apache.catalina.startup.Bootstrap | grep -v grep | awk '{ print $2 }'`
}

start() {
pid=$(tomcat_pid)
if [ -n "$pid" ]
then
echo "Tomcat is already running (pid: $pid)"
else
# Start tomcat
echo "Starting $USER"
ulimit -n 100000
umask 007
/bin/su -p -s /bin/sh $USER $CATALINA_HOME/bin/startup.sh
fi


return 0
}

stop() {
pid=$(tomcat_pid)
if [ -n "$pid" ]
then
echo "Stoping $USER"
/bin/su -p -s /bin/sh $USER $CATALINA_HOME/bin/shutdown.sh

let kwait=$SHUTDOWN_WAIT
count=0;
until [ `ps -p $pid | grep -c $pid` = '0' ] || [ $count -gt $kwait ]
do
echo -n -e "\nwaiting for processes to exit";
sleep 1
let count=$count+1;
done

if [ $count -gt $kwait ]; then
echo -n -e "\nkilling processes which didn't stop after $SHUTDOWN_WAIT seconds"
kill -9 $pid
fi
else
echo "$USER is not running"
fi

return 0
}

case $1 in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
pid=$(tomcat_pid)
if [ -n "$pid" ]
then
echo "$USER is running with pid: $pid"
else
echo "$USER is not running"
fi
;;
esac
exit 0
Register Tomcat for autostart:
chkconfig tomcat-sts onStart, Wait and Stop Tomcat
/etc/init.d/tomcat-sts start
tail -f /usr/share/tomcat-sts/logs/catalina.out
/etc/init.d/tomcat-sts stopYour sts.war file should now be extracted.
Copy the sts keystore to your tomcat-sts root folder:
cp /usr/share/tomcat-sts/webapps/sts/WEB-INF/classes/idp-ssl-key.jks /usr/share/tomcat-sts/
cp /usr/share/tomcat-sts/webapps/sts/WEB-INF/classes/idp-ssl-trust.jks /usr/share/tomcat-sts/Adjust settings of /usr/share/tomcat-sts/server.xml
  • Remove all out-commented blockes to improve readability.
  • Change shutdown password to something more complex:

<server port="9005" shutdown="ComPlexWord">
  • Enable SSL Support
<connector port="9443" protocol="org.apache.coyote.http11.Http11Protocol"
               maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
               keystoreFile="idp-ssl-key.jks"
               keystorePass="complexpassword"
               truststoreFile="idp-ssl-trust.jks"
               truststorePass="anotherComplexWord"
               truststoreType="JKS"
               clientAuth="want"
               sslProtocol="TLS" />
  • Disable autoDeploy
<host appbase="webapps" name="localhost"
            unpackWARs="true" autoDeploy="false">
. . .
</host>Update file permissions
# Create tomcat-sts user
useradd -d /usr/share/tomcat-sts tomcat-sts
useradd -G tomcat tomcat-sts

# Set ownership of all files to root and provide tomcat-sts access via group ownership
chown -R root:tomcat-sts /usr/share/tomcat-sts/

# Make all normal files readonly
find /usr/share/tomcat-sts/ -type f -exec chmod 640 {} +

# Allow tomcat-sts to change all files in temp and work
find /usr/share/tomcat-sts/temp/ -type f -exec chmod 660 {} +
find /usr/share/tomcat-sts/work/ -type f -exec chmod 660 {} +

# Allow tomcat-sts to access all tomcat folders
find /usr/share/tomcat-sts/ -type d -exec chmod 770 {} +

# Log files can only be appended by tomcat-sts but not read
chmod 730 /usr/share/tomcat-sts/logs

# Tomcat-STS will not be able to deploy further applications by its own
chmod 750 /usr/share/tomcat-sts/webapps
Start Tomcat-STS again and check if startup was successful
/etc/init.d/tomcat-sts start
tail -f /usr/share/tomcat-sts/logs/catalina.out
Categories: Jan Bernhardt

Apache Karaf Tutorial Part 8 - Distributed OSGi

Christian Schneider - Tue, 02/02/2016 - 08:54

Blog post edited by Christian Schneider - "Updated to karaf 4"

By default OSGi services are only visible and accessible in the OSGi container where they are published. Distributed OSGi allows to define services in one container and use them in some other (even over machine boundaries).

For this tutorial we use the DOSGi sub project of CXF which is the reference implementation of the OSGi Remote Service Admin specification, chapter 122 in the OSGi 4.2 Enterprise Specification).

Example on github

Introducing the example

Following the hands on nature of these tutorial we start with an example that can be tried in some minutes and explain the details later.

Our example is again the tasklist example from Part 1 of this tutorial. The only difference is that we now deploy the model and the persistence service on container A and model and UI to container B and we install the dosgi runtime on bother containers.

As DOSGi should not be active for all services on a system the spec defines that the service property "osgi.remote.interfaces" triggers if DOSGi should process the service. It expects the interface names that this service should export remotely. Setting the property to "*" means that all interfaces the service implements should be exported. The tasklist persistence service already sets the property so the service is exported with defaults.

Installing the service

To keep things simple we will install container A and B on the same system.

Install Service config:property-set -p org.apache.cxf.dosgi.discovery.zookeeper zookeeper.port 2181 config:property-set -p org.apache.cxf.dosgi.discovery.zookeeper.server clientPort 2181 feature:repo-add cxf-dosgi 1.7.0 feature:install cxf-dosgi-discovery-distributed cxf-dosgi-zookeeper-server feature:repo-add mvn:net.lr.tasklist/tasklist-features/1.0.0-SNAPSHOT/xml feature:install example-tasklist-persistence

After these commands the tasklist persistence service should be running and be published on zookeeper.

You can check the wsdl of the exported service http://localhost:8181/cxf/net/lr/tasklist/model/TaskService?wsdlBy starting the zookeeper client zkCli.sh from a zookeeper distro you can optionally check that there is a node for the service below the osgi path.

Installing the UI
  • Unpack into folder container_b
  • Start bin/karaf

 

Install Client config:property-set -p org.ops4j.pax.web org.osgi.service.http.port 8182 config:property-set -p org.apache.cxf.dosgi.discovery.zookeeper zookeeper.port 2181 feature:repo-add cxf-dosgi 1.7.0 feature:install cxf-dosgi-discovery-distributed feature:repo-add mvn:net.lr.tasklist/tasklist-features/1.0.0-SNAPSHOT/xml feature:install example-tasklist-ui

 

The tasklist client ui should be in status Active/Created and the servlet should be available on http://localhost:8182/tasklist. If the ui bundle stays in status graceperiod then DOSGi did not provide a local proxy for the persistence service.

How does it work

The Remote Service Admin spec defines an extension of the OSGi service model. Using special properties when publishing OSGi services you can tell the DOSGi runtime to export a service for remote consumption. The CXF DOSGi runtime listens for all services deployed on the local container. It only processes services that have the "osgi.remote.interfaces" property. If the property is found then the service is either exported with the named interfaces or with all interfaces it implements.The way the export works can be fine tuned using the CXF DOSGi configuration options.

By default the service will be exported using the CXF servlet transport. The URL of the service is derived from the interface name. The servlet prefix, hostname and port number default to the Karaf defaults of "cxf", the ip address of the host and the port 8181. All these options can be defined using a config admin configuration (See the configuration options). By default the service uses the CXF Simple Frontend and the Aegis Databinding. If the service interface is annotated with the JAX-WS @WebService annotation then the default is JAX-WS frontend and JAXB databinding.

The service informations are then also propagated using the DOSGi discovery. In the example we use the Zookeeper discovery implementation. So the service metadata is written to a zookeeper server.

The container_b will monitor the local container for needed services. It will then check if a needed service is available on the discovery impl (on the zookeeper server in our case). For each service it finds it will create a local proxy that acts as an OSGi service implementing the requested interface. Incoming request are then serialized and sent to the remote service endpoint.

So together this allows for almost transparent service calls. The developer only needs to use the OSGi service model and can still communicate over container boundaries.

View Online
Categories: Christian Schneider

An interop demo between Apache CXF Fediz and Keycloak

Colm O hEigeartaigh - Mon, 02/01/2016 - 17:15
Last week, I showed how to use the Apache CXF Fediz IdP as an identity broker with a real-world SAML SSO IdP based on the Shibboleth IdP (as opposed to an earlier article which used a mocked SAML SSO IdP). In this post, I will give similar instructions to configure the Fediz IdP to act as an identity broker with Keycloak.

1) Install and configure Keycloak

Download and install the latest Keycloak distribution (tested with 1.8.0). Start keycloak in standalone mode by running 'sh bin/standalone.sh'.

1.1) Create users in Keycloak

First we need to create an admin user by navigating to the following URL, and entering a password:
  • http://localhost:8080/auth/
Click on the "Administration Console" link, logging on using the admin user credentials. You will see the configuration details of the "Master" realm. For the purposes of this demo, we will create a new realm. Hover the mouse pointer over "Master" in the top left-hand corner, and click on "Add realm". Create a new realm called "realmb". Now we will create a new user in this realm. Click on "Users" and select "Add User", specifying "alice" as the username. Click "save" and then go to the "Credentials" tab for "alice", and specify a password, unselecting the "Temporary" checkbox, and reset the password.

1.2) Create a new client application in Keycloak

Now we will create a new client application for the Fediz IdP in Keycloak. Select "Clients" in the left-hand menu, and click on "Create". Specify the following values:
  • Client ID: urn:org:apache:cxf:fediz:idp:realm-A
  • Client protocol: saml
  • Client SAML Endpoint: https://localhost:8443/fediz-idp/federation
Once the client is created you will see more configuration options:
  • Select "Sign Assertions"
  • Select "Force Name ID Format".
  • Valid Redirect URIs: https://localhost:8443/*
Now go to the "SAML Keys" tab of the newly created client. Here we will have to import the certificate of the Fediz IdP so that Keycloak can validate the signed SAML requests. Click "Import" and specify:
  • Archive Format: JKS
  • Key Alias: realma
  • Store password: storepass
  • Import file: stsrealm_a.jks
1.3) Export the Keycloak signing certificate

Finally, we need to export the Keycloak signing certificate so that the Fediz IdP can validate the signed SAML Response from Keycloak. Select "Realm Settings" (for "realmb") and click on the "Keys" tab. Copy and save the value specified in the "Certificate" textfield.

2) Install and configure the Apache CXF Fediz IdP and sample Webapp

Follow a previous tutorial to deploy the latest Fediz IdP + STS to Apache Tomcat, as well as the "simpleWebapp". Test that the "simpleWebapp" is working correctly by navigating to the following URL (selecting "realm A" at the IdP, and authenticating as "alice/ecila"):
  • https://localhost:8443/fedizhelloworld/secure/fedservlet
2.1) Configure the Fediz IdP to communicate with Keycloak

Now we will configure the Fediz IdP to authenticate the user in "realm B" by using the SAML SSO protocol. Edit 'webapps/fediz-idp/WEB-INF/classes/entities-realma.xml'. In the 'idp-realmA' bean:
  • Change the port in "idpUrl" to "8443". 
In the 'trusted-idp-realmB' bean:
  • Change the "url" value to "http://localhost:8080/auth/realms/realmb/protocol/saml".
  • Change the "protocol" value to "urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser".
  • Change the "certificate" value to "keycloak.cert".
2.2) Configure Fediz to use the Keycloak signing certificate

Copy 'webapps/fediz-idp/WEB-INF/classes/realmb.cert' to a new file called 'webapps/fediz-idp/WEB-INF/classes/keycloak.cert'. Edit this file + delete the content between the "-----BEGIN CERTIFICATE----- / -----END CERTIFICATE-----" tags, pasting instead the Keycloak signing certificate as retrieved in step "1.3" above.

The STS also needs to trust the Keycloak signing certificate. Copy keycloak.cert into 'webapps/fediz-idp-sts/WEB-INF/classes". In this directory import the keycloak.cert into the STS truststore via:
  • keytool -keystore ststrust.jks -import -file keycloak.cert -storepass storepass -alias keycloak
Restart Fediz to pick up the changes (you may need to remove the persistent storage first).

3) Testing the service

To test the service navigate to:
  • https://localhost:8443/fedizhelloworld/secure/fedservlet
Select "realm B". You should be redirected to the Keycloak authentication page. Enter the user credentials you have created. You will be redirected to Fediz, where it converts the received SAML token to a token in the realm of Fediz (realm A) and redirects to the web application.


Categories: Colm O hEigeartaigh

An interop demo between Apache CXF Fediz and Shibboleth

Colm O hEigeartaigh - Tue, 01/26/2016 - 12:45
Apache CXF Fediz is an open source implementation of the WS-Federation Passive Requestor Profile for SSO. It allows you to configure SSO for your web application via a container plugin, which redirects the user to authenticate at an IdP (Fediz or another WS-Federation based IdP). The Fediz IdP also supports the ability to act as an identity broker to a remote IdP, if the user is to be authenticated in a different realm. Last year, this blog covered a new feature of Apache CXF Fediz 1.2.0, which was the ability to act as an identity broker with a remote SAML SSO IdP. In this post, we will look at extending the demo to work with the Shibboleth IdP.

1) Install and configure the Apache CXF Fediz IdP and sample Webapp

Firstly, follow a previous tutorial to deploy the latest Fediz IdP + STS to Apache Tomcat, as well as the "simpleWebapp". Test that the "simpleWebapp" is working correctly by navigating to the following URL (selecting "realm A" at the IdP, and authenticating as "alice/ecila"):
  • https://localhost:8443/fedizhelloworld/secure/fedservlet
Now we will configure the Fediz IdP to authenticate the user in "realm B", by using the SAML SSO protocol with a Shibboleth IdP instance. Edit 'webapps/fediz-idp/WEB-INF/classes/entities-realma.xml':

In the 'idp-realmA' bean:
  • Change the port in "idpUrl" to "8443". 
In the 'trusted-idp-realmB' bean:
  • Change the "url" value to "http://localhost:9080/idp/profile/SAML2/Redirect/SSO".
  • Change the "protocol" value to "urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser".
  • Add the following property: <property name="parameters"><util:map><entry key="require.known.issuer" value="false" /></util:map></property>
Restart Fediz to pick up the changes (you may need to remove the persistent storage first).

2) Install and configure Shibboleth

This is a reasonable complex task, so let's break it down into various sections.

2.1) Install Shibboleth and deploy to Tomcat

Download and extract the latest Shibboleth Identity Provider (tested with 3.2.1). Install Shibboleth by running the "install.sh" script in the bin directory. Install Shibboleth to "$SHIB_HOME" and use the default values that are prompted as part of the installation process, entering a random password for the keystore (we won't be using it). Download and extract an Apache Tomcat 7 instance, and follow these steps:
  • Copy '$SHIB_HOME/war/idp.war' into the Tomcat webapps directory.
  • Configure Shibboleth to find the IDP by defining: export JAVA_OPTS="-Xmx512M -Didp.home=$SHIB_HOME".
  • Next you need to download the jstl jar (https://repo1.maven.org/maven2/jstl/jstl/1.2/) + put it in the lib directory of Tomcat.
  • Edit conf/server.xml + change the ports to avoid conflict with the Tomcat instance that the Fediz IdP is running in. (e.g. use 9080 instead of 8080, etc.).
  • Now start Tomcat + check that everything is working by navigating to: http://localhost:9080/idp/profile/status
2.2) Configure the RP provider in Shibboleth

Next we need to configure the Fediz IdP as a RP (relying party) in Shibboleth. The Fediz IdP has the ability to generate metadata (either WS-Federation or SAML SSO) for a trusted IdP. Navigate to the following URL in a browser and save the metadata to a local file "fediz-metadata.xml":
  • https://localhost:8443/fediz-idp/metadata/urn:org:apache:cxf:fediz:idp:realm-B
Edit '$SHIB_HOME/conf/metadata-providers.xml' and add the following configuration to pick up this metadata file:

<MetadataProvider id="FedizMetadata"  xsi:type="FilesystemMetadataProvider" metadataFile="$METADATA_PATH/fediz-metadata.xml"/>

As we won't be encrypting the SAML response in this demo, edit the '$SHIB_HOME/idp.properties' file and uncomment the "idp.encryption.optional = false" line, changing "false" to "true".

2.3) Configuring the Signing Keys in Shibboleth

Next we need to copy the keys that Fediz has defined for "realm B" to Shibboleth. Copy the signing certificate "realmb.cert" from the Fediz source and rename it as '$SHIB_HOME/credentials/idp-sigining.crt'. Next we need to extract the private key from the keystore and save it as a plaintext private key. Download the realmb keystore. Extract the private key via:
  • keytool -importkeystore -srckeystore stsrealm_b.jks -destkeystore stsrealmb.p12 -deststoretype PKCS12 -srcalias realmb -deststorepass storepass -srcstorepass storepass -srckeypass realmb -destkeypass realmb
  • openssl pkcs12 -in stsrealmb.p12  -nodes -nocerts -out idp-signing.key
  • Edit idp-signing.key to remove any additional information before the "BEGIN PRIVATE KEY" part.
  • cp idp-signing.key $SHIB_HOME/credentials
2.4) Configure Shibboleth to authenticate users

Next we need to configure Shibboleth to authenticate users. If you have a configured KDC or LDAP installation on your machine, then it is easiest to use this, if you configure some test users there. If not then, in this section we will configure Shibboleth to use JAAS to authenticate users via Kerberos. Edit '$SHIB_HOME/conf/authn/password-authn-config.xml' + comment out the ldap import, instead uncommenting the "jaas-authn-config.xml" import. Next edit '$SHIB_HOME/conf/authn/jaas.config' and replace the contents with:

 ShibUserPassAuth {
    com.sun.security.auth.module.Krb5LoginModule required refreshKrb5Config=true useKeyTab=false;
};

Now we will set up and configure a test KDC. Assuming you are running this demo on linux, edit '/etc/krb5.conf' and change the "default_realm" to "service.ws.apache.org" + add the following to the realms section:

        service.ws.apache.org = {
                kdc = localhost:12345
        }

Now we will look at altering a test-case I wrote that uses Apache Kerby as a test-kdc. Clone my testcases github repo and go to the "cxf-kerberos-kerby" test-case, which is part of the top level "cxf" projects. Edit the AuthenticationTest
and change the values for KDC_PORT + KDC_UDP_PORT to "12345". Next remove the @org.junit.Ignore annotation from the "launchKDCTest()" method to just launch the KDC + sleep for a few minutes. Launch the test on the command line via "mvn test -Dtest=AuthenticationTest".

2.5) Configure Shibboleth to include the authenticated principal in the SAML Subject

For the purposes of our demo scenario, the Fediz IdP expects the authenticated principal in the SAML Subject it gets back from Shibboleth. Edit '$SHIB_HOME/conf/attribute-filter.xml' and add the following:

    <AttributeFilterPolicy id="releasePersistentIdToAnyone">
        <PolicyRequirementRule xsi:type="ANY"/>

        <AttributeRule attributeID="persistentId">
            <PermitValueRule xsi:type="ANY"/>
        </AttributeRule>
    </AttributeFilterPolicy>

Edit '$SHIB_HOME/conf/attribute-resolver.xml' and add the following:

<resolver:AttributeDefinition id="persistentId" xsi:type="ad:PrincipalName">
      <resolver:AttributeEncoder xsi:type="enc:SAML1StringNameIdentifier" nameFormat="urn:mace:shibboleth:1.0:nameIdentifier"/>
      <resolver:AttributeEncoder xsi:type="enc:SAML2StringNameID" nameFormat="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"/>
</resolver:AttributeDefinition>

Edit '$SHIB_HOME/conf/saml-nameid.xml' and comment out any beans listed in the "shibboleth.SAML2NameIDGenerators" list. Finally, edit '$SHIB_HOME/conf/saml-nameid.properties' and uncomment the legacy Generator:

idp.nameid.saml2.legacyGenerator = shibboleth.LegacySAML2NameIDGenerator

That will enable Shibboleth to process the "persistent" attribute using the Principal Name. (Re)start the Tomcat instance we we should be ready to go.

3) Testing the service

To test the service navigate to:
  • https://localhost:8443/fedizhelloworld/secure/fedservlet
Select "realm B". You should be redirected to the Shibboleth authentication page. Enter "alice/alice" as the username/password. You will be redirected to Fediz, where it converts the received SAML token to a token in the realm of Fediz (realm A) and redirects to the web application.




Categories: Colm O hEigeartaigh

Amazon EC2 plugin – 1.30 Released

Francis Upton's blog - Sun, 01/24/2016 - 01:46

A significant bug fix release was made in the plugin, thanks to all to helped test is and provided contributions.

The next release will probably be in the next month or so and will include the acceptance of enhancement PRs that have been filed.

Version 1.30 (Jan 23, 2016)
  • Add config to prefer the public IP to private IP when ssh-ing into slave
  • Added common method to compute tag value and also created constants for demand and spot
  • JENKINS-27601 instance caps incorrectly calculated
  • JENKINS-23787 EC2-plugin not spooling up stopped nodes
  • Depend on the aws-java-sdk plugin to limit AWS SDK duplication
  • Upgrade AWS SDK to 1.10.26
  • Terminate instance even if ec2 node deletion failed
  • JENKINS-27260 SPNEGO for Windows in the EC2 Plugin
  • JENKINS-26493 Use new EC2 API endpoint hostnames
  • JCIFS first tries to resolve a dfs path would timeout causing a long startup delay
  • JENKINS-28754 Jenkins EC2 Plugin should show timestamp in slave logs
  • JENKINS-30284 EC2 plugin too aggressive in timing in contacting new AWS instance over SSH
  • Use AWS4SignerType instead of QueryStringSignerType
  • Add minimum timeout for windows launching
  • Better exception handling in uptime check
  • JENKINS-29851 Global instance cap not calculated for spot instances
  • JENKINS-32439 JENKINS-32439 Incorrect slave template (AMI) found when launching slave
  • Improve logging to be less verbose

Categories: Francis Upton

Two Bays trail run 2016

Olivier Lamy - Sun, 01/24/2016 - 00:12
So I just started the year with a mid distance trail running.
Last year I did the 28km but decided to go for the 56km this year.
Training during summer and xmas period is a bit complicated and need some real motivation. But I finally managed to do a decent training.
The race was a bit complicated with the weather. I had some hard time with the hot (33° in some country bush part!!)
Bad eating strategy at the start. (eat too much...)
But so I did it. I would expect better time but the temperature really kills me on the way back. So I must be happy with this 7H for 56km and +1600m/-1600m.
I managed to build a video. So enjoy how is to run in Australia :-)
Strava activity here (Some GPS issues but I really did 56km :-) )
Next race is the rollercoaster 44km 27th February.
Then the big one of the year Ultra Trail Australia 100km in the Blue mountains.
And maybe the Surf coast century for a second time with a sub 12h goal (depends how the body will be in Jun :-) )
Categories: Olivier Lamy

Understanding Spring Web-Flow in Apache Fediz - Part 2

Jan Bernhardt - Sat, 01/16/2016 - 15:46
After explaining in Part 1 of this topic how the Spring Web-Flow will be initiated I'm going to review the actual flow in some more detail in this post.

The signin request flow can be customized within the WEB-INF/flows/federation-signin-request.xml file. The standard flow looks like this:


The bold line shows a normal login flow, when the user was not authenticated earlier and no 3rd party IDP is involved.
TO BE CONTINUED...
Categories: Jan Bernhardt

Amazon EC2 Plugin Release 1.30

Francis Upton's blog - Tue, 01/12/2016 - 16:24

I have just finished a bunch of work on this plugin to fix a number of bugs related to starting instances and respecting instance caps for spot instances. The plugin will now restart a stopped instance and always respect the instance caps. Other issues about the credentials working correctly in all regions should be fixed.

Before I make this release, I would like to have people test with the 1.30 Snapshot to see if there are any problems. Once this release is done, I will take some new features and move to require a more recent version of Jenkins.


Categories: Francis Upton

Understanding Spring Web-Flow in Apache Fediz - Part 1

Jan Bernhardt - Thu, 01/07/2016 - 16:20
When I started to work with Apache Fediz, most of the actions looked like magic to me, because I was not able to understand how Spring Security and Spring Web Flow have been used in Apache Fediz. After several hours of learning and investigation I finally understood how all this works together.

In this post I would like to share with you from what I understood of how Fediz works internally.
When you take a look inside the WEB-INF/web.xml you will find three URL mappings:
<servlet-mapping>
  <servlet-name>CXFServlet</servlet-name>
  <url-pattern>/services/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
  <servlet-name>idp</servlet-name>
  <url-pattern>/federation</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>metadata</servlet-name>
<url-pattern>/FederationMetadata/2007-06/FederationMetadata.xml</url-pattern>
</servlet-mapping>
  • /services/* provides access to all REST services for updating the IDP configuration
  • /FederationMetadata/2007-06/FederationMetadata.xml provides access to the generated IDP metadata document which is usually used in application wizards to setup the correct IDP configuration
  • /federation provides access to the configured Spring Web-Flow

If you take a look inside the WEB-INF/web.xml you will see that the /federation URL is linked with org.springframework.web.servlet.DispatcherServlet. The initialization of the Spring Flow however takes place within the WEB-INF/idp-servlet.xml.
So how is the DispatcherServlet linked to the idp-servlet.xml?
The key to the answer is Spring MVC which uses Convention over Configuration (CoC). Spring will search for a file with the same name as the servlet-name and ending with "-servlet.xml". To apply this knowledge you can see that the /federation URL is mapped to the servlet name idp and thus the default configuration spring file which will be loaded from the DispatcherServlet is idp-servlet.xml
Spring ConfigurationWithin the idp-servlet.xml you will find a spring configuration to setup the Spring Web Flow.
First Spring will do a component scan to instantiate and autowire all beans with a @Component annotation located within the beans package. These beans usually provide specific actions which are executed within the flows.
<context:component-scan base-package="org.apache.cxf.fediz.service.idp.beans" />
Now the JSP views and HTML resources like images will be made available for the spring web flow:
<mvc:resources mapping="/images/**" location="/resources/images/" />
<mvc:view-controller path="/" view-name="index" />
<mvc:view-controller path="/federation/up/login" view-name="signinform" />

<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>

<bean id="viewFactoryCreator"
class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
<property name="viewResolvers">
<list>
<ref local="viewResolver" />
</list>
</property>
</bean>

<bean id="expressionParser"
class="org.springframework.webflow.expression.WebFlowOgnlExpressionParser" />

<webflow:flow-builder-services id="builder"
view-factory-creator="viewFactoryCreator" expression-parser="expressionParser" />
At next the actual spring web flows will get registered. All beans setup within this spring config will be available within the web flows.
<webflow:flow-registry id="flowRegistry"
    flow-builder-services="builder">
    <webflow:flow-location
        path="/WEB-INF/flows/federation-validate-request.xml" id="federation" />
    <webflow:flow-location
        path="/WEB-INF/flows/federation-validate-request.xml" id="federation/up" />
    <webflow:flow-location
        path="/WEB-INF/flows/federation-validate-request.xml" id="federation/krb" />
    <webflow:flow-location
        path="/WEB-INF/flows/federation-validate-request.xml" id="federation/clientcert" />
    <webflow:flow-location 
        path="/WEB-INF/flows/federation-signin-request.xml" id="signinRequest" />
    <webflow:flow-location 
        path="/WEB-INF/flows/federation-signin-response.xml" id="signinResponse" />
</webflow:flow-registry>
Adding security restrictions to the flow will allow spring security to be included in the flow for user authentication.
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping" p:flowRegistry-ref="flowRegistry"
    p:order="2">
</bean>

<webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry">
    <webflow:flow-execution-attributes>
        <webflow:always-redirect-on-pause value="false" />
    </webflow:flow-execution-attributes>

    <webflow:flow-execution-listeners>
        <webflow:listener ref="securityFlowExecutionListener" />
    </webflow:flow-execution-listeners>
</webflow:flow-executor>

<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter" p:flowExecutor-ref="flowExecutor" />

<bean id="securityFlowExecutionListener" class="org.springframework.webflow.security.SecurityFlowExecutionListener">
    <property name="accessDecisionManager" ref="accessDecisionManager" />
</bean>

<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
    <property name="decisionVoters">
        <list>
            <bean class="org.springframework.security.access.vote.RoleVoter">
                <property name="rolePrefix" value="ROLE_" />
            </bean>
            <bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
        </list>
    </property>
</bean>
The spring security configuration can be found within the WEB-INF/security-config.xml file.
Categories: Jan Bernhardt

Register trusted 3rd party IDP with SAML Web Browser SSO Profile

Jan Bernhardt - Fri, 12/18/2015 - 23:35
In this Post I'll explain how to configure Apache Fediz IDP so that it can be used with a trusted 3rd party IDP based on SAML Web Browser SSO Profile.

In my previous posts about Apache Fediz I focused on the WS-Federation passive protocol only since it is the successor standard for the SAML Web Browser SSO Profile. But in some cases you will have to establish a federated trust relation with an IDP how does not support the WS-Federation Standard yet, but only the older SAML Web Browser SSO Profile.


I'll explain how to register a SAML trusted IDP at the IDP as well as how to setup a demonstrator. Please also take a look at Colms post about this topic. PreconditionsI would assume that you have the fedizhelloworld demo application already running within your Tomcat container, as well as the Fediz IDP & STS in a second Tomcat  container. If you don't know how to do this, you will find a detailed instruction in my previous post about Fediz, as well as this post from Colm.
Install SAML IDPFediz IDP itself does not support the SAML Web Browser Profile as a primary IDP protocol. So you cannot use Fediz IDP so login based on SAML Web Browser Profile. But you can register a 3rd party IDP based on that profile when Fediz is acting as a Service Provider (client).

For purposes of integration testing however the Fediz Project provides a mockup implementation of a SAML IDP which we will use for demonstration purposes here. To build the war file you should do the following:

1. Clone the Fediz Sources on your computer with GIT
> git clone -v https://github.com/apache/cxf-fediz.git
2. Goto the systestfolder and build the systest with maven
> cd cxf-fediz/systests/federation/samlIdpWebapp/
> mvn -Pfastinstall
3. Copy war file to tomcat webapps folder
> cp target/*.war ${tomcat.fediz.idp.home}/webapps
4. Start Fediz-IDP and Fediz Demo app (if not already done yet)
> ${tomcat.fediz.idp.home}/bin/startup.sh
> ${tomcat.fediz.rp.home}/bin/startup.sh Register 3rd Party IDPNext you must register the SAML SSO IDP at your Fediz-IDP so that you can choose it as your home realm at the login process. This can be done via a REST API since version 1.2.0.

The REST Service API requires a Basic user authentication. Default username is admin and password is password.
1. Register a new 3rd Party IDP
POST https://localhost:9443/fediz-idp/services/rs/trusted-idps
<ns2:trustedIdp id="0" xmlns:ns2="http://org.apache.cxf.fediz/">
   <realm>urn:org:apache:cxf:fediz:idp:realm-C</realm>
   <url>https://localhost:9443/samlssoidp/samlsso</url>
   <name>Realm C</name>
   <description>SAML Web SSO</description>
   <protocol>urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser</protocol>
   <trustType>PEER_TRUST</trustType>
   <certificate>realmb.cert</certificate>
   <federationType>FEDERATE_IDENTITY</federationType>
   <cacheTokens>true</cacheTokens>
   <parameters>
      <entry>
         <key>support.deflate.encoding</key>
         <value>true</value>
      </entry>
   </parameters>
</ns2:trustedIdp>2. Assign this new 3rd Party IDP to your Realm-A Fediz IDP
POST https://localhost:9443/fediz-idp/services/rs/idps/urn%3Aorg%3Aapache%3Acxf%3Afediz%3Aidp%3Arealm-A/trusted-idps
<ns2:trustedIdp xmlns:ns2="http://org.apache.cxf.fediz/">
    <realm>urn:org:apache:cxf:fediz:idp:realm-C</realm>  
</ns2:trustedIdp> Test: Perform a federated Login
Make sure to delete any localhost cookies within your browser. Otherwise your preferred home realm could be stored within a cookie and therefore your would not see a home realm selection screen.
Now you can perform a login by invoking the following URL:
https://localhost:8443/fedizhelloworld/secure/fedservlet

You should see a home realm selection screen, with our new SAML SSO IDP which you should select. Next you should see a Basic user authentication window. Here you can login with ALICE and ECILA as your password.


After some redirect you should see the demo page with your federated user account from alice:

Review Redirects in DetailIf you use a monitoring tool like Fiddler, you will be able to analyze the redirects in greater detail.

After invoking the fedizhelloworld demo app, I'll get redirected to the Fediz IDP:
GET https://localhost:9443/fediz-idp/federation
     ?wa=wsignin1.0
    &wreply=https%3A%2F%2Flocalhost%3A8443%2Ffedizhelloworld%2Fsecure%2Ffedservlet
    &wtrealm=urn%3Aorg%3Aapache%3Acxf%3Afediz%3Afedizhelloworld
     &wct=2015-12-18T17%3A45%3A36.860Z
    &wctx=b9220a8a-5802-41a2-9128-a2ba649a72bc
The Fediz IDP will show you the home realm selection page and after selection will redirect you to the SAML SSO IDP
GET https://localhost:9443/samlssoidp/samlsso
    ?SAMLRequest=nVNdb9owFP0rkd9TEkihuQIkBpqG1G0pZHvYm3FuiiXHznydlu3Xz07TlofBpL3545xzj8%2B9nhNv1LiFVeeOeoc%2FOyQXrYjQOmn02mjqGrR7tE9S4Lfd%2FYIdnWsJRiNlBFdHQw7yLJuMaqzk71hWbVih5YHOoo2Xk7rfXGQGB0QmUIcliz4aK7D3tGA1V4Qs2m4WTMzq5DDNeFxPJkmc3aXTOM9nWZxM0yrnh6ziSeqRVHAi%2BYTvXKIOt5oc127Bxkl6G6fjOL0r0xlktzDJb2Z5%2BoNFhTXOCKM%2BSF1J%2FbhgndVgOEkCzRskcAL2q8%2F3ML5J4PACIvhUlkVcfN2XLPqOlvq3egCLTo3SBC8JX9dqh8JsOe%2Fh0Du25wrXBfhry9iyh9lH4C0XRwRxqqFvDviEwSJXTbyaj87LDEVb%2BOJ1t5vCKCl%2BRSulzPPaE5wP0tkO%2B7Y03F13Ek5kFdc9FNoQCDnUjkX7Iug%2FdFzJWqIdZP7hlI3e3A3jiVU%2FGH42HZ5ctDZNy62kkDqeuHBvGZ7D1sontMP6%2FxO9BBMggrY%2FDlP3bGwVpgiF91larqk11r3G%2FTdHy%2BHywvver8%2B%2F6PIP
     &RelayState=962c9908-489c-4ea2-b1a4-090e180c91f3
    &SigAlg=http%3A%2F%2Fwww.w3.org%2F2000%2F09%2Fxmldsig%23rsa-sha1
    &Signature=PyFe4kjQLWUoatdKZ0uZig27CSgrIZpmgU%2FiGL86KW8JIeVgAEIm9StYwdPUWiJO9KMM5wKmd9o6tWjFM7oIEtv8yIYo%2Fcr1nX7qDj5QRd2ni2akDH61OdV%2FvPECS0auRolW1vDwT6qwnqBFNC1KWSJXXpHu0bk7HXRkfnyA3p557ZECunsYsPhMp1JfaGQJUP8tw2LR0HNweoL7NA%2FbKU8lzwKrIcmJ7kFsYC2OrW3TucfqruQ0hrQYIvHFyISwqc7uWRgiGo8KhvTuw1pg2JvpZJZq%2F50OWHGWLWuE5QKT2C5yjJeb7xch4gPkg4PIBJCqrENZSE7OZWIcb%2Fydjw%3D%3D
You can use for example Notepad++ to decode SAML-P Requests & Responses.


After decoding the SAMLRequest you will see the following SAML AuthnRequest:
<saml2p:AuthnRequest AssertionConsumerServiceURL="https://localhost:9443/fediz-idp/federation" Destination="https://localhost:9443/samlssoidp/samlsso" ForceAuthn="false" ID="c7f0b64a-f330-4816-9974-061d9ab4da01" IsPassive="false" IssueInstant="2015-12-18T17:45:39.791Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0" xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
    <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">urn:org:apache:cxf:fediz:idp:realm-A</saml2:Issuer>
    <saml2p:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" SPNameQualifier="urn:org:apache:cxf:fediz:idp:realm-A"/>
    <saml2p:RequestedAuthnContext Comparison="exact">
        <saml2:AuthnContextClassRef xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
    </saml2p:RequestedAuthnContext>
</saml2p:AuthnRequest>

After login at the SAML IDP the user will be redirected back to Fediz-IDP:
GET https://localhost:9443/fediz-idp/federation
    ?SAMLResponse=rVdZk6JMFn33V1TYj4YFCYhAdFUEiwsKgiIqvEywJIuySYLbrx%2B0ytqmqqfniwkfJC93OffcJDn8Rk6aEAW3gKjIMwQfZOmpzUBI9hkHdH2A97sUSwZdF7heF2dpD3dZlqEDov0gZ/egZf7U9voB7tKU0w1IEu9SDKC7LNunujgNfNZxKd/BQRODUA3lDFVOVj21CRz0uoDoAmYJ%2BhzV40j2kSFxu/2wgiWK86xxecTbD6c0yRD3gvSpXZcZlzsoRlzmpBBxlccZvKpwjStXlHmVe3nSfv59c%2BduBcuPGf6cwEEIllVTuv0cVVWBOAxLcs9JohxVHEtRJHZNglAe%2B8X98jf2sdZr5YIzKqeq0ZelmPvwYeUkNfwzDnTz5oza8yBCbez5tciXtBx/x3sb3L9YQDE0QzBdzyV7XQr0mC7ju0yXpkjAeC5OeX38/zCFv%2BXwNeaE4qf2lc6GzePx%2BHgkH/MyxAgcB9hGVQwvgqnTjW%2BAPNhEoZirzkVD0Zcml43xy2j/%2BZj8ht44zBo2S/gK1Ec/4MQxnMUaHx/F4a/2Wyz05SzIb0vRyfIsbiDEF%2BcKVYVVlPsPfBLmZVxF6Y8EAPyauAtPXtcDVPbrOuuP0P4y0SeEJXK6KHLAa64FDGAJG2ofzIX81P71d9vkFrosnQwFeZmiz8v/DQ/MDjDJC%2Bh30b2tV2h/n/B7prD/xCjFIUTVP6HtA2UvSW4P6jM7r1aVQScStV%2BeeJ3igaqVnjMrhOPTDcBH55vhjfCX5Zet8jbal4ghSA3AWtlZP1qzmglsIDn9%2BcLaXlYXRpdwYOIRT1L0ft9bDFczYjY3Ombp7Ox0Wep1NauKmtFxeROWKbVH/WGhRoJTVbxrni9o6MtLeWPLOl8SypJQsWQqOEzMFpI2cQNWm4S14eY4bxm8MdY3YDZVjkSA2QsKGEHQIS8nuTfWjoW58cb%2Bsq8IU1zbTGNKK5SL2wlPoifyNCmpaDE9r3GgT3HEb6roMoQBEpyOp5xlpIdqudrpQ8OzmfzSmXWGmTvU0m2fKdw5sdlsjsuB5UwjhtqPowu6jGpS1EUlV7cFpdRAHa51TzpT%2B10RwJnhgXHfww5jw%2BxjEFvXwWgsshB6grGa0HYmx8I0M87Hp6c36j9wfaV/Cs9vo9j0cFZyKudtIV4PmqB5jiv4rMqyeFyKIu%2BkIX%2BUBT6UB75DXIoLPxPC3T7axSP2iAv8HA15iV%2Boc%2BYozS1pNZ9Lg6NtLMyhujTl4zjyZq3m6jjbDo7NPz6TVGLdGNVtY5MG1Jtt%2B3OSMBzEKo%2BPRGM/ahmyS0rzQVPZ5HlKFqQjf3WY8nmDci4OvZ6A4Wd3aNmZsc1YgyZrfc/Kwnq%2BQgQ8ODZl4sdDAOnDKmnttZrXGDraTjB6EBpurY0TVY9lyyUTH1IpXO7pQWdTrPMTrgwY5WzM/RN2AAYDVsRkqoA862/iZiO4lNnCiRTfb2YwpvsLYIr83K7cqDgsoTdJ/SznHbfQ5MnO2CfzTKsYoqT8zWlgDXumXMb2KJ5bKr0zB41oOBQtfQgunfLEwHJLx8yomkNdW8fbKjMTex%2BOjsrgsMNnRH%2B0kEOgjTvJaFQQxWiHy%2BxYXbDaebnDFrvhYQcF1OKTvbIXk%2B15m4tbf4E0ewQ1tEaCR9jZqgOgop2yogeZ3KFjK5/V0t6ubEZNwSEZM5M1PQY6H6oCz4%2B2LXnJB6qAj3hg%2BlI4XwvCgoDYycysYguUgFY3qrbeL0pfWW2I7Tfbhdcabga8crLZFnAmEhwO1BAPPEhHghhtzqYHtIk3LE4nwk4vENcu61PEW%2BuQzDdEXzVn4aK389VcnwSBSEiRiUiTXHeElrWY4ltxX9S4ilnUIDxR8f4cjj3eWS54PcVGlb1DnaQDlcW4Y2BbfRWRl2m8xjEz2M2ts9Xb7e04ETJpo7fsodpkMDNPZyGrsDGRns364lUFu8lZdbS2lr3zcBojF2SH2TQkC2sydegqCwKgqGR4glvRSz1hPj0nZUtvzs2%2BnljRmXV2m9U4nUvlBYwR5E8l5lPWAXWsMhqXqR0N93W191V5YExGs%2Bb0Ho%2BtxTDVdBe/CGqNU1QLapHX0cwTpYzrCyywbFqlUj4bj0YnZ5pY5IB/PQC%2BPtRvxpfHHvt4IHw6MO4yw6jdLfSq%2B3LWyB1Zehg2rxun%2BlkHgUdws8R%2BN7i5cnWGCug1MKDffuYVWRzcBclLyi/1xDwL4mvgVdu9vMz%2BrLq8lHOhU8Ky/YdM16YfeN8vG1H51AZE/xFvfuCfiflZXmmZVvJBBcuvMrKHv8vIRdN2EcOr1vxBrAXQjy/dq1ZrrmB5g/queb9r5Ou9e8%2BNjx9fHdAVngAb8uFPEhfYf9dD4/cmt2s/vr7XG7KqMvZekHy%2B9XwbUhlyTuE0wpbzTgF3649r%2BuNK6CRpl7%2Bjfwv6avhUAPva23vNKsquHwQwbeh9uC3/u67/FN0kreCp%2Bs4mJo2Sb6TM8x/Fvsd5V7/GrDd/x7z033v5Jtd3Nz8b3/p5N9/1//tX0H23Pv8b    
    &RelayState=962c9908-489c-4ea2-b1a4-090e180c91f3Usually you would receive a POST message from the SAML IDP instead of a GET redirect, as done here by the mockup IDP.
A decoded SAMLResponse will look like this:
<saml2p:Response ID="1772f107-14b9-4d27-9d21-f3a1cf655648" InResponseTo="41e5c1dc-7cfe-446e-b475-3fb7a40b5432" IssueInstant="2015-12-18T14:16:24.456Z" Version="2.0" xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
    <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">https://localhost:9443/samlssoidp/samlsso</saml2:Issuer>
    <saml2p:Status>
        <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
    </saml2p:Status>
    <saml2:Assertion ID="_42311918-c677-4773-86b7-e5b42340354d" IssueInstant="2015-12-18T14:16:24.456Z" Version="2.0" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="saml2:AssertionType">
        <saml2:Issuer>https://localhost:9443/samlssoidp/samlsso</saml2:Issuer>
        <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
            <ds:SignedInfo>
                <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
                <ds:Reference URI="#_42311918-c677-4773-86b7-e5b42340354d">
                    <ds:Transforms>
                        <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
                        <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                    </ds:Transforms>
                    <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                    <ds:DigestValue>IvKTW0enrkTeXynCf9Aj0053fXM=</ds:DigestValue>
                </ds:Reference>
            </ds:SignedInfo>
            <ds:SignatureValue>GcHGaMUt6zM+tdKty0yXWOniNXh5V8JfYrCkjerx1LPI7K2w4oWCTfGtZ4TCnAhoKZQsyA3+VDpFg25HZIMjJVznazHPQ1idjvy5zlKdmG+jaHf+JWrKMuCb3w3UPJwWFEod49BnLGgLkBORr4rgWi0c4eloSK8NCnBHOXwhJHxkw5nUe+FIiuLpuIxbWnNddsWr7091ImuawDxfYfPDJuxaXX19EP2nx2zc7oQrmbqZAIIftao87OeAr2hfg4BDpAO7kFQC+Iw2B4pkmLUnJNyzspfU96bN9HaNvhBZSWD1HEdTzkHaNr9r1h9SSksBZLdmT8+p0+QidzNXN5H/sw==</ds:SignatureValue>
            <ds:KeyInfo>
                <ds:X509Data>
                    <ds:X509Certificate>MIICwTCCAamgAwIBAgIEda2zpzANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDEwZSRUFMTUIwHhcN
MTUwNjEwMTU0NDM2WhcNMjUwNDE4MTU0NDM2WjARMQ8wDQYDVQQDEwZSRUFMTUIwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCFc5B/0ybFYZnSjn9S63uPq9IBWQVs2evaZ4U0wvfe6vVl
qOuAO86hjJ/6EgSbuOHlMPiIYb3lde4meTq6E+XpWox0LE8LySQdx/v1S81V2JKL1on7XiCcCb4U
02m0qXNei67R1UCAQZtbhpvTecJmdnoAabpOIJkSqlQnOt82r4dXxEYF5UIriZGiQYM6kUE61dvp
PF1z+rx8erj6i8GtQePOWijtnUlZqgGwLEvk0N27GRIg1OH+lGGp2pGk0I9HMR9OyTk/RkFvkeBs
AlqLqCljyjoCjdRsOZGeOsWsBc2ZnV+1eLOxnp5e8oa6iYoNuDqZtZ8Mm1vlH8JW6H1PAgMBAAGj
ITAfMB0GA1UdDgQWBBR2e/xUnYpj1Lf6MXMOWqRrdLVX2jANBgkqhkiG9w0BAQsFAAOCAQEALxZ9
1aJDeFEMg0fce6hBChXyUc1OJcFpxx2Zmze0OzWxhAYWg3oX27MUNgR5kdMoPJffC2DhUs3U3W+B
YRK0jCqpu0M/Y4Egx4iqygHcAaTRAPm/GtZks+l+eLRH+S/jPVh3zKiW0/UfkQYyY5kqZilBnDXP
ZFMEgxUncP9e9L9i2myUuzctp9Xo9MGWYT5yFKisb1nvNKg3pYJKa6tnff1LM3gxejCcmcBQKylr
PA1M7PlYhy9akXVHmQDrz1HseAxr/d4Yvs+YrhHrmZhFqutqdMIESJGNithHHYRFmOPb0zBMu044
eOhc+OUx4LHuzep/nKtmDoNHGGxaKlY3EA==</ds:X509Certificate>
                </ds:X509Data>
            </ds:KeyInfo>
        </ds:Signature>
        <saml2:Subject>
            <saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">ALICE</saml2:NameID>
            <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <saml2:SubjectConfirmationData Address="127.0.0.1" InResponseTo="41e5c1dc-7cfe-446e-b475-3fb7a40b5432" NotOnOrAfter="2015-12-18T14:21:24.456Z" Recipient="https://localhost:9443/fediz-idp/federation"/>
            </saml2:SubjectConfirmation>
        </saml2:Subject>
        <saml2:Conditions NotBefore="2015-12-18T14:16:24.456Z" NotOnOrAfter="2015-12-18T14:21:24.456Z">
            <saml2:AudienceRestriction>
                <saml2:Audience>urn:org:apache:cxf:fediz:idp:realm-A</saml2:Audience>
            </saml2:AudienceRestriction>
        </saml2:Conditions>
        <saml2:AuthnStatement AuthnInstant="2015-12-18T14:16:24.456Z">
            <saml2:AuthnContext>
                <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml2:AuthnContextClassRef>
            </saml2:AuthnContext>
        </saml2:AuthnStatement>
    </saml2:Assertion>
</saml2p:Response>


Fediz-IDP is configured to do a identity mapping and will return a SAML token back to the demo application according to WS-Federation.
POST https://localhost:8443/fedizhelloworld/secure/fedservlet

wa=wsignin1.0
&wresult=%3CRequestSecurityTokenResponseCollection+xmlns%3D%22http%3A%2F%2Fdocs.oasis-open.org%2Fws-sx%2Fws-trust%2F200512%22+xmlns%3Ans2%3D%22http%3A%2F%2Fwww.w3.org%2F2005%2F08%2Faddressing%22+xmlns%3Ans3%3D%22http%3A%2F%2Fdocs.oasis-open.org%2Fwss%2F2004%2F01%2Foasis-200401-wss-wssecurity-utility-1.0.xsd%22+xmlns%3Ans4%3D%22http%3A%2F%2Fdocs.oasis-open.org%2Fwss%2F2004%2F01%2Foasis-200401-wss-wssecurity-secext-1.0.xsd%22+xmlns%3Ans5%3D%22http%3A%2F%2Fdocs.oasis-open.org%2Fws-sx%2Fws-trust%2F200802%22%3E%3CRequestSecurityTokenResponse%3E%3CTokenType%3Ehttp%3A%2F%2Fdocs.oasis-open.org%2Fwss%2Foasis-wss-saml-token-profile-1.1%23SAMLV2.0%3C%2FTokenType%3E%3CRequestedSecurityToken%3E%3Csaml2%3AAssertion+xmlns%3Asaml2%3D%22urn%3Aoasis%3Anames%3Atc%3ASAML%3A2.0%3Aassertion%22+xmlns%3Axsd%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema%22+xmlns%3Axsi%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema-instance%22+ID%3D%22_d11b7fa4-3dc2-4b81-a29e-c80cc6e20436%22+IssueInstant%3D%222015-12-18T17%3A45%3A39.933Z%22+Version%3D%222.0%22+xsi%3Atype%3D%22saml2%3AAssertionType%22%3E%3Csaml2%3AIssuer%3ESTS+Realm+A%3C%2Fsaml2%3AIssuer%3E%3Cds%3ASignature+xmlns%3Ads%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2F09%2Fxmldsig%23%22%3E%3Cds%3ASignedInfo%3E%3Cds%3ACanonicalizationMethod+Algorithm%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2F10%2Fxml-exc-c14n%23%22%2F%3E%3Cds%3ASignatureMethod+Algorithm%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2F04%2Fxmldsig-more%23rsa-sha256%22%2F%3E%3Cds%3AReference+URI%3D%22%23_d11b7fa4-3dc2-4b81-a29e-c80cc6e20436%22%3E%3Cds%3ATransforms%3E%3Cds%3ATransform+Algorithm%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2F09%2Fxmldsig%23enveloped-signature%22%2F%3E%3Cds%3ATransform+Algorithm%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2F10%2Fxml-exc-c14n%23%22%3E%3Cec%3AInclusiveNamespaces+xmlns%3Aec%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2F10%2Fxml-exc-c14n%23%22+PrefixList%3D%22xsd%22%2F%3E%3C%2Fds%3ATransform%3E%3C%2Fds%3ATransforms%3E%3Cds%3ADigestMethod+Algorithm%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2F04%2Fxmlenc%23sha256%22%2F%3E%3Cds%3ADigestValue%3EOB6hSosPWjhA5dxCE%2BF3eFAC4dRu%2FZxFT9XO%2B9tXBAI%3D%3C%2Fds%3ADigestValue%3E%3C%2Fds%3AReference%3E%3C%2Fds%3ASignedInfo%3E%3Cds%3ASignatureValue%3EOAZHDiqlANZXtK0UPfrusUTAf1E9hrPHjUw9kB0sP24RMtxjIfcJ0UFTIb1gBHMqGz%2BbxPJozH7c6O%2F%2F2OYa5V3eRDadQOqnxKvReDh8YjHqs641uhdNqlJl9SogWsm7MPmznmwB5jRLqCaQpTQDfFnjwHXPgxwcASh1i3anfYSpJebnq4ipC3%2Flyuy99xXb1tQoai6hgdRiPs5ragYUPLqE9bIrULj%2FOTbuXY4ikKcNBHltKzAhPJtvaVDzgUkAKRYNBk64te1vRTCYYdMWXjMjA%2FC2obHhIB4zA5eMjxoMPmZHe7ZxVVRiB938S%2FJW%2B4ysJvoVdFX2FTmqRmIKhA%3D%3D%3C%2Fds%3ASignatureValue%3E%3Cds%3AKeyInfo%3E%3Cds%3AX509Data%3E%3Cds%3AX509Certificate%3EMIICwTCCAamgAwIBAgIEINqJ9TANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDEwZSRUFMTUEwHhcN%0D%0AMTUwNjEwMTU0NDE3WhcNMjUwNDE4MTU0NDE3WjARMQ8wDQYDVQQDEwZSRUFMTUEwggEiMA0GCSqG%0D%0ASIb3DQEBAQUAA4IBDwAwggEKAoIBAQCJDSXn2lDR%2BJM%2BAsJarFG3%2FXGH7K%2B9AfAbQIz2IgB9MCpO%0D%0AKVWTUPCvuo1I%2BFp5nEGreuHYLEwgIiam3o%2BC9tvpLgtDDaDkmXjDzkWpk8z6%2Bim72HZ%2FODF93Rqw%0D%0AjIiY5ZCzgDumFyPzdKiGwChThamidy%2Brd6oheSoi6qRVSMMcnwiEUmvkfFvV3izXRqeT5nGQwsin%0D%0Ay9mCEiGx8jkfxP%2B%2BH0RQjVjhOwzfQ7epsR7dTQNf2ZhkBR3o6wKV9QnF2IBWHZpA9EK58rWU9H6j%0D%0AG7b631rYvwsbOUF9HcZ8DI2BFh%2B4p18jDN%2FfnjNGSLr9rYOExpsIiF1cHBK7Tr7WwCmDAgMBAAGj%0D%0AITAfMB0GA1UdDgQWBBRHy0qYoLm9jx%2F1L6r61NznHKun2jANBgkqhkiG9w0BAQsFAAOCAQEAR9rU%0D%0A5Sp1FsOErdvKNFqeaKl0oq6Fuz7BWcGm2kK6%2B1ZbWE8IOv6Vh%2BBlLuOe5hF7aLUbm8UIjhKsmg0M%0D%0AEy5MBwkBZktT1qhQteMuiKgYR7CxayCxO0f125RYvvwntJa5rI7bUrzOqX29VQD1qQ%2FTb%2B08fULT%0D%0AL7oURP%2Bg88Ff99dn3IpO4VZxZdsbl4%2BKZRtqQvPAdXNYjOajJtPzS489%2B%2FDtfWJ6wPm%2F7YZ4did4%0D%0A1fYcrdwyEZ15L0%2F5i931z7sztNickm5WhO40qEVDKN6KrlV2Eyea0%2B933v2Pwe4resTlko9G2T5h%0D%0AdEaSbvht2Q%2FJOMMmT91daeto2oS8HTKhTA%3D%3D%3C%2Fds%3AX509Certificate%3E%3C%2Fds%3AX509Data%3E%3C%2Fds%3AKeyInfo%3E%3C%2Fds%3ASignature%3E%3Csaml2%3ASubject%3E%3Csaml2%3ANameID+Format%3D%22urn%3Aoasis%3Anames%3Atc%3ASAML%3A1.1%3Anameid-format%3Aunspecified%22+NameQualifier%3D%22http%3A%2F%2Fcxf.apache.org%2Fsts%22%3Ealice%3C%2Fsaml2%3ANameID%3E%3Csaml2%3ASubjectConfirmation+Method%3D%22urn%3Aoasis%3Anames%3Atc%3ASAML%3A2.0%3Acm%3Abearer%22%2F%3E%3C%2Fsaml2%3ASubject%3E%3Csaml2%3AConditions+NotBefore%3D%222015-12-18T17%3A45%3A39.890Z%22+NotOnOrAfter%3D%222015-12-18T18%3A45%3A39.890Z%22%3E%3Csaml2%3AAudienceRestriction%3E%3Csaml2%3AAudience%3Eurn%3Aorg%3Aapache%3Acxf%3Afediz%3Afedizhelloworld%3C%2Fsaml2%3AAudience%3E%3C%2Fsaml2%3AAudienceRestriction%3E%3C%2Fsaml2%3AConditions%3E%3Csaml2%3AAttributeStatement%3E%3Csaml2%3AAttribute+Name%3D%22http%3A%2F%2Fschemas.xmlsoap.org%2Fws%2F2005%2F05%2Fidentity%2Fclaims%2Frole%22+NameFormat%3D%22urn%3Aoasis%3Anames%3Atc%3ASAML%3A2.0%3Aattrname-format%3Aunspecified%22%3E%3Csaml2%3AAttributeValue+xsi%3Atype%3D%22xsd%3Astring%22%3EUser%3C%2Fsaml2%3AAttributeValue%3E%3C%2Fsaml2%3AAttribute%3E%3Csaml2%3AAttribute+Name%3D%22http%3A%2F%2Fschemas.xmlsoap.org%2Fws%2F2005%2F05%2Fidentity%2Fclaims%2Fgivenname%22+NameFormat%3D%22urn%3Aoasis%3Anames%3Atc%3ASAML%3A2.0%3Aattrname-format%3Aunspecified%22%3E%3Csaml2%3AAttributeValue+xsi%3Atype%3D%22xsd%3Astring%22%3EAlice%3C%2Fsaml2%3AAttributeValue%3E%3C%2Fsaml2%3AAttribute%3E%3Csaml2%3AAttribute+Name%3D%22http%3A%2F%2Fschemas.xmlsoap.org%2Fws%2F2005%2F05%2Fidentity%2Fclaims%2Fsurname%22+NameFormat%3D%22urn%3Aoasis%3Anames%3Atc%3ASAML%3A2.0%3Aattrname-format%3Aunspecified%22%3E%3Csaml2%3AAttributeValue+xsi%3Atype%3D%22xsd%3Astring%22%3ESmith%3C%2Fsaml2%3AAttributeValue%3E%3C%2Fsaml2%3AAttribute%3E%3Csaml2%3AAttribute+Name%3D%22http%3A%2F%2Fschemas.xmlsoap.org%2Fws%2F2005%2F05%2Fidentity%2Fclaims%2Femailaddress%22+NameFormat%3D%22urn%3Aoasis%3Anames%3Atc%3ASAML%3A2.0%3Aattrname-format%3Aunspecified%22%3E%3Csaml2%3AAttributeValue+xsi%3Atype%3D%22xsd%3Astring%22%3Ealice%40realma.org%3C%2Fsaml2%3AAttributeValue%3E%3C%2Fsaml2%3AAttribute%3E%3C%2Fsaml2%3AAttributeStatement%3E%3C%2Fsaml2%3AAssertion%3E%3C%2FRequestedSecurityToken%3E%3CRequestedAttachedReference%3E%3Cns4%3ASecurityTokenReference+xmlns%3Awsse11%3D%22http%3A%2F%2Fdocs.oasis-open.org%2Fwss%2Foasis-wss-wssecurity-secext-1.1.xsd%22+wsse11%3ATokenType%3D%22http%3A%2F%2Fdocs.oasis-open.org%2Fwss%2Foasis-wss-saml-token-profile-1.1%23SAMLV2.0%22%3E%3Cns4%3AKeyIdentifier+ValueType%3D%22http%3A%2F%2Fdocs.oasis-open.org%2Fwss%2Foasis-wss-saml-token-profile-1.1%23SAMLID%22%3E_d11b7fa4-3dc2-4b81-a29e-c80cc6e20436%3C%2Fns4%3AKeyIdentifier%3E%3C%2Fns4%3ASecurityTokenReference%3E%3C%2FRequestedAttachedReference%3E%3CRequestedUnattachedReference%3E%3Cns4%3ASecurityTokenReference+xmlns%3Awsse11%3D%22http%3A%2F%2Fdocs.oasis-open.org%2Fwss%2Foasis-wss-wssecurity-secext-1.1.xsd%22+wsse11%3ATokenType%3D%22http%3A%2F%2Fdocs.oasis-open.org%2Fwss%2Foasis-wss-saml-token-profile-1.1%23SAMLV2.0%22%3E%3Cns4%3AKeyIdentifier+ValueType%3D%22http%3A%2F%2Fdocs.oasis-open.org%2Fwss%2Foasis-wss-saml-token-profile-1.1%23SAMLID%22%3E_d11b7fa4-3dc2-4b81-a29e-c80cc6e20436%3C%2Fns4%3AKeyIdentifier%3E%3C%2Fns4%3ASecurityTokenReference%3E%3C%2FRequestedUnattachedReference%3E%3Cwsp%3AAppliesTo+xmlns%3Awsp%3D%22http%3A%2F%2Fwww.w3.org%2Fns%2Fws-policy%22+xmlns%3Awst%3D%22http%3A%2F%2Fdocs.oasis-open.org%2Fws-sx%2Fws-trust%2F200512%22%3E%3Cwsa%3AEndpointReference+xmlns%3Awsa%3D%22http%3A%2F%2Fwww.w3.org%2F2005%2F08%2Faddressing%22%3E%3Cwsa%3AAddress%3Eurn%3Aorg%3Aapache%3Acxf%3Afediz%3Afedizhelloworld%3C%2Fwsa%3AAddress%3E%3C%2Fwsa%3AEndpointReference%3E%3C%2Fwsp%3AAppliesTo%3E%3CLifetime%3E%3Cns3%3ACreated%3E2015-12-18T17%3A45%3A39.890Z%3C%2Fns3%3ACreated%3E%3Cns3%3AExpires%3E2015-12-18T18%3A45%3A39.890Z%3C%2Fns3%3AExpires%3E%3C%2FLifetime%3E%3C%2FRequestSecurityTokenResponse%3E%3C%2FRequestSecurityTokenResponseCollection%3E
&wctx=b9220a8a-5802-41a2-9128-a2ba649a72bc
&wtrealm=urn%3Aorg%3Aapache%3Acxf%3Afediz%3Afedizhelloworld
The final wresult which will be sent to the demo app looks like this:
<RequestSecurityTokenResponseCollection xmlns="http://docs.oasis-open.org/ws-sx/ws-trust/200512" xmlns:ns2="http://www.w3.org/2005/08/addressing" xmlns:ns3="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:ns4="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:ns5="http://docs.oasis-open.org/ws-sx/ws-trust/200802">
<RequestSecurityTokenResponse>
<TokenType>http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0</TokenType>
<RequestedSecurityToken>
<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ID="_d11b7fa4-3dc2-4b81-a29e-c80cc6e20436" IssueInstant="2015-12-18T17:45:39.933Z" Version="2.0" xsi:type="saml2:AssertionType">
<saml2:Issuer>STS Realm A</saml2:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="#_d11b7fa4-3dc2-4b81-a29e-c80cc6e20436">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xsd"/>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>OB6hSosPWjhA5dxCE+F3eFAC4dRu/ZxFT9XO+9tXBAI=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>OAZHDiqlANZXtK0UPfrusUTAf1E9hrPHjUw9kB0sP24RMtxjIfcJ0UFTIb1gBHMqGz+bxPJozH7c6O//2OYa5V3eRDadQOqnxKvReDh8YjHqs641uhdNqlJl9SogWsm7MPmznmwB5jRLqCaQpTQDfFnjwHXPgxwcASh1i3anfYSpJebnq4ipC3/lyuy99xXb1tQoai6hgdRiPs5ragYUPLqE9bIrULj/OTbuXY4ikKcNBHltKzAhPJtvaVDzgUkAKRYNBk64te1vRTCYYdMWXjMjA/C2obHhIB4zA5eMjxoMPmZHe7ZxVVRiB938S/JW+4ysJvoVdFX2FTmqRmIKhA==</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIICwTCCAamgAwIBAgIEINqJ9TANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDEwZSRUFMTUEwHhcN
MTUwNjEwMTU0NDE3WhcNMjUwNDE4MTU0NDE3WjARMQ8wDQYDVQQDEwZSRUFMTUEwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCJDSXn2lDR+JM+AsJarFG3/XGH7K+9AfAbQIz2IgB9MCpO
KVWTUPCvuo1I+Fp5nEGreuHYLEwgIiam3o+C9tvpLgtDDaDkmXjDzkWpk8z6+im72HZ/ODF93Rqw
jIiY5ZCzgDumFyPzdKiGwChThamidy+rd6oheSoi6qRVSMMcnwiEUmvkfFvV3izXRqeT5nGQwsin
y9mCEiGx8jkfxP++H0RQjVjhOwzfQ7epsR7dTQNf2ZhkBR3o6wKV9QnF2IBWHZpA9EK58rWU9H6j
G7b631rYvwsbOUF9HcZ8DI2BFh+4p18jDN/fnjNGSLr9rYOExpsIiF1cHBK7Tr7WwCmDAgMBAAGj
ITAfMB0GA1UdDgQWBBRHy0qYoLm9jx/1L6r61NznHKun2jANBgkqhkiG9w0BAQsFAAOCAQEAR9rU
5Sp1FsOErdvKNFqeaKl0oq6Fuz7BWcGm2kK6+1ZbWE8IOv6Vh+BlLuOe5hF7aLUbm8UIjhKsmg0M
Ey5MBwkBZktT1qhQteMuiKgYR7CxayCxO0f125RYvvwntJa5rI7bUrzOqX29VQD1qQ/Tb+08fULT
L7oURP+g88Ff99dn3IpO4VZxZdsbl4+KZRtqQvPAdXNYjOajJtPzS489+/DtfWJ6wPm/7YZ4did4
1fYcrdwyEZ15L0/5i931z7sztNickm5WhO40qEVDKN6KrlV2Eyea0+933v2Pwe4resTlko9G2T5h
dEaSbvht2Q/JOMMmT91daeto2oS8HTKhTA==</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<saml2:Subject>
<saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified" NameQualifier="http://cxf.apache.org/sts">alice</saml2:NameID>
<saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"/>
</saml2:Subject>
<saml2:Conditions NotBefore="2015-12-18T17:45:39.890Z" NotOnOrAfter="2015-12-18T18:45:39.890Z">
<saml2:AudienceRestriction>
<saml2:Audience>urn:org:apache:cxf:fediz:fedizhelloworld</saml2:Audience>
</saml2:AudienceRestriction>
</saml2:Conditions>
<saml2:AttributeStatement>
<saml2:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
<saml2:AttributeValue xsi:type="xsd:string">User</saml2:AttributeValue>
</saml2:Attribute>
<saml2:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
<saml2:AttributeValue xsi:type="xsd:string">Alice</saml2:AttributeValue>
</saml2:Attribute>
<saml2:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
<saml2:AttributeValue xsi:type="xsd:string">Smith</saml2:AttributeValue>
</saml2:Attribute>
<saml2:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
<saml2:AttributeValue xsi:type="xsd:string">alice@realma.org</saml2:AttributeValue>
</saml2:Attribute>
</saml2:AttributeStatement>
</saml2:Assertion>
</RequestedSecurityToken>
<RequestedAttachedReference>
<ns4:SecurityTokenReference xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" wsse11:TokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0">
<ns4:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLID">_d11b7fa4-3dc2-4b81-a29e-c80cc6e20436</ns4:KeyIdentifier>
</ns4:SecurityTokenReference>
</RequestedAttachedReference>
<RequestedUnattachedReference>
<ns4:SecurityTokenReference xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" wsse11:TokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0">
<ns4:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLID">_d11b7fa4-3dc2-4b81-a29e-c80cc6e20436</ns4:KeyIdentifier>
</ns4:SecurityTokenReference>
</RequestedUnattachedReference>
<wsp:AppliesTo xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wst="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
<wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>urn:org:apache:cxf:fediz:fedizhelloworld</wsa:Address>
</wsa:EndpointReference>
</wsp:AppliesTo>
<Lifetime>
<ns3:Created>2015-12-18T17:45:39.890Z</ns3:Created>
<ns3:Expires>2015-12-18T18:45:39.890Z</ns3:Expires>
</Lifetime>
</RequestSecurityTokenResponse>
</RequestSecurityTokenResponseCollection>

Categories: Jan Bernhardt

Liferay Portal Integration with Fediz OpenID Connect

Jan Bernhardt - Thu, 12/17/2015 - 11:24
I was given the task to provide a security solution to enable SSO in a Liferay portal based on OpenID Connect with the Apache Fediz OIDC Service. In this post I'll explain how to get this done.

You will need Apache Fediz version 1.3.0 or higher, if you want to setup this use case by yourselfInstall Liferay Portal with Fediz PluginFirst download and extract Liferay bundled with Tomcat. (I used liferay-portal-6.2-ce-ga5)

Enable HTTPs port in liferay-portal-6.2-ce-ga5/tomcat-7.0.62/conf/server.xml
<Server port="8005" shutdown="SHUTDOWN">

     . . .

    <Service name="Catalina">

         . . .

        <Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
             maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
             keystoreFile="idp-ssl-key.jks"
             keystorePass="tompass"
             clientAuth="false"
             sslProtocol="TLS" />

    </Service>
</Server>
I reused the idp-ssl-key.jks file from the IDP Tomcat to keep things simple. Of course you can also use a different keystore. Your keystore should be stored in your tomcat root folder liferay-portal-6.2-ce-ga5/tomcat-7.0.62/.

Now you can start Liferay for a first setup. Simply execute liferay-portal-6.2-ce-ga5/tomcat-7.0.62/bin/startup.sh

After Tomcat startup is complete you can invoke the server page at https://localhost:8443/.

I continued with the default values (except for the Email address) and simply clicked "Finish Configuration". After that you have to wait until Liferay installation is complete. Next you will see the license confirmation page, which you need to confirm. After that you can set your password reminder as well as the administration password.

The OpenID Connect Extension which we will install in the following section requires a user group UnityUser which will be applied for all new users when then login the very first time to the portal. Therefore we must create this user group first under control panel -> Users -> User Groups -> Add


Your Liferay Portal is now up and running so lets continue next on enabling OpenID Connect for your portal.
Register Liferay Portal at OIDC ProviderAfter starting your OIDC Service, you can register the Liferay Portal under the following URL: https://localhost:9443/fediz-oidc/clients/register.

You will need the client Identifier as well as the Client Secret in the following section.
Install OpenIdConnect Extension for LiferayYou will need the OpenIdConnectLiferay extension, which you can clone from Github. Further information on installing this extension can be found at the authors webpage.

You'll need to update the configuration within it.infn.ct.security.liferay.openidconnect.utils.Authenticator

public Authenticator(State state) {
    authC = new ClientSecretBasic(new ClientID("hLiSIY6b1X_0Jg"), new Secret("llPySiI1aEwyIgsnyBu6aA"));
    this.state = state;
    try {
        callback = new URI("https://localhost:8443/c/portal/login");
oauthS = new URI("https://localhost:9443/fediz-oidc/idp/authorize");
        tokenS = new URI("https://localhost:9443/fediz-oidc/oauth2/token");
        userS = new URI("https://localhost:9443/fediz-oidc/users/userinfo");
        tokenCertSign = new URI("https://localhost:9443/fediz-oidc/jwk/keys");
        issuer = "accounts.fediz.com";
        aud = "hLiSIY6b1X_0Jg";
    } catch (URISyntaxException ex) {
        _log.error(ex);
    }
}

Now you can build and deploy this extension.
$ mvn clean install
You will find a jar file with all extensions at OpenIdConnectLiferay/target/OpenIdConnectLiferay-0.1-jar-with-dependencies.jar. You need to copy this jar file to liferay-portal-6.2-ce-ga5/tomcat-7.0.62/lib/ext/.

Next you need to create (or modify if it already exists) the following file liferay-portal-6.2-ce-ga5/tomcat-7.0.62/webapps/ROOT/WEB-INF/classes/portal-ext.properties to activate the OpenID Connect Login handler:
auto.login.hooks=\
it.infn.ct.security.liferay.openidconnect.OpenIdConnectAutoLogin,\
com.liferay.portal.security.auth.CASAutoLogin,\
com.liferay.portal.security.auth.FacebookAutoLogin,\
com.liferay.portal.security.auth.NtlmAutoLogin,\
com.liferay.portal.security.auth.OpenIdAutoLogin,\
com.liferay.portal.security.auth.OpenSSOAutoLogin,\
com.liferay.portal.security.auth.RememberMeAutoLogin,\
com.liferay.portal.security.auth.SiteMinderAutoLogin

Now you should restart your tomcat and after that you can invoke the following login URL: https://localhost:8443/c/portal/login?openIdLogin=true. This time you should get redirected to Fediz-IDP for user authentication (login). After successful login you should be able to see your portal again with an active user.

For debugging purposes is can also be helpful to increase the log level by adding the following line at liferay-portal-6.2-ce-ga5/tomcat-7.0.62/conf/logging.properties
it.infn.ct.security.liferay.openidconnect.level = FINE
Test your Setup: Login with OpenID ConnectNow you can validate if your setup is working as expected. Open the following URL in your browser:
https://localhost:8443/c/portal/login?openIdLogin=true

Make sure to logout first, if you are still logged in at your portal.
You should get redirected to the Fediz IDP Login page and after login (bob:bob) you should get redirected back to your Liferay portal.
When you login the very first time, you should see a screen to confirm the "Terms of Use". After that you will be asked to enter a new password. This password can be used to login without SSO / OpenID Connect so you should choose a complex password. As long as you use SSO however you will never be ask again to enter this password. Same applies to the password reminder.
Once that is done, you will see the start screen of the Liferay Portal.
Now you can logout and login again with the above URL. This time you will login directly without any additional steps/questions.

You have been successful!
Categories: Jan Bernhardt

Fediz with OpenID Connect Support and WS-Federation Bridge (2/2)

Jan Bernhardt - Mon, 12/14/2015 - 14:46
Setup a DemonstratorIn this article I'll explain how to setup a demonstrator for the use case described in my previous post.
Setup Fediz IDP & OIDCFirst you need to setup the Fediz IDP as usual. To get the OIDC Service working you also need to do the following:
  1. Install Fediz Plugin for the Fediz IDP Server (usually you would do this for the client application only)
    For the fediz_config.xml you can use the sample provided with the OIDC Service.
  2. Download or build the OIDC service and then deploy the fediz-oidc.war file to your webapps folder (same place where you deployed STS & IDP)
Register an OpenID Connect Client From the perspective of OpenID Connect the Web Portal takes the role of a OIDC client. So the client must be registered up front. After starting the OIDC service you can invoke the following URL in your browser:

https://localhost:9443/fediz-oidc/clients/register
For Client Name and Client Description you can enter any human readable and meaningful value related to your service.
OIDC supports Confidential as well as Public as a Client Type. If your Client is a Public client (for example your client is java code running inside the browser of a user), no client secret will be generated, since the secret could not be protected anyway. The normal use case however should be Confidential.
Your redirect URI will be the final URL from which the OIDC service will redirect the user with the generated code. Normally this will be a OIDC Client service from your app consuming the code value and exchanging it for an access and ID token.
If your application (OIDC Client) is  bound to a fix Home Realm (all users from this app will always login at the same home realm), then you can select this HomeRealm here. In this case users will not see a home realm selection screen but will be redirected to the correct home realm IDP directly.

After submitting you client information you will see the generated client_id and client_secret. These values need to be set at the web portal.
Understanding the Web PortalYour web portal can by any kind of (java) web application. To enable OpenID Connect support at my web application I need to add a Relaying Party (RP) OIDC Handler at a URL of my choice.
<!--
OIDC RP endpoint: authenticates a user by redirecting a user to OIDC Provider, and redirects the user
to the initial application form once the authentication is done
-->
<jaxrs:server id="oidcRpServer" address="/oidc">
<jaxrs:serviceBeans>
<bean class="org.apache.cxf.rs.security.oidc.rp.OidcRpAuthenticationService">
<!-- This state manager is shared between this RP endpoint and the oidcRpFilter which protects
the application endpoint, the RP endpoint sets an OIDC context on it and the filter checks
the context is available -->
<property name="clientTokenContextManager" ref="stateManager" />
<!-- Where to redirect to once the authentication is complete -->
<property name="defaultLocation" value="/app/service/start" />
</bean>
</jaxrs:serviceBeans>

<jaxrs:providers>
<!-- the filter which does the actual work for obtaining an OIDC context.
It redirect to the OIDC Provider, exchanges an authorization code for access token,
extracts OIDC IdToken and makes it all available as OidcCientTokenContext
-->
<bean id="rpOidcRequestFilter" class="org.apache.cxf.rs.security.oidc.rp.OidcClientCodeRequestFilter">
<property name="clientCodeStateManager">
<!-- This state manager creates an OAuth2 'state' parameter and saves it in the HTTP session -->
<bean class="org.apache.cxf.rs.security.oauth2.client.MemoryClientCodeStateManager">
<property name="generateNonce" value="true"/>
</bean>
</property>
<property name="scopes" value="openid refreshToken" />
<property name="accessTokenServiceClient" ref="atServiceClient" />
<property name="idTokenReader">
<bean class="org.apache.cxf.rs.security.oidc.rp.IdTokenReader">
<!-- disable it if the local key store or the client secret is used to validate ID Tokens -->
<property name="jwkSetClient" ref="jwkSetClient"/>
<property name="issuerId" value="accounts.fediz.com"/>
</bean>
</property>
<property name="consumer" ref="consumer" />
<property name="authorizationServiceUri" value="https://localhost:9443/fediz-oidc/idp/authorize" />
<property name="startUri" value="rp" />
<property name="completeUri" value="/" />
</bean>

<!-- JAX-RS provider that makes OidcClientTokenContext available as JAX-RS @Context -->
<ref bean="clientTokenContextProvider" />
</jaxrs:providers>
</jaxrs:server>
 
<!-- The state manager shared between the RP and application endpoints -->
<bean id="stateManager" class="org.apache.cxf.rs.security.oauth2.client.MemoryClientTokenContextManager"/>
<!-- WebClient for requesting an OAuth2 Access token.
rpOidcRequestFilter uses it to exchange a code for a token -->

<jaxrsclient:client id="atServiceClient" threadSafe="true"
address="https://localhost:9443/fediz-oidc/oauth2/token"
serviceClass="org.apache.cxf.jaxrs.client.WebClient">
<jaxrsclient:headers>
<entry key="Accept" value="application/json"/>
</jaxrsclient:headers>
<jaxrsclient:providers>
<bean class="org.apache.cxf.jaxrs.provider.FormEncodingProvider">
<property name="expectedEncoded" value="true"/>
</bean>
</jaxrsclient:providers>
</jaxrsclient:client>

<!-- Client id and secret allocated by OIDC ClientRegistrationService -->
<bean id="consumer" class="org.apache.cxf.rs.security.oauth2.client.Consumer">
<property name="clientId" value="-7TdKEwzkf5BSQ"/>
<property name="clientSecret" value="q6ys7349uXMIgOu1kXNFTQ"/>
</bean>
 
<!-- JAX-RS provider that makes OidcClientTokenContext available as JAX-RS @Context -->
<bean id="clientTokenContextProvider" class="org.apache.cxf.rs.security.oauth2.client.ClientTokenContextProvider"/>

<!-- disable it if the local key store or the client secret is used to validate ID Tokens -->
<jaxrsclient:client id="jwkSetClient" threadSafe="true"
address="https://localhost:9443/fediz-oidc/jwk/keys"
serviceClass="org.apache.cxf.jaxrs.client.WebClient">
<jaxrsclient:headers>
<entry key="Accept" value="application/json"/>
</jaxrsclient:headers>
<jaxrsclient:providers>
<bean class="org.apache.cxf.rs.security.jose.jaxrs.JsonWebKeysProvider"/>
</jaxrsclient:providers>
</jaxrsclient:client>

For being able to use the access token when invoking a REST Backend-Service you must add the access token as an Authorization Header within your Request. For this purpose you must first create a JAX-RS Client and also inject the OIDC-Context to your application.
<jaxrsclient:client id="backendServiceClient" threadSafe="true"
   address="https://localhost:8082/backendService" serviceClass="org.apache.cxf.jaxrs.client.WebClient">
   <jaxrsclient:headers>
       <entry key="Accept" value="application/json"/>
   </jaxrsclient:headers>
   <jaxrsclient:providers>
      <bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider"/>
   </jaxrsclient:providers>
</jaxrsclient:client>
Within your code you need to inject the OidcClientTokenContext, for example via @Context annotation:
@Context
private OidcClientTokenContext oidcContext;
Within your method when just before invoking the REST Service you must add the authorization header as follows:
ClientAccessToken accessToken = oidcContext.getToken();
backendServiceClient.authorization(accessToken);
Understanding the REST ServiceLets take a DemoService as an example to explain the OIDC/Auth2 Integration at the backend REST Service.First lets take a loog a the REST Interface. You will note an annotation @Scopes which will require that the used access token was provided for the scope userinfo. The other method will also require an access token, but without any scope enforcement.
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;

import org.apache.cxf.rs.security.oauth2.filters.Scopes;

@Path("/")
public class DemoService {
   
    @GET
    @Path("/public")
    public String getGreeting() {
        return "Hello World!";
    }
   
    @GET
    @Path("/secure")
    @Scopes("userinfo")
    public String getPersonalGreeting(@QueryParam("name") String name) {
        return "Hello " + name + "!";
    }
}

Within your Spring configuration you need to add two filters. The OAuthRequestFilter is needed to ensure that the provided access token is still valid, and the OAuthScopesFilter checks that the required scope for invoking a certain method will matches with the scope of the access token.
<bean id="demoService" class="org.apache.service.DemoService"/>

<jaxrs:server id="demoService" address="/greeting">
    <jaxrs:serviceBeans>
        <ref bean="demoService"/>
    </jaxrs:serviceBeans>
    <jaxrs:providers>
        <bean class="org.apache.cxf.rs.security.oauth2.filters.OAuthRequestFilter">
         <property name="tokenValidator">
<bean class="org.apache.cxf.rs.security.oauth2.filters.AccessTokenValidatorClient">
         <property name="tokenValidatorClient" ref="tokenValidatorClient"/>
     </bean>
         </property>
  </bean>
    <bean class="org.apache.cxf.rs.security.oauth2.filters.OAuthScopesFilter">
        <property name="securedObject" ref="demoService"/>
    </bean>
  </jaxrs:providers>
</jaxrs:server>

<jaxrsclient:client id="tokenValidatorClient"
address="https://localhost:9443/fediz-oidc/oauth2/validate"
serviceClass="org.apache.cxf.jaxrs.client.WebClient">
<jaxrsclient:headers>
<entry key="Content-Type" value="application/x-www-form-urlencoded"/>
<entry key="Accept" value="application/xml"/>
</jaxrsclient:headers>
<jaxrsclient:providers>
<bean class="org.apache.cxf.jaxrs.provider.FormEncodingProvider">
<property name="expectedEncoded" value="true"/>
</bean>
</jaxrsclient:providers>
</jaxrsclient:client>
Since validation is not yet standardized  the tokenValidatorClient communicates with the OIDC service in a proprietary manner.

Categories: Jan Bernhardt

Fediz with OpenID Connect Support and WS-Federation Bridge (1/2)

Jan Bernhardt - Wed, 12/09/2015 - 16:53
I'm currently engaged for a big company to provide a solution that allows this company to offer various (REST) services to their partners while these services are hosted and maintained by the company but users can login to these services with accounts managed within their own partner network.

This solution should work for Web-Portals, Mobile Apps & Desktop Applications.

First I was skeptical if it will be possible to find one solution fitting all theses different use cases. But I think I actually did find a very interesting solution. In this post I'll explain the overall architecture of this solution. In my next posts I'll tell you how to get a Liferay Web-Portal integrated as well as a mobile App based on Android.

WS-Federation normally uses SAML Tokens for user authentication. This is fine for container based security solutions, when the user wants to login to a web-portal. But modern web applications (e.g. AJAX based) tend to be executed primarily in the Browser, invoking REST backend services directly from within the Browser.
Handling XML based tokens (incl. XML signature validation) is just a too heavy burden for this type of applications. Also handling lifetime issues with SAML Token could require a Token exchange with an STS. But an STS only provides a SOAP interface according to WS-Trust. It is not feasible for a AJAX Web Application to handle SOAP communication including XML security. Browser based applications should be light-weight and thus they prefer talking to REST services.

Token Types & Token Handling JSON Web Tokens (JWT) are similar to SAML tokens but instead of being XML based they are provided in a JSON format. Since JSON is the preferred document format for REST services, they fit much better to a REST Service compared to a XML based SAML Token.

One step closer to the solution could be to provide a STS that can issue JWT tokens as well as SAML tokens. This could help to exchange SAML token to JWT token and vice versa in cases when you need both. SAML for SOAP services and JWT for REST services. Colm O hEigeartaigh has already done some improvements to the CXF STS to support JWT tokens at the STS.

Instead of requesting a SAML Token with the following TokenType http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0 you can now also request a JWT token with this TokenType urn:ietf:params:oauth:token-type:jwt.

This way you can request or even exchange JWT tokens simply by setting the expected TokenType value. When sending a SAML or JWT token OnBehalfOf your token request you can exchange one format for the other.
What is currently missing to bridge both token types for SOAP and REST scenarios would be a REST interface for the STS. This would make it a lot easier for REST clients to interact with an STS. Since there are no standards for a STS REST API, I'll design a REST interface by myself discuss it with the CXF community and then add it to the STS soon.

OpenID ConnectI would see OpenID Connect as the successor standard for WS-Federation which was the successor standard of the SAML Web-Profile. You can see that the OIDC sequence flow is still similar to the prior protocols but that it also learned and improved a lot from the older standards.

OIDC is also based on the OAuth2 standard and thus inherits also all benefits and drawbacks of this protocol.

Many big internet companies support OpenID Connect like Google, Facebook, Twitter, etc..
OpenID Connect is related but not equal to OpenID on which some of the bigger companies dropped already the support for (like Google).
Simple Sequence FlowOpenID connect is based on OAuth2 and thus provides several sequence flows. Which one you will choose will depend on your circumstances. In this blog I'll focus on the authorization code flow only.

(1) The user invokes the WebPortal (same would apply if the user invokes a REST Service).
GET https://demo.portal.com/webPortal/index.html HTTP/1.1
Host: demo.portal.comto be continued...
(2) Since there is no existing session with the user, the server response with a redirect to the OIDC Server (line breaks added to improve readability).
HTTP/1.1 303 See Other
Location: https://your.oidc-server.com/idp/login
?client_id=Ro2hJVtj94oWLw
&scope=openid
&response_type=code
&redirect_uri=https%3A%2F%2Fdemo.portal.com%2FwebPortal%2Foidc
&state=a8a4ee9e8061a34f93539635ce02e32
&nonce=1d5c428ffbff3eed95721339e67c56e8c2aa4add6bb493e436249578c81f88
The user will see a login screen for authentication.
(3) After successful login the user will be redirected back to the provided redirect_uri with an authorization code:
HTTP/1.1 303 See Other
Set-Cookie: JSESSIONID=55638DC5FF717DD730B72978B70F088E; Path=/idp/; Secure; HttpOnly
Cache-Control: private
Expires: Thu, 01 Jan 1970 01:00:00 CET
Date: Thu, 19 Nov 2015 13:39:08 GMT
Location: https://demo.portal.com/webPortal/oidc
?state=a8a4ee9e8061a34f93539635ce02e32
&code=a1a822cd99da976f47c8a7218ae212
(4) This code can now be used by the service provider (web portal) to get a JWT token. For this reason the service provider needs to authenticate against the token endpoint with its client_id & client_secret within the Authorization header, as well as the code value and redirect_uri.
POST https://your.oidc-server.com/idp/oauth2/token
Host: your.oidc-server.com
Authorization: Basic Um8yaEpWdGo5NG9XTHc6RUFpemlWUU5PWVpmaHN5WGlSNmpxUQ==

grant_type=authorization_code
&code=a1a822cd99da976f47c8a7218ae212
&redirect_uri=https%3A%2F%2Fdemo.portal.com%2FwebPortal%2Foidc
As a result the token endpoint of the OIDC IDP will return the JWT Token as well as an access code. The access code will not be needed in this first scenario but is just part of the usual Oauth2 flow.
HTTP/1.1 200 OK
Content-Type: application/json

{
"access_token": "a8de6a544738c9e9036318ee78dfe7",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "openid",
"id_token": "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJib2IiLCJhdWQiOiJVVUY5RmRzNjdubnA2QSIsImlhdCI6MTQ0OTY3NDMyNywiZXhwIjoxNDQ5NzM0MzI3LCJnaXZlbl9uYW1lIjoiQm9iIiwiZW1haWwiOiJib2J3aW5kc29yQHJlYWxtYS5vcmciLCJmYW1pbHlfbmFtZSI6IldpbmRzb3IiLCJuYW1lIjoiQm9iIFdpbmRzb3IiLCJub25jZSI6IjFkNWM0MjhmZmJmZjNlZWQ5NTcyMTMzOWU2N2M1NmU4YzJhYTRhZGQ2YmI0OTNlNDM2MjQ5NTc4YzgxZjg4IiwiaXNzIjoiYWNjb3VudHMuZmVkaXouY29tIiwiYXRfaGFzaCI6InZvc1h4a1lhcW1aYmJiTWlVdWdYRUEifQ.VQB4QfI1nrka5cfgq8aOGyT0iv3EEE7BBETIzQHbee1t9BDr8wPNV55pGY1YqU6F5C9KIkWiIGLz8MBlKwQVfU7FfzXqm4gEF2zbq4i_LyL-f_RW38-id4VmfF3n6ybWDqdmLLXagFL2UurTdIuGWxbZVW_bgnuIc5dJfnQ_b2wi9hxoL-1u4PPufDLfTLBYRtP5zaedR01me9T5i6PCn2jZSdvfd9304Jf6MOf98Cvv-faeZ87ilUrd5k3q4tQl6dIL3IefPBTfbR8Ni69viD29A-PvtKLquQcGp6p3NEXnwOYF7c72ZsjuZI2pcItoeBeo2Whz9Ni21vfWsd3Iaw"
}
The id_token contains three values of interest base64 encoded and separated by a dot '.':
eyJhbGciOiJSUzI1NiJ9

eyJzdWIiOiJib2IiLCJhdWQiOiJVVUY5RmRzNjdubnA2QSIsImlhdCI6MTQ0OTY3NDMyNywiZXhwIjoxNDQ5NzM0MzI3LCJnaXZlbl9uYW1lIjoiQm9iIiwiZW1haWwiOiJib2J3aW5kc29yQHJlYWxtYS5vcmciLCJmYW1pbHlfbmFtZSI6IldpbmRzb3IiLCJuYW1lIjoiQm9iIFdpbmRzb3IiLCJub25jZSI6IjFkNWM0MjhmZmJmZjNlZWQ5NTcyMTMzOWU2N2M1NmU4YzJhYTRhZGQ2YmI0OTNlNDM2MjQ5NTc4YzgxZjg4IiwiaXNzIjoiYWNjb3VudHMuZmVkaXouY29tIiwiYXRfaGFzaCI6InZvc1h4a1lhcW1aYmJiTWlVdWdYRUEifQ

VQB4QfI1nrka5cfgq8aOGyT0iv3EEE7BBETIzQHbee1t9BDr8wPNV55pGY1YqU6F5C9KIkWiIGLz8MBlKwQVfU7FfzXqm4gEF2zbq4i_LyL-f_RW38-id4VmfF3n6ybWDqdmLLXagFL2UurTdIuGWxbZVW_bgnuIc5dJfnQ_b2wi9hxoL-1u4PPufDLfTLBYRtP5zaedR01me9T5i6PCn2jZSdvfd9304Jf6MOf98Cvv-faeZ87ilUrd5k3q4tQl6dIL3IefPBTfbR8Ni69viD29A-PvtKLquQcGp6p3NEXnwOYF7c72ZsjuZI2pcItoeBeo2Whz9Ni21vfWsd3Iaw
After base64 decoding the first value will tell us which algorithm has been used to secure the ID token:
{"alg":"RS256"}
And the second value will contain the actual JWT token:
{
"sub": "bob",
"aud": "UUF9Fds67nnp6A",
"iat": 1449674327,
"exp": 1449734327,
"given_name": "Bob",
"email": "bobwindsor@realma.org",
"family_name": "Windsor",
"name": "Bob Windsor",
"nonce": "1d5c428ffbff3eed95721339e67c56e8c2aa4add6bb493e436249578c81f88",
"iss": "accounts.fediz.com",
"at_hash": "vosXxkYaqmZbbbMiUugXEA"
}
The third parameter will contain the digital signature (binary value) thus I cannot display it here.

After consuming the authorization code the user will be redirected back to the initially requested resource
HTTP/1.1 303 See Other
Location: https://demo.portal.com/webPortal/index.html

OpenID Connect with WS-Federation LoginNow after understanding the basic OpenID Connect flow lets extend this scenario by performing the login not directly at the OIDC service but instead using the Fediz-Plugin at the OIDC Service to redirect the user according to WS-Federation to the Fediz-IDP for user authentication. After successful login at the Fediz-IDP the user will be send back to the OIDC with a SAML token. This token can then be mapped to a JWT token for the OpenID connect login process.


(1) In the first step the user invokes the web portal.
(2) Since now existing session exists the user will be redirected to the OIDC Service according to OpenID Connect.
(3) An Apache Fediz Plugin is active on the OIDC Server. Since now previous session exists the Fediz Plugin will redirect the user to the RP-IDP according to WS-Federation.
(4) The user will see a login screen and will be redirected back to the OIDC server after successful authentication with a SAML token.
(5) The Fediz Plugin will store the SAML Token. OIDC will provide the requested code from step (2).
(6) The Web Portal can now exchange this code according to OAuth2 to get the JWT Token (transformation of the SAML token), as well as an access token to invoke another backend service.
(7) The REST Service will be invoked with the access token received in the previous step
GET https://my.services.com/backend/service
Host: my.services.com
Authorization: Bearer a8de6a544738c9e9036318ee78dfe7
(8) The REST Service will send the access token to the OIDC to ensure that this code is valid. (Unfortunately it is not defined within the standard how this validation should happen)

In my second part of this post, I'll explain how to setup a demonstrator for the above described use case.

Federated SSO with WS-Federation & OpenID ConnectAfter understanding OpenID Connect and WS-Federation Login I'll extend this scenario by one more degree of complexity thus providing us the flexibility which we discusses at the beginning to provide a SSO solution not just within one company but for multiple partners at the same time.

(1) A user from a partner company invokes the web portal.
(2) Since now existing session exists the user will be redirected to the OIDC Service according to OpenID Connect.
(3) An Apache Fediz Plugin is active on the OIDC Server. Since now previous session exists the Fediz Plugin will redirect the user to the RP-IDP according to WS-Federation.
(4) Since no existing session exists at the RP-IDP, the RP-IDP will perform a Home-Realm discovery and after that redirects the user to its own Requestor IDP (more details about this in the next section).
(5) After successful login the Requestor IDP will issue a SAML Token for the user and redirect the user back to the RP-IDP.
(6) The RP-IDP will to do a Claims or Identity Mapping and after that issue a new SAML token applicable for the OIDC Service and redirects the user back to the OIDC service.
(7) The Fediz Plugin at the OIDC service will store the SAML Token and OIDC will provide the requested code from step (2).
(8) The Web Portal can now exchange this code according to OAuth2 to get the JWT Token (transformation of the SAML token), as well as an access token to invoke a backend service.
(9) The REST Service will be invoked with the access token received in the step (8).
(10) The REST Service will send the access token to the OIDC to ensure that this code is valid. (Unfortunately it is not defined within the standard how this validation should happen)
Home Realm DiscoveryIf your web portal shall be used by users from multiple realms (e.g. partner networks), you need to find a way to discover the home realm of each user. The OpenID Connect Standard provides a parameter login_hint for this purpose whereas WS-Federation Standard offers a whr parameter for this purpose.

There are several ways to do a home realm discovery:
  1. Dedicated URLs
    You can provide different URLs for each user group. This can be done by adding the login_hint parameter directly to the URL which the user is invoking (e.g. link within a different portal which the user usually access first). Also very famous is the usage of different domain names with a reverse proxy in place which adds the login_hint / whr parameter.
  2. E-Mail Address
    If there is just a single page which will be used by all user groups it is also a good choice to ask the user for his/her E-Mail address and then use this as the  the login_hint.The OIDC service could use the domain name of this E-Mail Address to set it as the whr parameter for home realm discovery at the RP-IDP. The RP-IDP would need a mapping table of domain names and Requestor IDP URLs to send the user to its home IDP.
    One disadvantage of this solution is that the user will most likely be required to enter his/her E-Mail address twice. First at the portal to initiate the home realm discovery and later for the login at the Requestor IDP. This is because WS-Federation does not provide a felxible login_hint but instead only a more static whr parameter which will be the same value for all users within one group. You can improve the user experience if you use cookies to remember the selected home realm of a user until a user initiated logout takes place.
  3. IP Range
    IP ranges can also be used for home realm discovery but are usually not a good choice because users will not just login from a company network with a static IP but also from mobile devices with a dynamic IP range.
  4. Miscellaneous
    Any other way to securely identify the home realm of a user would also be acceptable, but will usually require custom development efforts to the services.
Categories: Jan Bernhardt

Javascript Object Signing and Encryption (JOSE) support in Apache CXF - part III

Colm O hEigeartaigh - Mon, 12/07/2015 - 18:03
This is the third article in a series of posts on support for Javascript Object Signing and Encryption (JOSE) in Apache CXF. The previous article described how to encrypt content using the JSON Web Encryption specification. This post covers support for JSON Web Tokens (JWT) in Apache CXF. The JWT spec is not strictly part of the JOSE specification set, but it makes sense to cover it in this series of posts, as it is a natural extension of the JOSE specs to convey claims.

1) Test Cases:

As before, let's start by looking at some practical unit tests on github:
  • cxf-jaxrs-jose: This project contains a number of tests that show how to use the JSON Security functionality in Apache CXF to sign and encrypt JSON payloads to/from a JAX-RS service.
These tests mostly follow the same basic format. The web service configuration defines a number of endpoints that map to the same web service implementation (a simple DoubleItService, which allows a user to POST a number and receive the doubled amount, where both the request and response are encoded via JSON). The client test code first constructs a JWT Token and then includes it in the message payload by adding a specific provider. The JWT Token is then processed by a provider on the receiving side. We will cover the individual tests in more detail below.

2) Constructing JWT Tokens

Apache CXF provides an easy to use API to create JWT Tokens. Let's look at how this is done in one of the tests - the JWTAuthenticationTest. The tests construct a JwtClaims Object, which has convenient set/get methods for the standard JWT Claims. For example:


The JwtClaims Object can be passed through to the constructor of a JwtToken Object. To serialize the JwtToken in the request simply add the JwtAuthenticationClientFilter to the client provider list, and specify the JwtToken Object as a message property under "jwt.token". Alternatively, the JwtClaims Object can be passed without having to construct a JwtToken via the property "jwt.claims". On the receiving side, a JWTToken can be processed by the JwtAuthenticationFilter provider.

3) Authentication and Authorization using signed JWT Tokens

By default, the JwtAuthenticationClientFilter signs the JWT Token. The signature configuration is the exact same as that used for JWS as covered in the first article. On the receiving side, the JwtAuthenticationFilter will set up a security context for the authenticated client, assuming that a public key signature algorithm was used to sign the token. The "sub" (Subject) claim from the token gets mapped to the principal of the security context.

As the JWT Token can convey arbitrary claims, it can be used for RBAC authorization. This is demonstrated in the JWTAuthorizationTest. A role called "boss" is inserted into the token. On the receiving side, the JwtAuthenticationFilter is configured to use the "role" claim in the token to extract roles for the authenticated principal and to populate the security context with them. As part of the test-case, CXF's SimpleAuthorizingInterceptor is used to require that a client must have a role of "boss" to invoke on the web service method in question.

4) Encrypting JWT Tokens

It is very easy to encrypt JWT Tokens (as well as both sign and encrypt) them in CXF. The JwtAuthenticationClientFilter needs to be configured to also encrypt the token, and the same configuration is used as for JWE in the previous article. Similarly, on the receiving side the JwtAuthenticationFilter must have the property "jweRequired" set to "true" to decrypt incoming encrypted tokens. See the JWTEncryptedTest test for some examples. 

5) Token validation

On receiving a JAX-RS request containing a JWT token, the
JwtAuthenticationFilter will first parse the token, and then verify the signature (if present) and decrypt the token (if encrypted). It then performs some quality of service validation on the token claims, which I'll detail here. This validation can be easily modified by overriding the protected "validateToken" method in JwtAuthenticationFilter.
  • The "exp" (Expiration Time) claim is validated if present. If the expiry value is before the current date/time, then the token is rejected. 
  • The "nbf" (Not Before) claim is validated if present. If the not before value is after the current date/time, then the token is rejected. 
  • The "iat" (Issued At) claim is validated if present. To validate the "iat" claim, a "ttl" property must be set on the JwtAuthenticationFilter.
  • Either an "iat" or "exp" claim must be present in the token, as otherwise we have no way of enforcing an expiry on a token.
  • A clockskew value can also be configured on the JwtAuthenticationFilter via the "clockOffset" property.
  • The "aud" (Audience) claim is validated. This claim must contain at least one audience value which matches the endpoint address of the recipient.
Categories: Colm O hEigeartaigh

Javascript Object Signing and Encryption (JOSE) support in Apache CXF - part II

Colm O hEigeartaigh - Wed, 12/02/2015 - 18:49
This is the second in a series of blog posts on the support for the Javascript Object Signing and Encryption (JOSE) specifications in Apache CXF. The first article covered how to sign content using the JSON Web Signature (JWS) specification. In this post we will look at how to encrypt content using the JSON Web Encryption (JWE) specification.

1) Test Cases:

As before, let's start by looking at some practical unit tests on github:
  • cxf-jaxrs-jose: This project contains a number of tests that show how to use the JSON Security functionality in Apache CXF to sign and encrypt JSON payloads to/from a JAX-RS service.
For now let's look at the tests contained in JWETest. These tests mostly follow the same basic format. The web service configuration defines a number of endpoints that map to the same web service implementation (a simple DoubleItService, which allows a user to POST a number and receive the doubled amount, where both the request and response are encoded via JSON). The client test code uses the CXF WebClient API to encrypt the message payload by adding a specific provider. The message in turn is decrypted by a provider on the receiving side. You can run the test via the command line "mvn test -Dtest=JWETest", and the message requests and responses will appear in the console.

2) Compact vs. JSON Serialization

Just like the JWS specification, there are two different ways of serializing JWE structures. Compact serialization is a URL-safe representation that is convenient to use when you only have a single encrypting entity. JSON serialization respresents the JWE structures as JSON objects. As of the time of publishing this post, CXF only has interceptors for the compact approach. However I'm told the JSON serialization case will be supported very soon :-)

The providers to use for the compact case on both the client + receiving sides are:
  • Compact: JweWriterInterceptor (out) + JweContainerRequestFilter (in)
3) Security Configuration

As well as adding the desired providers, it is also necessary to specify the security configuration to set the appropriate algorithms, keys, etc. to use. The CXF wiki has an extensive list of all of the different security configuration properties. For encryption, we need to first load the encrypting key (either a JKS keystore or else a JSON Web Key (JWK) is supported).

As well as defining the encryption key, we also need to configure the algorithms to encrypt the content as well as to encrypt the key. The list of acceptable encryption algorithms for JWE is defined by the JSON Web Algorithms (JWA) spec. For content encryption, the supported algorithms are all based on AES (CBC/GCM mode) with different key sizes. For key encryption, various schemes based on RSA, AES KeyWrap/GCM, Elliptic Curve Diffie-Hellman, PBES2 are supported, as well as a symmetric encryption option.

For example, the tests use the following configuration to load a public key from a Java KeyStore, and to use the RSA-OAEP key encryption algorithm, as well as a 128-bit AES content encryption algorithm in CBC mode, using HMAC-SHA256 to generate the authentication code:
The service side configuration is largely the same, apart from the fact that we need to specify the "rs.security.key.password" configuration tag to load the private key. The encryption algorithms must also be specified to impose a constraint on the desired algorithms.

4) Encrypting XML payload

Similar to the signature case, it is possible to use JWE to encrypt an XML message, and not just a JSON message. An example is included in JWETest ("testEncryptingXMLPayload").  The configuration is exactly the same as for the JSON case. 

5) Including the encrypting key

It is possible to include the encrypting certificate/key in the JWE header by setting one of the following properties:
  • rs.security.encryption.include.public.key - Include the JWK public key for encryption in the "jwk" header.
  • rs.security.encryption.include.cert - Include the X.509 certificate for encryption in the "x5c" header.
  • rs.security.encryption.include.key.id - Include the JWK key id for encryption in the "kid" header.
  • rs.security.encryption.include.cert.sha1 - Include the X.509 certificate SHA-1 digest for encryption in the "x5t" header.
It could be useful to include the encrypting certificate/key if the recipient has multiple decryption keys and doesn't know which one to use to decrypt the request.

6) Signing + encrypting a message

It is possible to both sign and encrypt a message by combining the JWS + JWE interceptors. For example, simply adding the JweWriterInterceptor and JwsWriterInterceptor providers on the client side will both sign and encrypt the request. An example is included in the github project above (JWEJWSTest). 
Categories: Colm O hEigeartaigh

Javascript Object Signing and Encryption (JOSE) support in Apache CXF - part I

Colm O hEigeartaigh - Mon, 11/30/2015 - 18:39
The Javascript Object Signing and Encryption (JOSE) specifications cover how to sign and encrypt data using JSON. Apache CXF has excellent support for all of the JOSE specifications (see the documentation here), thanks largely to the work done by my colleague Sergey Beryozkin. This is the first in a series of blog posts describing how to use and implement JOSE for your web services using Apache CXF. In this post, we will cover how to sign content using the JSON Web Signature (JWS) specification.

1) Test Cases:

Let's start by looking at some practical unit tests on github:
  • cxf-jaxrs-jose: This project contains a number of tests that show how to use the JSON Security functionality in Apache CXF to sign and encrypt JSON payloads to/from a JAX-RS service.
For now let's look at the JWSSignatureTest. These tests mostly follow the same basic format. The web service configuration defines a number of endpoints that map to the same web service implementation (a simple DoubleItService, which allows a user to POST a number and receive the doubled amount, where both the request and response are encoded via JSON). The client test code uses the CXF WebClient API to sign the message payload by adding a specific provider. The message in turn is validated by a provider on the receiving side. You can run the test via the command line "mvn test -Dtest=JWSSignatureTest", and the message requests and responses will appear in the console.

For example, here is the output of the "testSignatureCompact" request. The Payload consists of the concatenated (+ separated by a '.') BASE-64 URL encoded JWS header (e.g. containing the signature algorithm, amongst other values), the BASE-64 URL encoded message payload, and the BASE-64 URL encoded signature value.


2) Compact vs. JSON Serialization

The JWS specification defines two different ways of serializing the signatures. Compact serialization is a URL-safe representation that is convenient to use when you only have a single signing entity. JSON serialization resprents the JWS structures as JSON objects, and allows multiple signatures to be included in the request as a result. The JWSSignatureTest includes both examples ("testSignatureListProperties" and "testSignatureCompact"). It's very easy to experiment with both approaches, as you only have to use different providers on both the client + receiving sides:
  • JSON Serialization: JwsJsonWriterInterceptor (out) + JwsJsonContainerRequestFilter (in)
  • Compact: JwsWriterInterceptor (out) + JwsContainerRequestFilter (in)
3) Security Configuration

As well as adding the desired providers, it is also necessary to specify the security configuration to set the appropriate algorithms, keys, etc. to use. The CXF wiki has an extensive list of all of the different security configuration properties. For signature, we need to first load the signing key (either a JKS keystore or else a JSON Web Key (JWK) is supported).

As well as defining a signing key, we also need to configure the signing algorithm. The list of acceptable signing algorithms for JWS is defined by the JSON Web Algorithms (JWA) spec. For signature, this boils down to a public key signature scheme based on either RSA or EC-DSA, or a symmetric scheme using HMAC.

For example, the tests use the following configuration to load a private key from a Java KeyStore, and to use the signature scheme of RSASSA-PKCS1-v1_5 using SHA-256:
The service side configuration is largely the same, apart from the fact that we don't need to specify the "rs.security.key.password" configuration tag, as we don't need to load the private key. The signature algorithm must be specified to impose a constraint on the acceptable signature algorithm.

4) Signing XML payload

The JWS payload (the content to be signed) can be any binary content and not just a JSON Object. This means that we can use JWS to sign an XML message. This is a really cool feature of the specification in my opinion, as it essentially removes the need to use XML Signature to sign XML payload. An example of this is included in the JWSSignatureTest. The configuration is exactly the same as for the JSON case.

5) Including the signing key

It is possible to include the signing certificate/key in the JWS header by setting one of the following properties:
  • rs.security.signature.include.public.key -  Include the JWK public key for signature in the "jwk" header.
  • rs.security.signature.include.cert - Include the X.509 certificate for signature in the "x5c" header.
  • rs.security.signature.include.key.id - Include the JWK key id for signature in the "kid" header.
  • rs.security.signature.include.cert.sha1- Include the X.509 certificate SHA-1 digest for signature in the "x5t" header.
One advantage of including the entire certificate is that the service doesn't need to store the client certificate locally, but only the issuing certificate.
Categories: Colm O hEigeartaigh

Enterprise ready request logging with CXF 3.1.0 and elastic search

Christian Schneider - Mon, 11/30/2015 - 15:24

Blog post edited by Christian Schneider

You may already know the old CXF LoggingFeature (org.apache.cxf.feature.LoggingFeature). You added it to a JAXWS endpoint to enable logging for a CXF endpoint at compile time.

While this already helped a lot it was not really enterprise ready. The logging could not be controlled much at runtime and contained too few details. This all changes with the new CXF logging support and the up coming Karaf Decanter.

Logging feature in CXF 3.1.0

In CXF 3.1 this code was moved into a separate module and gathered some new features.

  • Auto logging for existing CXF endpoints
  • Uses slf4j MDC to log meta data separately
  • Adds meta data for Rest calls
  • Adds MD5 message id and exchange id for correlation
  • Simple interface for writing your own appenders
  • Karaf decanter support to log into elastic search
Manual UsageCXF LoggingFeature <jaxws:endpoint ...> <jaxws:features> <bean class="org.apache.cxf.ext.logging.LoggingFeature"/> </jaxws:features> </jaxws:endpoint> Auto logging for existing CXF endpoints in Apache Karaf

Simply install and enable the new logging feature:

Logging feature in karaf feature:repo-add cxf 3.1.0 feature:install cxf-features-logging config:property-set -p org.apache.cxf.features.logging enabled true

Then install CXF endpoints like always. For example install the PersonService from the Karaf Tutorial Part 4 - CXF Services in OSGi. The client and endpoint in the example are not equipped with the LoggingFeature. Still the new logging feature will enhance the clients and endpoints and log all SOAP and Rest calls using slf4j. So the logging data will be processed by pax logging and by default end up in your karaf log.

A log entry looks like this:

Sample Log entry 2015-06-08 16:35:54,068 | INFO | qtp1189348109-73 | REQ_IN | 90 - org.apache.cxf.cxf-rt-features-logging - 3.1.0 | <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:addPerson xmlns:ns2="http://model.personservice.cxf.karaf.tutorial.lr.net/" xmlns:ns3="http://person.jms2rest.camel.karaf.tutorial.lr.net"><arg0><id>3</id><name>Test2</name><url></url></arg0></ns2:addPerson></soap:Body></soap:Envelope>

This does not look very informative. You only see that it is an incoming request (REQ_IN) and the SOAP message in the log message. The logging feature provides a lot more information though. You just need to configure the pax logging config to show it.

Slf4j MDC values for meta data

This is the raw logging information you get for a SOAP call:

FieldValue@timestamp2015-06-08T14:43:27,097ZMDC.addresshttp://localhost:8181/cxf/personServiceMDC.bundle.id90MDC.bundle.nameorg.apache.cxf.cxf-rt-features-loggingMDC.bundle.version3.1.0MDC.content-typetext/xml; charset=UTF-8MDC.encodingUTF-8MDC.exchangeId56b037e3-d254-4fe5-8723-f442835fa128MDC.headers{content-type=text/xml; charset=UTF-8, connection=keep-alive, Host=localhost:8181, Content-Length=251, SOAPAction="", User-Agent=Apache CXF 3.1.0, Accept=*/*, Pragma=no-cache, Cache-Control=no-cache}MDC.httpMethodPOSTMDC.messageIda46eebd2-60af-4975-ba42-8b8205ac884cMDC.portNamePersonServiceImplPortMDC.portTypeNamePersonServiceMDC.serviceNamePersonServiceImplServiceMDC.typeREQ_INlevelINFOloc.classorg.apache.cxf.ext.logging.slf4j.Slf4jEventSenderloc.fileSlf4jEventSender.javaloc.line55loc.methodsendloggerClassorg.ops4j.pax.logging.slf4j.Slf4jLoggerloggerNameorg.apache.cxf.services.PersonService.REQ_INmessage<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:getAll xmlns:ns2="http://model.personservice.cxf.karaf.tutorial.lr.net/"; xmlns:ns3="http://person.jms2rest.camel.karaf.tutorial.lr.net"/></soap:Body></soap:Envelope>;threadNameqtp80604361-78timeStamp1433774607097

Some things to note:

  • The logger name is <service namespace>.<ServiceName>.<type> karaf by default only cuts it to just the type.
  • A lot of the details are in the MDC values

You need to change your pax logging config to make these visible.

You can use the logger name to fine tune which services you want to log this way. For example set the debug level to WARN for noisy services to avoid that they are logged or log some services to another file.

Message id and exhange id

The messageId allows to uniquely identify messages even if you collect them from several servers. It is also transported over the wire so you can correlate a request sent on one machine with the request received on another machine.

The exchangeId will be the same for an incoming request and the response sent out or on the other side for an outgoing request and the response for it. This allows to correlate request and responses and so follow the conversations.

Simple interface to write your own appenders

Write your own LogSender and set it on the LoggingFeature to do custom logging. You have access to all meta data from the class LogEvent.

So for example you could write your logs to one file per message or to JMS.

Karaf decanter support to write into elastic search

Many people use elastic search for their logging. Fortunately you do not have to write a special LogSender for this purpose. The standard CXF logging feature will already work.

It works like this:

  • CXF sends the messages as slf4j events which are processed by pax logging
  • Karaf Decanter LogCollector attaches to pax logging and sends all log events into the karaf message bus (EventAdmin topics)
  • Karaf Decanter ElasticSearchAppender sends the log events to a configurable elastic search instance

As Decanter also provides features for a local elastic search and kibana instance you are ready to go in just minutes.

Installing Decanter for CXF Logging feature:repo-add mvn:org.apache.karaf.decanter/apache-karaf-decanter/3.0.0-SNAPSHOT/xml/features feature:install decanter-collector-log decanter-appender-elasticsearch elasticsearch kibana


After that open a browser at http://localhost:8181/kibana. When decanter is released kibana will be fully set up. At the moment you have to add the logstash dashboard and change the index name to [karaf-]YYYY.MM.DD.

Then you should see your cxf messages like this:

Kibana easily allows to filter for specific services and correlate requests and responses.

This is just a preview of decanter. I will do a more detailed post when the first release is out.

 

View Online
Categories: Christian Schneider

WADL and Swagger United in Apache CXF

Sergey Beryozkin - Fri, 11/20/2015 - 18:33
Who could've thought that Swagger and WADL can be real friends ?
Both Swagger and WADL are about describing REST APIs and while the former has a definite momentum, the latter has proved to be very capable and helpful to JAX-RS users.

The important thing is that we have users who submit WADL documents  to the runtime or build time code generators which is all working fine. We also have Swagger users who use cool Swagger features and being happy with a nice UI being generated. And WADL users, while being happy with WADL (which IMHO is indeed a very capable language for describing schema rich XML but with some extensions - even JSON - services) would like to use Swagger to introspect the code generated by WADL processors and have a nice API UI.

So my colleague Andrei and  Francesco, Apache Syncope maestro, have driven the work about enhancing a WADL generator to set WADL documentation fragments as Java Docs in the generated sources and then having CXF Swagger features being very smart about enhancing Swagger JSON payloads with these Java Docs, with Francesco doing some magic there. I should also mention Andriy Redko doing some work earlier on directly with Swagger for it to better support JAX-RS annotations and initiating the CXF Swagger project and Aki Yoshida doing a lot of Swagger2 work next.

So here you go, WADL and Swagger United in Apache CXF.

IMHO this project has been a perfect example of the power of the Open Source collaboration with the contributors from different teams working effectively on this project.


Categories: Sergey Beryozkin

HTrace your Apache CXF Service flows

Sergey Beryozkin - Fri, 11/20/2015 - 18:10
Andriy Redko keeps pushing CXF to the next level with adding new features nearly every few weeks :-).

One of his latest projects has been to do with wiring Apache HTrace into CXF such that CXF users can HTrace calls starting from CXF clients going to CXF servers and then to such HTrace aware containers as HBase  and using the collectors like Zipkin.

I'm looking forward to Andriy talking in detail about it on his blog and at the conferences, but in meantime you can check the documentation. Note that it works not only for JAX-RS but for JAX-WS too: if we can have a new feature working with both frontends then you know it will be done. The demo is here.

Give it a try and stay on top of the web services game :-)
Enjoy !



 
Categories: Sergey Beryozkin

JAX-RS 2.1 specification work has started

Sergey Beryozkin - Fri, 11/20/2015 - 17:51
JAX-RS 2.1 specification work has finally started after a rather quiet year and this is a good news for JAX-RS users at large and CXF JAX-RS users in particular.
JAX-RS 2.1 is entirely Java 8 based and a number of new enhancements are on the way. I was concerned earlier on that having a Java 8 will slow down the adoption but I think now the spec leads were right, Java 8 is so rich and JAX-RS needs to be open to accepting the latest Java features - ultimately this is what will excite the users.

The main new features list is: support for Server-Sent Events (something CXF users will enjoy experimenting with while also keeping in mind CXF has some great WebSocket support done by Aki), enhanced NIO support and introducing a reactive mode into Client API.

I've already mentioned before that JAX-RS 2.0 AsyncResponse API is IMHO very impressive as it makes a fairly complex task of dealing with suspended invocations becoming rather trivial to deal with. Marek and Santiago are doing it again with the new 2.1 proposals. Of course there will be some minor disagreements here and there but overall I'm very positive about this new JAX-RS project.


We now have a CXF Java 8 master branch to support the future JAX-RS 2.1 features but having a Java 8 trunk is great for all of the CXF community.

What is really good is that there appears to be no obvious end to the new requirements coming into the JAX-RS space. The HTTP services space is wide open, with the new ideas generated around the security, faster processing, etc, and it all will be eventually available as future JAX-RS features. I'm confident JAX-RS 3.0 will be coming in due time too.


Categories: Sergey Beryozkin

Pages

Subscribe to Talend Community Coders aggregator