05 February 2016

Apache Fediz installation in production

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 Changes

Remove Files

rm -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 Files

mv 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
  • Add your desired database library to your dependencies at services/idp/pom.xml

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 Files

rm -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 Files

mv services/sts/src/main/resources/stsKeystoreA.properties services/sts/src/main/resources/stsKeystore.properties

Modify 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 Installation

Tomcat 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 750 {} +

IDP Tomcat Setup

Setup 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/latest
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 $CATALINA_BASE | 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
    echo
  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
Update file permissions
# Create tomcat-idp user 
useradd -d /usr/share/tomcat-idp tomcat-idp
usermod -a -G tomcat tomcat-idp

# Make startscript executable
chmod 750 /etc/init.d/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
Register Tomcat for autostart:
chkconfig tomcat-idp on
Start, 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/conf/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
 
# Set ownership of all files to root and provide tomcat-idp access via group ownership 
chown -R root:tomcat-idp /usr/share/tomcat-idp/webapps/

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

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

# Tomcat-IDP will not be able to deploy further applications on its own 
chmod 750 /usr/share/tomcat-idp/webapps

# Remove war files
rm /usr/share/tomcat-idp/webapps/*.war
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/latest
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 $CATALINA_BASE | 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
    echo
  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
Update file permissions
# Create tomcat-sts user
useradd -d /usr/share/tomcat-sts tomcat-sts
usermod -a -G tomcat tomcat-sts

# Make startscript executable
chmod 750 /etc/init.d/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
Register Tomcat for autostart:
chkconfig tomcat-sts on
Start, Wait and Stop Tomcat
/etc/init.d/tomcat-sts start
tail -f /usr/share/tomcat-sts/logs/catalina.out
/etc/init.d/tomcat-sts stop
Your sts.war file should now be extracted.
Copy the sts keystore to your tomcat-sts root folder:
cp /usr/share/tomcat-idp/webapps/idp/WEB-INF/classes/idp-ssl-key.jks /usr/share/tomcat-sts/
cp /usr/share/tomcat-idp/webapps/idp/WEB-INF/classes/idp-ssl-trust.jks /usr/share/tomcat-sts/
Adjust settings of /usr/share/tomcat-sts/conf/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
# Set ownership of all files to root and provide tomcat-sts access via group ownership
chown -R root:tomcat-sts /usr/share/tomcat-sts/webapps/

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

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

# Tomcat-STS will not be able to deploy further applications by its own
chmod 750 /usr/share/tomcat-sts/webapps

# Remove war files
rm /usr/share/tomcat-sts/webapps/*.war
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 

OIDC Installation

Just in case, that you would want to use OIDC also, you need to do the following steps, to get it up and running:

I'm assuming here that you will install OIDC in the same Tomcat with the IDP. However this is not required, you could also easily setup a 3rd Tomcat container tomcat-oidc. In that case you need to change the file locations & settings accordingly.

Download Fediz Client Plugin (zip-with-dependencies.zip) and extract libraries to /usr/share/tomcat-idp/lib
mkdir /usr/share/tomcat-idp/lib
cd /usr/share/tomcat-idp/lib/ 
wget http://search.maven.org/remotecontent?filepath=org/apache/cxf/fediz/fediz-tomcat7/1.2.1/fediz-tomcat7-1.2.1-zip-with-dependencies.zip
unzip fediz-tomcat7-1.2.1-zip-with-dependencies.zip
rm fediz-tomcat7-1.2.1-zip-with-dependencies.zip
chmod 640 /usr/share/tomcat-idp/lib/*
chown -R root:tomcat-idp /usr/share/tomcat-idp/lib
# Copy STS Truststore from sts deployment
cp /usr/share/tomcat-sts/webapps/sts/WEB-INF/classes/ststrust.jks /usr/share/tomcat-idp/
chown root:tomcat-idp /usr/share/tomcat-idp/ststrust.jks

Next you must add the plugin configuration at /usr/share/tomcat-idp/conf/fediz_config.xml

<FedizConfig>
        <contextConfig name="/oidc">
                <audienceUris>
                        <audienceItem>urn:org:apache:cxf:fediz:oidc</audienceItem>
                </audienceUris>
                <certificateStores>
                        <trustManager>
                                <keyStore file="ststrust.jks" password="changedPassword" type="JKS" />
                        </trustManager>
                </certificateStores>
                <trustedIssuers>
                        <issuer certificateValidation="PeerTrust" />
                </trustedIssuers>
                <protocol xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                        xsi:type="federationProtocolType" version="1.0.0">
                        <realm>urn:org:apache:cxf:fediz:oidc</realm>
                        <issuer>https://my-external.domain.com:8443/idp/federation</issuer>
                        <homeRealm type="Class">org.apache.cxf.fediz.service.oidc.handler.hrd.LoginHintHomeRealmDiscovery,org.apache.cxf.fediz.service.oidc.handler.hrd.ClientIdHomeRealmDiscovery</homeRealm>
                        <roleDelimiter>,</roleDelimiter>
                        <roleURI>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role</roleURI>
                        <claimTypesRequested>
                                <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role" optional="true" />
                                <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" optional="true" />
                                <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" optional="true" />
                                <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" optional="true" />
                        </claimTypesRequested>
                </protocol>
        </contextConfig>
</FedizConfig>

1 comment:

  1. it would be amazing if there was a command line wizard which would do this. it could ask where you plan to deploy the webapp, it could generate the necessary certificates, ask what the credentials of your ldap server are etc.

    ReplyDelete