tag:blogger.com,1999:blog-52570086706692592762024-03-23T11:14:42.982+01:00Lessons LearnedThis blog focuses on technical solutions around security and application integration tasksJan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.comBlogger27125tag:blogger.com,1999:blog-5257008670669259276.post-57948338196099567202022-03-07T18:05:00.011+01:002022-04-25T19:27:16.101+02:00How-to enable Certificate revocation List (CRL) validation with Talend ESB Runtime<p>When certificates are issued they usually have a lifetime of a few years. In some cases it is necessary to terminate the validity of a certificate before the planned end of life. For example if a private key was compromised a certificate should not be valid, as soon as possible.</p>
<p>X.509 certificates (the most common certificate type, used for most internet services) support two different types of certificate revocation:</p>
<ol style="text-align: left;">
<li><a href="https://en.wikipedia.org/wiki/Online_Certificate_Status_Protocol" target="_blank">Online Certificate Status Protocol</a> (OCSP) <a href="https://datatracker.ietf.org/doc/html/rfc6960" target="_blank">RFC-6960</a><br />The application that wants to validate a certificate sends a certificate identifier to the OCSP Server for revocation checking. The response tells the client if the certificate was revoked or is still OK to use.</li>
<li><a href="https://en.wikipedia.org/wiki/Certificate_revocation_list" target="_blank">Certificate Revocation List</a> (CRL) <a href="https://datatracker.ietf.org/doc/html/rfc5280" target="_blank">RFC-5280</a><br />The application downloads a file that contains a list of revoked certificates and checks if the current certificate is listed in that file.</li>
</ol>
<p>As you can see already from the RFC number CRL is the older standard which is usually less performant and less up-to-date compared with OCSP. However in this bog post, I will only focus on the CRL approach.</p>
<p>By default most Java applications will not check for certificate revocations as not every certificate contains a revocation URI and it also has a negative performance impact. The same applies to the Talend runtime. However if you need to check for revocations it is easy to activate. All you need to do is to set two system properties:</p>
<pre class="brush:js">com.sun.net.ssl.checkRevocation=true
com.sun.security.enableCRLDP=true
</pre>
<p>
You can add these two lines at the end of the <code>runtime/etc/system.properties</code> configuration file.</p><p>If you are interested in the complete logging output you can add some debug system properties in the same file as well:</p>
<pre class="brush:js">javax.net.debug=all
java.security.debug=all
</pre><p>In the rest of this article I will show you how to create your own certificates that contain a CRL URL to test and validate this setup.</p><span><a name='more'></a></span><p>If you are running on windows I can recommend the <a href="https://keystore-explorer.org/" target="_blank">KeyStore Explorer</a> to you, as it makes it very easy to handle any kind of certificates.</p><p>At first you need to create a root certificate authority (CA).</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhsB4zLyXdIloZHkIRPaByj8DHjqr07tmHrlbpBGFxIj_L40v30LQGBqukSGDwAOilrHrRVLTwS2yL1w-1DkEhOT-w5z7iaOcXl2xfJ_5-oDrtHZsWG0m-tX9ZFz0U6c3MALwC_RI57fCNLAFgDWB_yUbKhbRT4qdT08QmXb2NLQA4-5ts4H-nMH5Gh=s783" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="674" data-original-width="783" height="344" src="https://blogger.googleusercontent.com/img/a/AVvXsEhsB4zLyXdIloZHkIRPaByj8DHjqr07tmHrlbpBGFxIj_L40v30LQGBqukSGDwAOilrHrRVLTwS2yL1w-1DkEhOT-w5z7iaOcXl2xfJ_5-oDrtHZsWG0m-tX9ZFz0U6c3MALwC_RI57fCNLAFgDWB_yUbKhbRT4qdT08QmXb2NLQA4-5ts4H-nMH5Gh=w400-h344" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="text-info">At first I was able to test my setup without a CRL URL in my root CA. But testing again today it was not working. I had to recreate the root ca, add the CRL URL and replace all my other issued keys. After that it was working again as needed.</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgGrI0oAFnE3ylPsWkNTXywtOznZpmtsEoZz87u213T3yjYY0yJcnBh2TWaswXat8EZC5p0FuR1YUwJ0YVgfFajrxE2gR7ZvUC9lXmmkDdteRTs4qa2VYGLErKEewhaZKHzwD1ENtrM9-hjbezdunmHJMyoV_aMTPUmTzt1yC2vGJz0Y-2U9H3aDvi0=s944" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="848" data-original-width="944" height="359" src="https://blogger.googleusercontent.com/img/a/AVvXsEgGrI0oAFnE3ylPsWkNTXywtOznZpmtsEoZz87u213T3yjYY0yJcnBh2TWaswXat8EZC5p0FuR1YUwJ0YVgfFajrxE2gR7ZvUC9lXmmkDdteRTs4qa2VYGLErKEewhaZKHzwD1ENtrM9-hjbezdunmHJMyoV_aMTPUmTzt1yC2vGJz0Y-2U9H3aDvi0=w400-h359" width="400" /></a></div><br /></div>Next you need to create your server certificate.<div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiH0A-RaiYATCeyowfRJkbZ2DlFD5dPaHD3PyxeqPP39CK9awNQTkSm_IwDQWo9ZHyrX_6yGVd9O3HgY7NwR1jRaaMcQyWZjvaaJCattFtLah5H8QdaEnrgH7CKrgtxmpfKxi47NKKpnCS0UzyFunY8YCjI2tHmsmHyR5oUaaSCdg3BrECXNkXWFBXs=s715" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="559" data-original-width="715" height="313" src="https://blogger.googleusercontent.com/img/a/AVvXsEiH0A-RaiYATCeyowfRJkbZ2DlFD5dPaHD3PyxeqPP39CK9awNQTkSm_IwDQWo9ZHyrX_6yGVd9O3HgY7NwR1jRaaMcQyWZjvaaJCattFtLah5H8QdaEnrgH7CKrgtxmpfKxi47NKKpnCS0UzyFunY8YCjI2tHmsmHyR5oUaaSCdg3BrECXNkXWFBXs=w400-h313" width="400" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgY2MUSB_EsXgjp2Xi_WPLjYE2OUlt-uaSqjmnB8htfWn7ii5EkvygF-rAlujIYz1HcRSx_NsX2CmpG7RLIGGbGfn36gNmC83gVVpW3eyTXLS8wqKSDD73I9XSaZRxroNbzpbmjxa88eduK0BSdhMK1CLxh_diUDwY6A7-YRtaB3-f57e9tHXoNXVMD=s940" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="794" data-original-width="940" height="338" src="https://blogger.googleusercontent.com/img/a/AVvXsEgY2MUSB_EsXgjp2Xi_WPLjYE2OUlt-uaSqjmnB8htfWn7ii5EkvygF-rAlujIYz1HcRSx_NsX2CmpG7RLIGGbGfn36gNmC83gVVpW3eyTXLS8wqKSDD73I9XSaZRxroNbzpbmjxa88eduK0BSdhMK1CLxh_diUDwY6A7-YRtaB3-f57e9tHXoNXVMD=w400-h338" width="400" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEj7MkzLa2iJ9aVglKXPiZiaF4vtIiEFJLMOa-gMYJ5fiBj-QWNzDHuRxz0opnJrmVUn8ppRoTIrxFOP6zGW3-_grHEZ5yVUX7o0JcLV33yu8ankOAtZFpWXZiRyLvgfMOPKT5eo2k1c2K9HjHB_iuN3EgFvNashDiH4K1PfhIx69WKOap4eNHC1SyZT=s809" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="657" data-original-width="809" height="325" src="https://blogger.googleusercontent.com/img/a/AVvXsEj7MkzLa2iJ9aVglKXPiZiaF4vtIiEFJLMOa-gMYJ5fiBj-QWNzDHuRxz0opnJrmVUn8ppRoTIrxFOP6zGW3-_grHEZ5yVUX7o0JcLV33yu8ankOAtZFpWXZiRyLvgfMOPKT5eo2k1c2K9HjHB_iuN3EgFvNashDiH4K1PfhIx69WKOap4eNHC1SyZT=w400-h325" width="400" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEh0ml2U6CVpN7LDnwgCTt6p6dmQ1ggMYjYeWl49H-1SL9WGsTyrrdke-0RT98vZ1OQWbO8MIw8zAPWC0OQzQ7T9CmD6We_vGcltUVJGMMJnxdT-xHO2giz7amsSO2itpotHgopVBPwqNI1Wud_njoivGDecM1XW7bJGuzCiQDtOnR0Pixd11L4O7rzm=s895" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="809" data-original-width="895" height="361" src="https://blogger.googleusercontent.com/img/a/AVvXsEh0ml2U6CVpN7LDnwgCTt6p6dmQ1ggMYjYeWl49H-1SL9WGsTyrrdke-0RT98vZ1OQWbO8MIw8zAPWC0OQzQ7T9CmD6We_vGcltUVJGMMJnxdT-xHO2giz7amsSO2itpotHgopVBPwqNI1Wud_njoivGDecM1XW7bJGuzCiQDtOnR0Pixd11L4O7rzm=w400-h361" width="400" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEifMGsR7Pu4vkk0mX8L41Y030_m-WrBtJfCXBFFU0XSm0V1xyfVtNoOmhsmiYmqAbmHjhVuREZaECJ0tMWOkiSCK1JCu6MAhdQW2zl2ssl9P3X7Tfe4pjCjmerM_gzvaPIzePeQUrUm1njObTFcN3ToCPvMHIVuFGMlyUwJkfkTJ1sC2-Siuf5ovyow=s944" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="848" data-original-width="944" height="359" src="https://blogger.googleusercontent.com/img/a/AVvXsEifMGsR7Pu4vkk0mX8L41Y030_m-WrBtJfCXBFFU0XSm0V1xyfVtNoOmhsmiYmqAbmHjhVuREZaECJ0tMWOkiSCK1JCu6MAhdQW2zl2ssl9P3X7Tfe4pjCjmerM_gzvaPIzePeQUrUm1njObTFcN3ToCPvMHIVuFGMlyUwJkfkTJ1sC2-Siuf5ovyow=w400-h359" width="400" /></a></div><br /><div>For the client certificate you need to do almost the same as for the server certificate, except that you do not need to set a subject alternative name and you need to select the TLS client usage instead of the TLS server usage on the extended key usage settings:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiFWkjBQdsqGS8tMlztl1s86cUviZQMYBALoX3xQ3X-iIFFQIz3UDWwUi05xFsU4Njrwq6I8yrsyGcawQwHFXNeARQfx2fAvdTU0unS_2kiGvsG_zqbIgS8WM9tdWFZVZ504t12wwB98k37JZ82C4jywMNrH4DaGWdxXjOSesX5pspT_-Jw0dYERd3N=s794" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="586" data-original-width="794" height="295" src="https://blogger.googleusercontent.com/img/a/AVvXsEiFWkjBQdsqGS8tMlztl1s86cUviZQMYBALoX3xQ3X-iIFFQIz3UDWwUi05xFsU4Njrwq6I8yrsyGcawQwHFXNeARQfx2fAvdTU0unS_2kiGvsG_zqbIgS8WM9tdWFZVZ504t12wwB98k37JZ82C4jywMNrH4DaGWdxXjOSesX5pspT_-Jw0dYERd3N=w400-h295" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">Save the keystore and create 3 copies of that file. Open each file and remove two key pairs from each, so that you end up with 3 files where each file contains a different key pair.</div><br /><div>Export eachcertificate into a local file as we will need them later.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhK8auoHmtl-AjuPshkiknNp0jKuww1ULdmcUleZgRVZDQOTaxRPZBQt6Mx_IGYbQIZa2es0hG3lOIVc22k38RWgC9hnGIzc9p6Bim_n4iNx0DwW2Pm1zsP7sgWG0cSx4EOU_60OjQDKz00IgdB5jZQnL8R1kFyaE-0i5ctaObphl1VurLik-J111Ov=s718" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="566" data-original-width="718" height="315" src="https://blogger.googleusercontent.com/img/a/AVvXsEhK8auoHmtl-AjuPshkiknNp0jKuww1ULdmcUleZgRVZDQOTaxRPZBQt6Mx_IGYbQIZa2es0hG3lOIVc22k38RWgC9hnGIzc9p6Bim_n4iNx0DwW2Pm1zsP7sgWG0cSx4EOU_60OjQDKz00IgdB5jZQnL8R1kFyaE-0i5ctaObphl1VurLik-J111Ov=w400-h315" width="400" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEib2SvHPSsH0Ao7ox_mOpZ_x90EWRDM9Eb4XhaLxFuVDSdbiq9fIwGcJXC4pWAVnBinAUE1EB2lVdKQ3caoqazZkHeYF6V1y21d-wybQYYbpd6L57PGak-zHeh6sACn7TlGHdRtfzqyAZCex4Qhjds_bxDnuvZFZbWwg0tF4nx0c4kEFiE-rrh5SxHS=s514" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="239" data-original-width="514" height="186" src="https://blogger.googleusercontent.com/img/a/AVvXsEib2SvHPSsH0Ao7ox_mOpZ_x90EWRDM9Eb4XhaLxFuVDSdbiq9fIwGcJXC4pWAVnBinAUE1EB2lVdKQ3caoqazZkHeYF6V1y21d-wybQYYbpd6L57PGak-zHeh6sACn7TlGHdRtfzqyAZCex4Qhjds_bxDnuvZFZbWwg0tF4nx0c4kEFiE-rrh5SxHS=w400-h186" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">Now we can create a certificate revocation list.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgGrI0oAFnE3ylPsWkNTXywtOznZpmtsEoZz87u213T3yjYY0yJcnBh2TWaswXat8EZC5p0FuR1YUwJ0YVgfFajrxE2gR7ZvUC9lXmmkDdteRTs4qa2VYGLErKEewhaZKHzwD1ENtrM9-hjbezdunmHJMyoV_aMTPUmTzt1yC2vGJz0Y-2U9H3aDvi0=s944" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="848" data-original-width="944" height="359" src="https://blogger.googleusercontent.com/img/a/AVvXsEgGrI0oAFnE3ylPsWkNTXywtOznZpmtsEoZz87u213T3yjYY0yJcnBh2TWaswXat8EZC5p0FuR1YUwJ0YVgfFajrxE2gR7ZvUC9lXmmkDdteRTs4qa2VYGLErKEewhaZKHzwD1ENtrM9-hjbezdunmHJMyoV_aMTPUmTzt1yC2vGJz0Y-2U9H3aDvi0=w400-h359" width="400" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjNPljYcnEe8bQDp63jz3op0xzp-CUAnbiFxnUtyOlIZP20vrwXJKhOdF3jsWDvSF3yPvIBbLdgpu3m7tw7CwoeI-N3bgdk3uAFgz2CzeHINtLf2ORvGKMTQNcXIDENq0bawbADqlw8ZGb8an5c5RLYl8c75biNE84eX2dglVhFR-mEXDXlvQziD-6o=s721" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="571" data-original-width="721" height="316" src="https://blogger.googleusercontent.com/img/a/AVvXsEjNPljYcnEe8bQDp63jz3op0xzp-CUAnbiFxnUtyOlIZP20vrwXJKhOdF3jsWDvSF3yPvIBbLdgpu3m7tw7CwoeI-N3bgdk3uAFgz2CzeHINtLf2ORvGKMTQNcXIDENq0bawbADqlw8ZGb8an5c5RLYl8c75biNE84eX2dglVhFR-mEXDXlvQziD-6o=w400-h316" width="400" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjb2PnjhP6LwQ1DOXRWJYJ48wDnrhLr40evcTRSnRogQemF7lD1bjh0JxpSlFRAb-HKOnzerXCnRi6eTdmFZk-H4EFslMJU7eU25aAv1Cuvjs_dvBlDKae6JrxsQE5YyyxwXWFodNd7MkD-kCb2m2k6NXmpLyQNEWDhpqIJlG9QJUzUzZHwoAxTRq99=s807" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="664" data-original-width="807" height="329" src="https://blogger.googleusercontent.com/img/a/AVvXsEjb2PnjhP6LwQ1DOXRWJYJ48wDnrhLr40evcTRSnRogQemF7lD1bjh0JxpSlFRAb-HKOnzerXCnRi6eTdmFZk-H4EFslMJU7eU25aAv1Cuvjs_dvBlDKae6JrxsQE5YyyxwXWFodNd7MkD-kCb2m2k6NXmpLyQNEWDhpqIJlG9QJUzUzZHwoAxTRq99=w400-h329" width="400" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhSC1gxFenb51N0Y_g697seXn-TIAKiq9cSBt4aVnu2RiYtdsfhF9B6rSltLfn8grqhfMCVIM-HuB85ZDFFIyEMJnYSOZae0slHbsUk1O4-bbwXy1bjXzCGOWkPXAV-7osUS2cA2WgzvqcRVZ8TYZxmtxED4nXoHA2HLdkGR9Ljl369L_9lJBX2z8kU=s440" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="175" data-original-width="440" height="159" src="https://blogger.googleusercontent.com/img/a/AVvXsEhSC1gxFenb51N0Y_g697seXn-TIAKiq9cSBt4aVnu2RiYtdsfhF9B6rSltLfn8grqhfMCVIM-HuB85ZDFFIyEMJnYSOZae0slHbsUk1O4-bbwXy1bjXzCGOWkPXAV-7osUS2cA2WgzvqcRVZ8TYZxmtxED4nXoHA2HLdkGR9Ljl369L_9lJBX2z8kU=w400-h159" width="400" /></a></div><br /><div class="separator" style="clear: both; text-align: left;">Upload this file to your URL that you used earlier when setting the CRL URI in your certificate creation process.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">For the root ca certificate you should create a dedicated truststore.</div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhgYJ-YvE1KsjlUqwAhpKrU03VVytf2l5CrnDEx-RDHrzZqqDnuo-Vdu_24e6-WAkIi2jntw-njnBx9eJctv64oZYXTQUBZLDdNMmW5icmhPPISYmP2fV3ir-ADS6C7n-vegM3biAacdg1AR43p1ide1cdRA7CdMTGIvXHD049vHPosh_vgzvwtMgJ7=s717" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="566" data-original-width="717" height="316" src="https://blogger.googleusercontent.com/img/a/AVvXsEhgYJ-YvE1KsjlUqwAhpKrU03VVytf2l5CrnDEx-RDHrzZqqDnuo-Vdu_24e6-WAkIi2jntw-njnBx9eJctv64oZYXTQUBZLDdNMmW5icmhPPISYmP2fV3ir-ADS6C7n-vegM3biAacdg1AR43p1ide1cdRA7CdMTGIvXHD049vHPosh_vgzvwtMgJ7=w400-h316" width="400" /></a></div><br /><div>Now you can use your newly created certificates in your ESB runtime <code>runtime/etc/org.ops4j.pax.web.cfg</code> file</div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhqwWSejaMxfgjU3iWcmiI-n2fYMc3hGuqUsA8rGXKKUALjv9MoqWe7U6ohUx-GwUGeP28ZMVVPP8fgAkMe2ttdxSsBVo969mBz7BbSEq2-pZnjreRqbSq_jktXxoPAnHlYV9_8cFw6E-HXh_j_7THlxykStkJW_O2Ct1yxlBaEftF_yKa8X7jPPaGf=s692" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="395" data-original-width="692" height="229" src="https://blogger.googleusercontent.com/img/a/AVvXsEhqwWSejaMxfgjU3iWcmiI-n2fYMc3hGuqUsA8rGXKKUALjv9MoqWe7U6ohUx-GwUGeP28ZMVVPP8fgAkMe2ttdxSsBVo969mBz7BbSEq2-pZnjreRqbSq_jktXxoPAnHlYV9_8cFw6E-HXh_j_7THlxykStkJW_O2Ct1yxlBaEftF_yKa8X7jPPaGf=w400-h229" width="400" /></a></div><br /><div>You can make the client authentication optional or mandatory by setting wanted (optional) or needed (mandatory) settings to true.</div><div><br /></div><div>You also need to import the client certificate in your browser so that you can choose it when connecting to your runtime.</div><div><br /></div><div>Now you are ready to test you setup. Strat your runtime and connect to the console. If you have done everything correct, you will see the following error.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgGRVHh0P_vrY6v-44zvFgOSY2iq010cd0vYptW1ygw5t4bxzs9DCJR1ec323VoSPFyIw_sXzXKzmD2xMX0RWYGUxzVoGn1ECcrhnemx0w2XERRLgwYbbneesbORaLs_OC3zlSTYDInQjhR3sFba7RY2D97B3hC_kTe-2H5zJiCn9oUo2TjYMHuDi1h=s1750" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="176" data-original-width="1750" height="64" src="https://blogger.googleusercontent.com/img/a/AVvXsEgGRVHh0P_vrY6v-44zvFgOSY2iq010cd0vYptW1ygw5t4bxzs9DCJR1ec323VoSPFyIw_sXzXKzmD2xMX0RWYGUxzVoGn1ECcrhnemx0w2XERRLgwYbbneesbORaLs_OC3zlSTYDInQjhR3sFba7RY2D97B3hC_kTe-2H5zJiCn9oUo2TjYMHuDi1h=w640-h64" width="640" /></a></div><br />
<div class="text-alert">Only certificates where the revocation status can be validated will be accepted now. Certificates without any CRL URLs will be rejected.</div>
<p></p>Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com0tag:blogger.com,1999:blog-5257008670669259276.post-71714340148931402122019-11-11T16:40:00.000+01:002019-11-11T16:40:32.089+01:00Only Once Ansible Task ExecutionAnsible is a great tool to setup multiple servers in a consistent reproducible way. It is easy to setup a complete cluster or a complex software architecture running on multiple machines. But some tasks only need to be executed once. For example you can setup a complete cluster of DB servers, but the table definitions/content only needs to be done once, after the cluster is running. Since the goal of Ansible is to always end with a consistent state it should be OK to run the same task multiple times, without breaking your setup (idempotent), but if you setup a bigger cluster with Hundertes of nodes, you would definitely want to avoid running the same task over and over again, if this can be avoided.<br />
<br />
There a basically two options that you can use to ensure a task is executed only once.
<br />
<a name='more'></a><h3>
<code>run_once: True</code></h3>
Code sample take from the <a href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_delegation.html#run-once" target="_blank">official documentation</a>:<br />
<pre class="brush: js">---
# ...
tasks:
- name: Send summary mail
local_action:
module: mail
subject: "Summary Mail"
to: "{{ mail_recipient }}"
body: "{{ mail_body }}"
run_once: True
</pre>
<div class="text-alert">
Not working if you use serial playbook execution!</div>
<br />
However this approach only works if you run your setup on all nodes simultaneously. If you run your playbook in a sequential order (using <code>serial: 1</code>) your <code>run_once</code> task will be executed each time.
<br />
If you plan to extend or upgrade your existing cluster you will have to set serial: 1 to ensure that each node gets updated one after the other. If you would upgrade all nodes at once, you would have a complete cluster outage. Please read the next section for an alternative approach.
<br />
<h3>
localhost execution</h3>
When you setup a complete cluster with ansible, you can usually reach this cluster from your localhost. Of course ssh port needs to be available anyway to run ansible, but in most cases you will also have access to the application port (e.g. from your DB) as well. By setting the <code>hosts</code> in your playbook to <code>localhost</code> you can also ensure that each role/task in your playbook is also executed only once.
<br />
<pre class="brush: js">---
- name: Setup elasticsearch configuration
hosts: localhost
roles:
- role: elasticsearch-config
</pre>
<div class="text-info">
Not working if you want to setup your application cluster within the same playbook</div>
<br />
If you want to setup your application cluster in a sequential way as well as setting up some configuration only once for your cluster, you need to define two different playbooks and then have another one importing both playbooks.
<br />
<pre class="brush: js">---
# Setup complete ELK stack for the cluster
- import_playbook: prepare_server.yml
- import_playbook: elasticsearch.yml
- import_playbook: elasticsearch-config.yml
- import_playbook: kibana.yml
- import_playbook: zookeeper.yml
- import_playbook: kafka.yml
- import_playbook: logstash.yml
- import_playbook: metricbeat.yml
- import_playbook: filebeat.yml
</pre>
The playbook <code>elasticsearch.yml</code> will run with <code>serial: 1</code> setting up each node one after the other, while the <code>elasticsearch-config.yml</code> playbook will be executed on your <code>localhost</code> only (once) the cluster is running. This way you can combine both approaches together.Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com1tag:blogger.com,1999:blog-5257008670669259276.post-16487614179314353362018-12-12T16:48:00.001+01:002018-12-12T16:55:37.700+01:00Custom Claim Handler in Fediz PluginApache Fediz plugin provides now a support for custom claim processing since version 1.4.5. This allows fine grained claim control on application side, which is very useful if you are not in control of the IDP/STS claim creation itself. Or if you want to do some local claim value mapping that is very application specific.<br />
<br />
In this blog post, I will show you how to leverage this new Fediz feature.<br />
<a name='more'></a><br />
If you want to provide your own Claim Parser you need to implement the following interface
<br />
<pre class="brush: java">package org.apache.cxf.fediz.core.processor;
import java.util.List;
import org.apache.cxf.fediz.core.Claim;
public interface ClaimsProcessor {
/**
* This operation can be used to transform, filter or trigger other actions
* based on the input claims. The response can be the same list of claims as
* from the input parameter, a subset of it or a renamed or extended list of
* claims.
*
* @param claims Claims to be processed
* @return List of processed claims
*/
List<claim> processClaims(List<claim> claims);
}</pre>
Here is a sample implementation of this interface showing you how easy it is to change any value of a given claim. Or even adding additional claims that have not been part of the original SAML token.<br />
<pre class="brush: java">import java.util.ArrayList;
package org.apache.cxf.fediz.common;
import java.util.List;
import org.apache.cxf.fediz.core.Claim;
import org.apache.cxf.fediz.core.ClaimTypes;
import org.apache.cxf.fediz.core.processor.ClaimsProcessor;
/**
* Changes claim type and claim value
*/
public class ClaimMutateProcessor implements ClaimsProcessor {
@Override
public List<claim> processClaims(List<claim> claims) {
List<claim> newClaimList = new ArrayList<>();
for (Claim c : claims) {
// Check if one claim is of type privatepersonalidentifier
if (ClaimTypes.PRIVATE_PERSONAL_IDENTIFIER.equals(c.getClaimType())) {
//Create new claim of type givenname
Claim lowerClaim = new Claim();
lowerClaim.setClaimType(ClaimTypes.FIRSTNAME);
// Copy value from source claim to new claim as lowercase text
lowerClaim.setValue(c.getValue().toString().toLowerCase());
//Create second claim of type surname
Claim upperClaim = new Claim();
upperClaim.setClaimType(ClaimTypes.LASTNAME);
// Copy value from source claim to new claim as UPPERCASE text
upperClaim.setValue(c.getValue().toString().toUpperCase());
// Add both claims to response
newClaimList.add(lowerClaim);
newClaimList.add(upperClaim);
}
}
return newClaimList;
}
}</pre>
You need to package your custom implementation as a jar file and add it together with the other Apache Fediz Plugin libraries to your application container.
<br /><br />
Next you need to enable the claim processor by adding it to your Fediz configuration:
<br />
<pre class="brush: xml"><?xml version="1.0" encoding="UTF-8"?>
<FedizConfig>
<contextConfig name="/fedizhelloworld">
<audienceUris>
<audienceItem>urn:org:apache:cxf:fediz:fedizhelloworld</audienceItem>
</audienceUris>
<certificateStores>
<trustManager>
<keyStore file="test-classes/clienttrust.jks"
password="storepass" type="JKS" />
</trustManager>
</certificateStores>
<trustedIssuers>
<issuer certificateValidation="PeerTrust" />
</trustedIssuers>
<maximumClockSkew>1000</maximumClockSkew>
<protocol xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="federationProtocolType" version="1.0.0">
<realm>urn:org:apache:cxf:fediz:fedizhelloworld</realm>
<issuer>https://localhost:${idp.https.port}/fediz-idp/federation</issuer>
<roleDelimiter>,</roleDelimiter>
<roleURI>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role</roleURI>
<freshness>10</freshness>
<homeRealm type="String">urn:org:apache:cxf:fediz:idp:realm-A</homeRealm>
<claimTypesRequested>
<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role" optional="false" />
<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/privatepersonalidentifier" optional="true" />
</claimTypesRequested>
</protocol>
<logoutURL>/secure/logout</logoutURL>
<logoutRedirectTo>/index.html</logoutRedirectTo>
<claimsProcessor type="Class">org.apache.cxf.fediz.common.ClaimMutateProcessor</claimsProcessor>
<!-- you can have one or more claimsProcessor elements added here -->
</contextConfig>
</FedizConfig></pre>
That's it. Next time you invoke your service, you will see that the user has firstname and lastname claims set instead of a privatepersonalidentifier.
Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com0tag:blogger.com,1999:blog-5257008670669259276.post-47826646778018783672018-09-28T12:50:00.002+02:002018-10-01T09:26:02.792+02:00Using camel json schema validation in Talend StudioSchema validation is well known for XML content. Since JSON has become very popular in combination with REST services the need for JSON schema validation has also increased.<br />
<br />
JSON schema validation is available since Camel 2.20.0 matching Talend Studio version 7.0.1.<br />
<br />
This article describes how JSON schema validation can be used for Talend Studio route development.<br />
<br />
<a name='more'></a><h2>
Missing dependencies</h2>
<div>
The first challenge to take is that the required dependencies are not pre-packed within Talend Studio 7.0.1. Adding the required jar libraries can become quite a challenge if you search for one missing dependency after the other.</div>
<br />
Getting a list of all required dependencies can be done a lot easier:<br />
<br />
<h4>
Option A</h4>
<div>
Copy <a href="https://github.com/apache/camel/blob/camel-2.20.1/components/camel-json-validator/pom.xml" target="_blank">pom.xml from github</a> and store it as a local file.<br />
Execute <a href="https://maven.apache.org/guides/getting-started/" target="_blank">Maven</a> to get the full dependency tree:<br />
<pre class="brush:bash">mvn dependency:tree</pre>
</div>
<h4>
Option B</h4>
Clone the existing camel repository<br />
<pre class="brush:bash">git clone https://github.com/apache/camel.git</pre>
Checkout to the correct version<br />
<pre class="brush:bash">git checkout camel-2.20.1 --</pre>
Switch to the camel-json-validator component directory<br />
<pre class="brush:bash">cd camel/components/camel-json-validator</pre>
Execute <a href="https://maven.apache.org/guides/getting-started/" target="_blank">Maven</a> to get the full dependency tree:<br />
<pre class="brush:bash">mvn dependency:tree</pre>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvQXUAwfjF3hbiMLdHS5Ph0UMjcggBIJ02S04OlwJP-t6LObmdxmSWd_iRSQjKSJL1iwXmbxymQezQw5cKS4mHerEq1Y3ZmKSlTZQjbUN6OqkQPFk2mdjhciwFR4DPzUBEGTgTA3SY3rU/s1600/mvn-dependency-tree-camel-json-validator.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="708" data-original-width="691" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvQXUAwfjF3hbiMLdHS5Ph0UMjcggBIJ02S04OlwJP-t6LObmdxmSWd_iRSQjKSJL1iwXmbxymQezQw5cKS4mHerEq1Y3ZmKSlTZQjbUN6OqkQPFk2mdjhciwFR4DPzUBEGTgTA3SY3rU/s320/mvn-dependency-tree-camel-json-validator.jpg" width="312" /></a></div>
<br />
Now you could download each jar file from the dependency list and add it as a remote library to your route within the cConfig component. This would still be a lot of work. See next section on how this can be done easier.<br />
<br />
<h2>
Create JAR file including all dependencies</h2>
To avoid downloading and adding each dependency separately you can also create a jar file including all required dependencies within the same jar file. This makes it a lot easier to handle within Studio.<br />
<br />
To do this you have to modify the existing pom file and add another plugin for this purpose:<br />
<br />
<code>camel/components/camel-json-validator/pom.xml</code><br />
<pre class="brush:xml"><project>
. . .
<dependencies>
. . .
</dependencies>
<build>
<plugins>
<!-- Maven Assembly Plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4.1</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
</pre>
Exclude camel-core (as this will be already available within the runtime by default) from dependencies by setting scope to provided:<br />
<pre class="brush:xml"><dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<scope>provided</scope>
</dependency>
</pre>
Execute maven to build jar file:<br />
<pre class="brush:bash">camel/components/camel-json-validator> mvn clean package</pre>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4GUaQrAS8ZRIzmFm8oAsqs4zScz_8rx7pDsPjlEW0HWD3Jk6nFT42tDyP8TmMqDjvI42KN4OmvYosjyry7oL4DE3jikQrpI3JBV_0iQs50Tb5Wc6pTN3nSs9LpUJBw2SGPSuyqpoDIBw/s1600/maven-build.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="478" data-original-width="803" height="190" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4GUaQrAS8ZRIzmFm8oAsqs4zScz_8rx7pDsPjlEW0HWD3Jk6nFT42tDyP8TmMqDjvI42KN4OmvYosjyry7oL4DE3jikQrpI3JBV_0iQs50Tb5Wc6pTN3nSs9LpUJBw2SGPSuyqpoDIBw/s320/maven-build.jpg" width="320" /></a></div>
<br />
<h2>
Setup demo route</h2>
Import <code>camel/components/camel-json-validator/target/camel-json-validator-2.20.1-jar-with-dependencies.jar</code> within <code>cConfig</code> component of your route in studio.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXTj5Sq9IVGOgHFCwqipP0bIJnuetwCbyJkBKS-Gaj5rDU2Q980FBre56imPs3_mkzKrnp2qaiTgayV2pL2Ur7iWXeeRV80LNuFRxnNOgnxG8CuK8nNPamMexR7ue4Mui_h65PA2x8_FY/s1600/studio-add-dependency.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="868" data-original-width="1600" height="173" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXTj5Sq9IVGOgHFCwqipP0bIJnuetwCbyJkBKS-Gaj5rDU2Q980FBre56imPs3_mkzKrnp2qaiTgayV2pL2Ur7iWXeeRV80LNuFRxnNOgnxG8CuK8nNPamMexR7ue4Mui_h65PA2x8_FY/s320/studio-add-dependency.jpg" width="320" /></a></div>
<br />
Before deploy to external runtime check external jar in Bundle ClassPath under the Dependencies tab of your route to include this library as embedded to your route.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjU1SnRonRDeaKYvLzy5iaKIbZozeGjbTaP7gZ-VyetBOtagxCOgLKnWsPHg1WtuhR7gc_fOTNK1uGeCqugmI-gVMpvbIbXdjKsABpywQmgw0ocOR6TfzVnv7hRUqUpDRr4JdhnIhtOJ9o/s1600/studio-embed-deppendency.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="867" data-original-width="1600" height="173" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjU1SnRonRDeaKYvLzy5iaKIbZozeGjbTaP7gZ-VyetBOtagxCOgLKnWsPHg1WtuhR7gc_fOTNK1uGeCqugmI-gVMpvbIbXdjKsABpywQmgw0ocOR6TfzVnv7hRUqUpDRr4JdhnIhtOJ9o/s320/studio-embed-deppendency.jpg" width="320" /></a></div>
<div>
<br /></div>
Use a generic <code>cMessagingEndpoint</code> component for validation. Set URI to your schema validation file.<br />
E.g.: <code>"json-validator:file:/C:/Talend/jsonValidation/people_schema.json"</code><br />
Review the full <a href="https://access.redhat.com/documentation/en-us/red_hat_jboss_fuse/7.0-tp/html/apache_camel_component_reference/json-validator-component" target="_blank">component documentation</a> to learn more about URI syntax and optional parameters if needed.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAeEWlatFvRgVQG26mOVtDAfTULq07C1okuVccHOodLUn30bAy7CgVCCgE9x3CqQa-a3yUvtbEfMDoFRwzBOCV7NStNXPFVqLIv9PeOQeLGR9NnLaX7iGkxF7Kr5gOgb-xHy7HCudo_sI/s1600/route-validator.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="616" data-original-width="788" height="250" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAeEWlatFvRgVQG26mOVtDAfTULq07C1okuVccHOodLUn30bAy7CgVCCgE9x3CqQa-a3yUvtbEfMDoFRwzBOCV7NStNXPFVqLIv9PeOQeLGR9NnLaX7iGkxF7Kr5gOgb-xHy7HCudo_sI/s320/route-validator.jpg" width="320" /></a></div>
<br />
You can catch the <code>org.apache.camel.ValidationException</code> to handle any payload that is not compliant with the schema.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhy8IcMpvqlgYpjkTuptyctl8saYqO-4O67XzkmrM5nzywGU8EJYQbcvaAZOhzdyXExkazH6tZoggyOUidY_xL_9_nY1pF-5AnJ3ViD403La-ooxOvqdgZUhjrg8zm1kKoCEiPu3_MKieE/s1600/route-exception.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="867" data-original-width="1600" height="173" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhy8IcMpvqlgYpjkTuptyctl8saYqO-4O67XzkmrM5nzywGU8EJYQbcvaAZOhzdyXExkazH6tZoggyOUidY_xL_9_nY1pF-5AnJ3ViD403La-ooxOvqdgZUhjrg8zm1kKoCEiPu3_MKieE/s320/route-exception.jpg" width="320" /></a></div>
<br />
Run your test route:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVmJRrfJxyFSMiYqV16OT6Z57lcOdSxtgQtg2Yr1T_FW3kH6NzFBPxdmXm-bdnRMHqXi3L9Uhw2BGs3GLtRTNE8yaJ68XKDLHAJJdLqHKJUlwkwtra8R-fUrP_xerjyKAATmLGlz9pUAM/s1600/route-run.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="867" data-original-width="1600" height="173" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVmJRrfJxyFSMiYqV16OT6Z57lcOdSxtgQtg2Yr1T_FW3kH6NzFBPxdmXm-bdnRMHqXi3L9Uhw2BGs3GLtRTNE8yaJ68XKDLHAJJdLqHKJUlwkwtra8R-fUrP_xerjyKAATmLGlz9pUAM/s320/route-run.jpg" width="320" /></a></div>
<br />
You can <a href="https://drive.google.com/drive/folders/1zl_JnX9heZn3jMhZRfxiuiz0dG45k3ro?usp=sharing" target="_blank">download the complete sample</a> from my google drive share.Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com3tag:blogger.com,1999:blog-5257008670669259276.post-28857311982393124522017-03-13T17:27:00.003+01:002017-03-16T10:08:13.255+01:00Username/Password Authentication with Talend ESB WebServiceIn this Blog post I'll show you how to use Username/Password authentication with a Talend ESB WebService (based on CXF) running inside a Karaf runtime. First with a UsernameToken inside the SOAP Header and second by using BasicAuthentication.<br />
<br />
<a name='more'></a><h2>
Prepare your Test Service</h2>
1.) Start Talend Studio (6.3.1)<br />
<br />
2.) Create a new Service<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhS3C7Z7CghHGf8-8Br3NimZG9riFdnzOA8mb_IHVIfnnuKkf66IxOeIwdXvp_oRTG4cKTRBSsEhjbkQ2dyXakLInmKty49s6arC4ZzpQOE4RBrkbIbTNeVRfb73SnVHqEr2Zkg_QUYFNA/s1600/01+-+Create+Service.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="185" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhS3C7Z7CghHGf8-8Br3NimZG9riFdnzOA8mb_IHVIfnnuKkf66IxOeIwdXvp_oRTG4cKTRBSsEhjbkQ2dyXakLInmKty49s6arC4ZzpQOE4RBrkbIbTNeVRfb73SnVHqEr2Zkg_QUYFNA/s200/01+-+Create+Service.png" width="200" /></a></div>
2.1) Name your Service: <b>EchoService</b><br />
2.2) Select: <b>Create new Service</b><br />
<b><br /></b>
3.) Import Schema<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQ-1qfRT6ZHaKS2XBUKjZK0Vl7XnTqHfXyZe8BBg3Zifx_AauymZdea_lGx2ZfpDDeJ2376qOOu6AmwArE3ZdMObSk7Qj_zI337VBZP4goTFOw2GGXn7YNGwgEKO1DTw9EP6koOjc37_g/s1600/02+-+Import+Schema.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQ-1qfRT6ZHaKS2XBUKjZK0Vl7XnTqHfXyZe8BBg3Zifx_AauymZdea_lGx2ZfpDDeJ2376qOOu6AmwArE3ZdMObSk7Qj_zI337VBZP4goTFOw2GGXn7YNGwgEKO1DTw9EP6koOjc37_g/s200/02+-+Import+Schema.png" width="138" /></a></div>
<br />
4.) Implement Service<br />
4.1) Assign Job to operation
<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgofAPhB-kbzUXV7bcp8NBhWrJiX8l8wIDGmRvFQzALmS5TLdZOLN8tGvocc6Dm877pm4HcRY9AI6S1a00H09GGmME8hlc0VpKrq1GY9BYbmG8_MT-2i8DiI25A0-nZQtIUWINQ90rzDBc/s1600/03+-+Assign+new+Job.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="194" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgofAPhB-kbzUXV7bcp8NBhWrJiX8l8wIDGmRvFQzALmS5TLdZOLN8tGvocc6Dm877pm4HcRY9AI6S1a00H09GGmME8hlc0VpKrq1GY9BYbmG8_MT-2i8DiI25A0-nZQtIUWINQ90rzDBc/s200/03+-+Assign+new+Job.png" width="200" /></a></div>
4.2) Select: <b>Create a new Job and Assign it to this Service Operation</b><br />
4.3) Add <b>tXMLMap</b> to your job<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBPybXqpIpCpzW-D6a-Z8XS4SQNK2WnfPr4fqpu77lYlSye4U7BLNkpVTi5tnBGz-rvTp8PnOJGtPPwDUYWPj5y_NovXMmlA_0L33ZUk5ilbAkVFvnFKO-Yff7IZxWeh-P6QCZpdAbXzA/s1600/04+-+Add+tXMLMap.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="131" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBPybXqpIpCpzW-D6a-Z8XS4SQNK2WnfPr4fqpu77lYlSye4U7BLNkpVTi5tnBGz-rvTp8PnOJGtPPwDUYWPj5y_NovXMmlA_0L33ZUk5ilbAkVFvnFKO-Yff7IZxWeh-P6QCZpdAbXzA/s320/04+-+Add+tXMLMap.png" width="320" /></a></div>
4.4) Import Schema to your input and output mapping from your repository<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNR-PJzA4zKfvTxR-4eOtkgRgxK6Q1Ih7hmQF4Iyw5ylEXvJFNQSQ_3eOgzcChDGeYHZFtzzBZe_cK5h5B9q4ybYGGWPHHDOkP70kPnOaYK4zv2utrc8QdbOo6vqgS2zbWw8lTUE5ReVQ/s1600/05+-+Import+Schema.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="175" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNR-PJzA4zKfvTxR-4eOtkgRgxK6Q1Ih7hmQF4Iyw5ylEXvJFNQSQ_3eOgzcChDGeYHZFtzzBZe_cK5h5B9q4ybYGGWPHHDOkP70kPnOaYK4zv2utrc8QdbOo6vqgS2zbWw8lTUE5ReVQ/s320/05+-+Import+Schema.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKY09T-Fq5FBbHBkWymZuFjm2g7EyG8AkyUwwr4N07ZG1UqVi1xVPrJkp8px-MkmgOta0QN8zfXfavVCkIkIm8xcZwg4ulTja4pBT04_ixdTRXH3YdOgKTipZ5mjqYoDdzxNvTXonUUp0/s1600/06+-+Select+Schema.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="198" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKY09T-Fq5FBbHBkWymZuFjm2g7EyG8AkyUwwr4N07ZG1UqVi1xVPrJkp8px-MkmgOta0QN8zfXfavVCkIkIm8xcZwg4ulTja4pBT04_ixdTRXH3YdOgKTipZ5mjqYoDdzxNvTXonUUp0/s200/06+-+Select+Schema.png" width="200" /></a></div>
4.5) Define your mapping<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVEotDdCD31dGAYaSw7aGETi2fjeWJKHyU7lb8-qymtiUjDnqx3g18I3udGENDD8CiE46SgMH2uuorgGmWnXw0TaYxRF4GREN0Q35wwczU3q8yA91RL-jcGNl_VfJnxN1g71dYDlVkq3g/s1600/07+-+Define+Mapping.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="175" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVEotDdCD31dGAYaSw7aGETi2fjeWJKHyU7lb8-qymtiUjDnqx3g18I3udGENDD8CiE46SgMH2uuorgGmWnXw0TaYxRF4GREN0Q35wwczU3q8yA91RL-jcGNl_VfJnxN1g71dYDlVkq3g/s320/07+-+Define+Mapping.png" width="320" /></a></div>
<br />
5.) Test your Service<br />
5.1) Run your Service inside Studio
<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaROrnz9cnljoWbudIPq3DnfX-TmnXJrPoo78HdDfEw60JyhukswrEpVQnbBLV0aUknN06DyzNPFjxb9BbBNWcFbILeB5zfuIRTR-JvvQSd1_j8TyAuaa0QGnN_1J4gUvw4fUJoywkxh0/s1600/08+-+Run+your+Service.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="209" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaROrnz9cnljoWbudIPq3DnfX-TmnXJrPoo78HdDfEw60JyhukswrEpVQnbBLV0aUknN06DyzNPFjxb9BbBNWcFbILeB5zfuIRTR-JvvQSd1_j8TyAuaa0QGnN_1J4gUvw4fUJoywkxh0/s320/08+-+Run+your+Service.png" width="320" /></a></div>
5.2) Send a Test Request (for example with SoapUI) to your service at http://localhost:8090/services/EchoService<br />
<pre class="brush: xml"><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://www.talend.org/service/">
<soapenv:Header/>
<soapenv:Body>
<ser:EchoServiceOperationRequest>
<in>Hello World!</in>
</ser:EchoServiceOperationRequest>
</soapenv:Body>
</soapenv:Envelope></pre>
You should get the following response:
<br />
<pre class="brush: xml"><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<tns:EchoServiceOperationResponse xmlns:tns="http://www.talend.org/service/">
<out>Hello World!</out>
</tns:EchoServiceOperationResponse>
</soap:Body>
</soap:Envelope>
</pre>
<h2>
UsernameToken Authentication</h2>
1.) Active Username /Passwort ESB Runtime Option<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAV-5pVcqp64xIR4qD723TW-EZOXzck9uWO6YZegBw_k_ZAbeyfoYZfzC6vl2NDIhJqicnz7QLOH5zqbihxIZDRrBAEMrK10Sh3PmXwTUMcLyTnIPDE5Bi1Xt-M6EAhG0nDLrN3YDotHU/s1600/09+-+ESB+Runtime+Options.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAV-5pVcqp64xIR4qD723TW-EZOXzck9uWO6YZegBw_k_ZAbeyfoYZfzC6vl2NDIhJqicnz7QLOH5zqbihxIZDRrBAEMrK10Sh3PmXwTUMcLyTnIPDE5Bi1Xt-M6EAhG0nDLrN3YDotHU/s200/09+-+ESB+Runtime+Options.png" width="150" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgli5GZ9Vwa3-Hg_e6EUFOxFiyHM2WICiKghlo0rDZyz3N37Te4PD2dhZadwX1VMsYEkxgE0XotQud1IlRvN53RJsV_4nK5Elw1EfdD8XvNlhznUVDPJ5Q1op1xLONZrUz8xeSfk8VfnuI/s1600/10+-+Enable+UsernameToken.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgli5GZ9Vwa3-Hg_e6EUFOxFiyHM2WICiKghlo0rDZyz3N37Te4PD2dhZadwX1VMsYEkxgE0XotQud1IlRvN53RJsV_4nK5Elw1EfdD8XvNlhznUVDPJ5Q1op1xLONZrUz8xeSfk8VfnuI/s200/10+-+Enable+UsernameToken.png" width="135" /></a></div>
2.) Export Service to Runtime<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQUosgZ2IBc24B-I8lXTYqA-gcQ7M3CDr4pmDSqTo83pEhkR8jpFJTNZzTP7hBW1gc-gEEp6bIFT3SV7WXaROR7V5XIqnftFd1NQhgDzXhXohM3kcZZ1Q3KvCufx9xIyl73LppG2bWSOw/s1600/11+-+Export+Service.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQUosgZ2IBc24B-I8lXTYqA-gcQ7M3CDr4pmDSqTo83pEhkR8jpFJTNZzTP7hBW1gc-gEEp6bIFT3SV7WXaROR7V5XIqnftFd1NQhgDzXhXohM3kcZZ1Q3KvCufx9xIyl73LppG2bWSOw/s200/11+-+Export+Service.png" width="153" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPBKhxnCDLrbF8Wgtfz78ajNUudT3wji6vZ54IVOIYuetzQmvC1g28O5N-ceXsgvM0s42quBVAaQQ3dFjNiSuoYvVUzxlXzoA6HKOdN7GHyB577RaInVtcd903qlRBnE5qIxinyt8szZk/s1600/12+-+Export+Location.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="164" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPBKhxnCDLrbF8Wgtfz78ajNUudT3wji6vZ54IVOIYuetzQmvC1g28O5N-ceXsgvM0s42quBVAaQQ3dFjNiSuoYvVUzxlXzoA6HKOdN7GHyB577RaInVtcd903qlRBnE5qIxinyt8szZk/s200/12+-+Export+Location.png" width="200" /></a></div>
3.) Start Runtime<br />
<pre class="brush: bash">C:\Talend\6.3.1\runtime\bin\trun.bat
</pre>
<a href="https://localhost:9001/services/EchoService?wsdl">https://localhost:9001/services/EchoService?wsdl</a><br />
<br />
4.) Send a Test Request (for example with SoapUI) to your service at https://localhost:9001/services/EchoService<br />
<pre class="brush: xml"><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://www.talend.org/service/">
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="uuid_faf0159a-6b13-4139-a6da-cb7b4100c10c">
<wsse:Username>karaf</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">karaf</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<ser:AttendeeLookupOperationRequest>
<in>Hello</in>
</ser:AttendeeLookupOperationRequest>
</soapenv:Body>
</soapenv:Envelope></pre>
You should get the following response:
<br />
<pre class="brush: xml"><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<tns:EchoServiceOperationResponse xmlns:tns="http://www.talend.org/service/">
<out>Hello World!</out>
</tns:EchoServiceOperationResponse>
</soap:Body>
</soap:Envelope>
</pre>
<h2>
Basic Authentication</h2>
1.) Disable Username/Password Authentication from previous step above.<br />
2.) Modify wsdl file by adding a <code>HttpBasicAuthentication</code> policy assertion<br />
<a href="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/ws-securitypolicy-1.2-spec-os.html#_HttpsToken_Assertion">http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/ws-securitypolicy-1.2-spec-os.html#_HttpsToken_Assertion</a> <br />
<pre class="brush: xml"><?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions name="EchoService"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://www.talend.org/service/"
xmlns:wsp="http://www.w3.org/ns/ws-policy"
targetNamespace="http://www.talend.org/service/">
<wsdl:types>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.talend.org/service/">
<xsd:element name="EchoServiceOperationRequest">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="in" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="EchoServiceOperationResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="out" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</wsdl:types>
<wsdl:message name="EchoServiceOperationRequest">
<wsdl:part name="parameters" element="tns:EchoServiceOperationRequest"/>
</wsdl:message>
<wsdl:message name="EchoServiceOperationResponse">
<wsdl:part name="parameters" element="tns:EchoServiceOperationResponse"/>
</wsdl:message>
<wsdl:portType name="EchoServicePortType">
<wsdl:operation name="EchoServiceOperation">
<wsdl:input message="tns:EchoServiceOperationRequest"/>
<wsdl:output message="tns:EchoServiceOperationResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="EchoServiceBinding" type="tns:EchoServicePortType">
<wsp:PolicyReference URI="#BasicAuthPolicy"/>
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="EchoServiceOperation">
<soap:operation soapAction="http://www.talend.org/service/EchoServiceOperation" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="EchoService">
<wsdl:port name="EchoServicePort" binding="tns:EchoServiceBinding">
<soap:address location="http://localhost:8090/services/EchoService" />
</wsdl:port>
</wsdl:service>
<wsp:Policy xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="BasicAuthPolicy">
<wsp:ExactlyOne>
<wsp:All>
<sp:TransportBinding xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<sp:TransportToken>
<wsp:Policy>
<sp:HttpsToken>
<wsp:Policy>
<sp:HttpBasicAuthentication/>
</wsp:Policy>
</sp:HttpsToken>
</wsp:Policy>
</sp:TransportToken>
<sp:Layout>
<wsp:Policy>
<sp:Lax/>
</wsp:Policy>
</sp:Layout>
<sp:AlgorithmSuite>
<wsp:Policy>
<sp:Basic128/>
</wsp:Policy>
</sp:AlgorithmSuite>
</wsp:Policy>
</sp:TransportBinding>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
</wsdl:definitions></pre>
3.) (Re)Deploy Webservice to runtime<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiccRZjhUonIebB9gEPe0zCMn2krPR2BDTB4gTjPVtk2hd3CF0BZgeEBbQMMPjk64BpHw8QGOw2LqufsY-CU6X31r6dTGWJT41ZR61_GG2Ef5M5Rekc3FiyMSUK_k21LPAMdFnBCjv8lKY/s1600/11+-+Export+Service.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiccRZjhUonIebB9gEPe0zCMn2krPR2BDTB4gTjPVtk2hd3CF0BZgeEBbQMMPjk64BpHw8QGOw2LqufsY-CU6X31r6dTGWJT41ZR61_GG2Ef5M5Rekc3FiyMSUK_k21LPAMdFnBCjv8lKY/s200/11+-+Export+Service.png" width="153" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1ThAEQKcyfd4cQwJn9EQY9QBfY6pZeyFRiYCpJhrkTWJwRhlkj7ZgJXnENFUprcD6C33jHezYtr-KVlbAL3c4HmJ0vBXrALCAN1_DNrzkYTt61GVEsU4gGu_QZ3nNZidtLQFaaCLCkEs/s1600/12+-+Export+Location.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="164" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1ThAEQKcyfd4cQwJn9EQY9QBfY6pZeyFRiYCpJhrkTWJwRhlkj7ZgJXnENFUprcD6C33jHezYtr-KVlbAL3c4HmJ0vBXrALCAN1_DNrzkYTt61GVEsU4gGu_QZ3nNZidtLQFaaCLCkEs/s200/12+-+Export+Location.png" width="200" /></a></div>
<br />
4.) Send a Test Request (for example with Postman) to your service with karaf:karaf credentials at https://localhost:9001/services/EchoService<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinB96iOxeDD9bOcCOwbqcf9LCJ35kw4GvoHf6m3u1sHL53DMxU7L_ljHiI8OTsPp7bV7DXLOXEwP8cDksvTh_geJCG_Sb_kxtoMWNwumyWDBN1RvjvQAv1fz-c8KQQ7Sid2fX20gC4nBA/s1600/13+-+Basic+Authentication+Header.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="77" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinB96iOxeDD9bOcCOwbqcf9LCJ35kw4GvoHf6m3u1sHL53DMxU7L_ljHiI8OTsPp7bV7DXLOXEwP8cDksvTh_geJCG_Sb_kxtoMWNwumyWDBN1RvjvQAv1fz-c8KQQ7Sid2fX20gC4nBA/s320/13+-+Basic+Authentication+Header.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6wISdcntbJ7TjpWtgTW02OohukZRFM5xxOeawgmLq_KTjnagrTo165f36ljar7Jee_Ug3rJX5zgzNz_ZAYc_55JPwyTFV0j2kOsOyvJm6JpsYxXOGDdW91NisIvvq0SNiK9CFMqGs1Zc/s1600/13+-+Test+Message.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="93" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6wISdcntbJ7TjpWtgTW02OohukZRFM5xxOeawgmLq_KTjnagrTo165f36ljar7Jee_Ug3rJX5zgzNz_ZAYc_55JPwyTFV0j2kOsOyvJm6JpsYxXOGDdW91NisIvvq0SNiK9CFMqGs1Zc/s320/13+-+Test+Message.png" width="320" /></a></div>
<div class="text-alert">After some further testing I discovered that actually no JAAS realm is involved in the Basic Authentication process. So your credentials will not be validated. The WS-Security Assertion only ensures that a Basic Authentication header is present in the request. But any username/password will be accepted. I'll do some further research to understand why this is happening and hopefully find a solution to ensure credential validation. Until then, I cannot recommend using Basic Authentication for Studio generated Jobs. </div>
<h3>
Runtime JAAS Configuration</h3>
The reason why <code>karaf:karaf</code> are valid credentials is, that the runtime uses a default JAAS realm which points to a configuration file containing several users.<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicMuFQhY9BOHAMyq02tNp44o9CtPvhc0g7Aeue_Gy8c7vC71cfPBELOy3PQ81r0brxS2WyrhsPYdB2VCIquYrhSKx2sfmUwjFSmlj1qHbIeY27Mf6WGeJdnPLTzxgKgChqbd8-i_hh0lw/s1600/14+-+JAAS+Modules.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="99" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicMuFQhY9BOHAMyq02tNp44o9CtPvhc0g7Aeue_Gy8c7vC71cfPBELOy3PQ81r0brxS2WyrhsPYdB2VCIquYrhSKx2sfmUwjFSmlj1qHbIeY27Mf6WGeJdnPLTzxgKgChqbd8-i_hh0lw/s320/14+-+JAAS+Modules.png" width="320" /></a></div>
<code>C:\Talend\6.3.1\runtime\etc\users.properties</code>
<br />
<pre class="brush: bash">tadmin=tadmin,_g_:admingroup,sl_admin
tesb=tesb,_g_:admingroup,sl_maintain
karaf = karaf,_g_:admingroup
_g_\:admingroup = group,admin,manager,viewer,systembundles
</pre>
Inside the container Jetty is responsible for the HTTP transport Basic Authentication. And inside the jetty configuration <code>karaf</code> is defined as the default JAAS realm:
<code>C:\Talend\6.3.1\runtime\etc\jetty.xml</code>
<br />
<pre class="brush: xml"><Configure id="Server" class="org.eclipse.jetty.server.Server">
. . .
<Call name="addBean">
<Arg>
<New class="org.eclipse.jetty.jaas.JAASLoginService">
<Set name="name">default</Set>
<Set name="loginModuleName">karaf</Set>
<Set name="roleClassNames">
<Array type="java.lang.String">
<Item>org.apache.karaf.jaas.boot.principal.RolePrincipal</Item>
</Array>
</Set>
</New>
</Arg>
</Call>
</Configure></pre>
Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com3tag:blogger.com,1999:blog-5257008670669259276.post-50102460343388396752017-02-06T15:06:00.000+01:002017-03-13T16:15:13.989+01:00Kerberos Debugging in JavaWorking with Kerberos can easily cause a lot of trouble. Troubleshooting can take several hours.<br />
In this blog I'll show you what will help you best when using Kerberos with Java for example to secure a Hadoop cluster.<br />
<br />
When Kerberos is not working as expected it is important to understand why. Enabling Kerberos debug logging is a very valuable resource to understand what is happening.<br />
To enable Kerberos debugging you need to set the following JVM property:<br />
<pre class="brush: bash">-Dsun.security.krb5.debug=true
</pre>
Now read your log file very carefully. This will help you to understand what is missing.<br />
<br />
Usually you will define your Kerberos configuration within your <code>C:\Windows\krb5.ini</code> or <code>/etc/krb5.conf</code> file. Make sure that your hostname mapping to your Kerberos realm is correct in here.<br />
There are also a few other JVM properties that are usually not required, but can be useful to override/define your configuration at application startup:<br />
<pre class="brush: bash">-Djava.security.krb5.kdc=hostname.of-your.kerberos.server
-Djava.security.krb5.realm=YOUR.KERBEROS.REALM
-Djava.security.auth.login.config=file:/C:/Programme/Tomcat-IDP/conf/kerberos.jaas
</pre>
<div class="text-tip">
Kerberos is very sensitive to DNS configuration.</div>
<br />
Here are some more shell commands that are very helpful to test if Kerberos is working in general (outside of your Java application):
<br />
<pre class="brush: bash"># Login with a specific keytab file
kinit -k -t /path/to/your/keytab
# List all local available tokens. After kinit there should be at least your tgt token.
klist
# Request a ticket for a specific service. Check if the service is registered correctly at your Kerberos server.
kvno service/hostname@domain
</pre>
<a href="https://web.mit.edu/kerberos/krb5-1.12/doc/user/user_commands/kvno.html" target="_blank">https://web.mit.edu/kerberos/krb5-1.12/doc/user/user_commands/kvno.html</a><br />
<br />
<a name='more'></a>Here is a sample configuration for your <code>krb5.ini</code> file:<br />
<pre class="brush: bash">[libdefaults]
default_realm = HORTONWORKSHA.COM
dns_lookup_kdc = false
dns_lookup_realm = false
ticket_lifetime = 86400
renew_lifetime = 604800
forwardable = true
default_tgs_enctypes = rc4-hmac
default_tkt_enctypes = rc4-hmac
permitted_enctypes = rc4-hmac
udp_preference_limit = 1
kdc_timeout = 3000
[realms]
CLOUDERAHA.COM = {
kdc = talend.cloudera57
admin_server = talend.cloudera57
}
HORTONWORKSHA.COM = {
kdc = hdp24masternode
admin_server = hdp24masternode
}
[domain_realm]
.hortonworksha.com = HORTONWORKSHA.COM
hortonworksha.com = HORTONWORKSHA.COM
.clouderaha.com = CLOUDERAHA.COM
clouderaha.com = CLOUDERAHA.COM</pre>
<br />
And here is another example for a JAAS configuration file (first for a normal user and second for a technical service account):
<br />
<pre class="brush: bash">alice {
com.sun.security.auth.module.Krb5LoginModule required
refreshKrb5Config=true
debug=true
principal="alice";
};
sts {
com.sun.security.auth.module.Krb5LoginModule required
debug=true
refreshKrb5Config=true
useKeyTab=true
storeKey=true
keyTab="file:c:/Users/jbernhardt/workspace/kerberos/sts.keytab"
principal="sts/tal-csg01";
};</pre>
<br />
If you want to define the location for your cached tickets, set the following system property accordingly:<br />
<pre class="brush: bash"># Windows Style
set KRB5CCNAME="C:\Users\jbernhardt\krb5cc_jbernhardt"
# Linux Style
export KRB5CCNAME="/home/jbernhardt/krb5cc_jbernhardt"</pre>
<br />
Sample Java Code:
<br />
<pre class="brush: java">package test;
import java.io.IOException;
import java.net.URL;
import java.security.Principal;
import java.util.Set;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
public class JaasLoginTest {
public static void main(String argv[]) {
URL conf = JaasLoginTest.class.getClassLoader().getResource("jaas.conf");
System.setProperty("java.security.auth.login.config", conf.toString());
System.setProperty("java.security.krb5.realm", "TEST.TALEND.DE");
System.setProperty("java.security.krb5.kdc", "192.168.0.100");
System.setProperty("sun.security.krb5.debug", "true");
// Only needed when not using the ticket cache
CallbackHandler callbackHandler = new CallbackHandler() {
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (Callback callback : callbacks) {
if (callback instanceof NameCallback) {
((NameCallback)callback).setName("alice");
}
if (callback instanceof PasswordCallback) {
((PasswordCallback)callback).setPassword("password".toCharArray());
}
}
}
};
try {
LoginContext lc = new LoginContext("alice", callbackHandler);
// LoginContext lc = new LoginContext("sts", callbackHandler);
lc.login();
Subject subject = lc.getSubject();
Set<Principal> principals = subject.getPrincipals();
Set<Object> credentials = subject.getPrivateCredentials();
System.out.println("OK: " + principals);
System.out.println("OK: " + credentials);
} catch (LoginException e) {
e.printStackTrace();
}
}
}
</pre>
<h3>
Useful Links</h3>
<div>
<ol>
<li><a href="https://technet.microsoft.com/en-us/library/cc961976.aspx" target="_blank">Basic Concepts for the Kerberos Protocol</a></li>
<li><a href="https://technet.microsoft.com/en-us/library/cc772815(v=ws.10).aspx" target="_blank">How the Kerberos Version 5 Authentication Protocol Works</a></li>
<li><a href="http://www.zeroshell.org/kerberos/Kerberos-cross-authentication/" target="_blank">Kerberos Cross Authentication</a></li>
</ol>
</div>
Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com1tag:blogger.com,1999:blog-5257008670669259276.post-88911514960735263012016-09-22T14:43:00.000+02:002016-09-22T14:44:10.991+02:00How to enable Fediz Plugin LoggingIf you are using the <a href="http://cxf.apache.org/fediz.html" target="_blank">Apache Fediz</a> plugin to enable WS-Federation Support for your Tomcat container, you will not see any log statements from the Fediz Plugin by default. Especially when testing or analyzing issues with the plugin you will be interested in actually seeing some log statements from the plugin.<br />
<br />
In this blog post I'll explain to you what need to be done to get all DEBUG log level statements from the Apache Fediz Tomcat Plugin using Log4J.<br />
<a name='more'></a>Apache Tomcat tells you how to <a href="http://tomcat.apache.org/tomcat-7.0-doc/logging.html#Using_Log4j" target="_blank">enable logging</a> on the container level.<br />
<h3>
1. Adding Dependencies</h3>
First you need to ensure that the required libraries are available within your classpath. This can be done in one of two ways:<br />
<h4>
a) Adding Maven Dependencies to the Fediz Tomcat Plugin</h4>
Add the following dependency to <code>cxf-fediz/plugins/tomcat7/pom.xml</code>:
<br />
<pre class="brush: xml"><project . . .>
. . .
<dependencies>
<dependency>
<groupid>org.slf4j</groupid>
<artifactid>slf4j-log4j12</artifactid>
<version>${slf4j.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
. . .
</project>
</pre>
Now build the plugin again <code>mvn clean package</code> and deploy the content of <code>cxf-fediz/plugins/tomcat7/target/fediz-tomcat7-1.3.0-zip-with-dependencies.zip</code> into your <code>tomcat/lib/fediz</code> folder.
<br />
<h4>
b) Adding lib files directly to your lib folder</h4>
Add slf4j and log4j libs (in the desired version) to your fediz plugin dependencies:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgM6SlPsxGdEzgwQR3gzH1SHR1iYd0MSE3L5jT55hFDM4fRFYEACBHyuJxTNZkQjO6z29q3XtlWx2Q9uGzZJtJqX7qTjigV7_USPw-Ee4NcDWhDOOaSriQwpLYGQjH56iqe0o2LnjsuMUk/s1600/slf4j-log4j.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgM6SlPsxGdEzgwQR3gzH1SHR1iYd0MSE3L5jT55hFDM4fRFYEACBHyuJxTNZkQjO6z29q3XtlWx2Q9uGzZJtJqX7qTjigV7_USPw-Ee4NcDWhDOOaSriQwpLYGQjH56iqe0o2LnjsuMUk/s320/slf4j-log4j.PNG" width="271" /></a></div>
<h3>
2. Adding Log4J configuration file</h3>
Once your dependencies are added to your Tomcat installation, you need to add a <code>log4j.properties</code> file to your <code>tomcat/lib</code> folder. Here is an example content for this file:<br />
<pre class="brush: bash"># Loggers
log4j.rootLogger = WARN, CATALINA, CONSOLE
log4j.logger.org.apache.cxf.fediz = DEBUG, CONSOLE, FEDIZ
log4j.additivity.org.apache.cxf.fediz = false
# Appenders
log4j.appender.CATALINA = org.apache.log4j.DailyRollingFileAppender
log4j.appender.CATALINA.File = ${catalina.base}/logs/catalina.out
log4j.appender.CATALINA.Append = true
log4j.appender.CATALINA.Encoding = UTF-8
log4j.appender.CATALINA.DatePattern = '.'yyyy-MM-dd
log4j.appender.CATALINA.layout = org.apache.log4j.PatternLayout
log4j.appender.CATALINA.layout.ConversionPattern = %d [%t] %-5p %c %x - %m%n
log4j.appender.FEDIZ = org.apache.log4j.DailyRollingFileAppender
log4j.appender.FEDIZ.File = ${catalina.base}/logs/fediz-plugin.log
log4j.appender.FEDIZ.Append = true
log4j.appender.FEDIZ.Encoding = UTF-8
log4j.appender.FEDIZ.Threshold = DEBUG
log4j.appender.FEDIZ.DatePattern = '.'yyyy-MM-dd
log4j.appender.FEDIZ.layout = org.apache.log4j.PatternLayout
log4j.appender.FEDIZ.layout.ConversionPattern = %d [%t] %-5p %c %x - %m%n
log4j.appender.CONSOLE = org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Encoding = UTF-8
log4j.appender.CONSOLE.Threshold = INFO
log4j.appender.CONSOLE.layout = org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern = %d [%t] %-5p %c %x - %m%n
</pre>
<br />
Now restart your tomcat container and you will see Fediz <code>Info</code> logs on your <code>console</code> and <code>Debug</code> messages within <code>tomcat/logs/fediz-plugin.log</code>.
Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com2tag:blogger.com,1999:blog-5257008670669259276.post-86616618508949500852016-09-01T13:12:00.000+02:002016-09-02T12:04:30.914+02:00Syncope User Synchronisation with a DatabaseIn a <a href="http://janbernhardt.blogspot.de/2016/07/karaf-jdbc-jaas-module_20.html">previous post</a> I explained how to setup a datasource for an embedded H2 database and how to use it with the Karaf DB JAAS plugin.<br />
<br />
In this post, I'll explain to you how to setup Syncope to synchronize users from that database into syncope. Of course you can also use any other database with a matching JDBC driver.<br />
<a name='more'></a><h3>
Install Syncope</h3>
In this post I'll refer to the Syncope Installation which comes with the Talend 6.1.1 installer. If you need to setup Syncope manually, please take a look at some <a href="http://coheigea.blogspot.de/2013/07/apache-syncope-tutorial-part-i_26.html" target="_blank">posts from Colm</a>.<br />
<h3>
Setup DB Connection Module</h3>
<div class="text-info">
According to some <a href="http://syncope-user.1051894.n5.nabble.com/Role-Synchronization-with-DB-Backend-possible-td5708656.html" target="_blank">feedback</a> from the Syncope community, it is recommended to use a <a href="https://cwiki.apache.org/confluence/display/SYNCOPE/Configure+a+Scripted+SQL+resource" target="_blank">Scripted SQL connectors</a> instead of the database connector which is used in this blog post.</div>
<br />
<a href="https://cwiki.apache.org/confluence/display/SYNCOPE/Configure+a+Database+resource" target="_blank">Syncope</a> uses <a href="https://github.com/Tirasa/ConnId/blob/master/README.md#available-connectors" target="_blank">connid</a> to connect to other backend systems like LDAP.<br />
You need to download the <a href="https://github.com/Tirasa/ConnIdDBBundle/releases/download/db-2.2.4/net.tirasa.connid.bundles.db.table-2.2.4.jar" target="_blank">DB connid bundle</a> and follow the <a href="https://cwiki.apache.org/confluence/display/SYNCOPE/Install+connector+bundles" target="_blank">installation instructions</a>.<br />
<ol>
<li>Open <code>webapps/syncope/WEB-INF/classes/connid.properties</code> and define your connid bundle location:<br /><b>Windows Style:</b>
<pre class="brush: bash">connid.locations=file:/C:/Talend/6.1.1/apache-tomcat/webapps/syncope/WEB-INF/connid/</pre>
<b>Linux Style:</b>
<pre class="brush: bash">connid.locations=file:/opt/Talend-6.1.1/apache-tomcat/webapps/syncope/WEB-INF/connid/</pre>
</li>
<li>Create the defined folder and copy your downloaded connid bundle (jar) into it</li>
<li>Download and copy your required JDBC driver to your <code>tomcat/lib</code> folder</li>
<li>Restart Syncope / Tomcat</li>
<li>Login to Syncope Console: <a href="http://localhost:8080/syncope-console/">http://localhost:8080/syncope-console/</a> <br />Default-Username: <code>admin</code><br />Default-Password: <code>password</code></li>
</ol>
<h4>
Setup DB Connector</h4>
Next you need to setup a connection to your database, before you can define any synchronization pattern.
<br />
<ol>
<li>Switch to Resources -> Connectors and click Create</li>
<li>Enter your connection name and select your connid bundle:
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYIGKB4IkREIq6Bm4x4IJSvlB8Jmt-thy2J9j_nvsGSHkrf8AcKTw_3FEMdQiRX2GX-XBd0AaSBescbIQCNd9clxfQkSr8E2XF1Qv9RXNO4qFB_uO2yubdTto6LC5QUr6MCg9cvBzTx2I/s1600/Syncope-Connector-1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="210" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYIGKB4IkREIq6Bm4x4IJSvlB8Jmt-thy2J9j_nvsGSHkrf8AcKTw_3FEMdQiRX2GX-XBd0AaSBescbIQCNd9clxfQkSr8E2XF1Qv9RXNO4qFB_uO2yubdTto6LC5QUr6MCg9cvBzTx2I/s400/Syncope-Connector-1.jpg" width="400" /></a></div>
</li>
<li>Configure your connection settings:
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5QeTQ8BB87YML3BxYPdQHcwS-kVSZYhVH-2XGIheuXcnuH73OpGaN2xZfnlFNIPbtgo3PVxYdqGinWNhktYyiHs16f1ILYZtzbXjpI-zGSJpj2wmgTRLzyL1B3_9DYAh2PTGtlzfQx-c/s1600/Syncope-Connector-2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5QeTQ8BB87YML3BxYPdQHcwS-kVSZYhVH-2XGIheuXcnuH73OpGaN2xZfnlFNIPbtgo3PVxYdqGinWNhktYyiHs16f1ILYZtzbXjpI-zGSJpj2wmgTRLzyL1B3_9DYAh2PTGtlzfQx-c/s400/Syncope-Connector-2.jpg" width="315" /></a></div>
<br /><div class="text-tip">
Since Syncope expects SHA1 hashes to be Uppercase you must set this checkbox, or otherwise your users will not be able to authenticate against syncope with their synchronized password.<br />
<br />
Since Syncope 1.2 and newer it will also be possible to avoid user password synchronization, but instead to do a "<a href="https://ci.apache.org/projects/syncope/reference-guide.html#pass-through-authentication" target="_blank">pass-through authentication</a>". This will be especially helpful if your passwords are not just hashed but also salted and encrypted.</div>
<br />
</li>
<li>Perform a connection test by clicking on the top right world icon of the configuration tab<br />
<br />
<div class="text-tip">
If you are experiencing connection problems, take a look into the <code>tomcat/logs/core-connid.log</code> file for detailed information.
</div>
<br />
</li>
<li>Select all checkboxes on the capabilities tab:</li>
<li>Save your connection</li>
</ol>
<ol>
</ol>
<h4>
Define DB Resource </h4>
Now you can setup a new resource to define the attribute matching from syncope internal DB and external DB.
<br />
<ol>
<li>Click on Resources -> Resources -> Create<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieX9V7hFsSd9_iuF22KsYMRLltfKoJip6-Inn8y3gRd5nJXKJO6fZI9I9WmI7ZxvTcwT_bBOuKdL_WuljvnhPA4KN-WDcCixD1e-zKkKiLquDJalaGvSJZljpiQFJP-eH-bxa93FBplJY/s1600/Syncope-Connector-5.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="188" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieX9V7hFsSd9_iuF22KsYMRLltfKoJip6-Inn8y3gRd5nJXKJO6fZI9I9WmI7ZxvTcwT_bBOuKdL_WuljvnhPA4KN-WDcCixD1e-zKkKiLquDJalaGvSJZljpiQFJP-eH-bxa93FBplJY/s320/Syncope-Connector-5.jpg" width="320" /></a></div>
</li>
<li> Switch to user mapping tab<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhL-HwFgu6ur2QezZ-GcYqrlQ5nnogTM8Ntc9Y3MYWK5oNKUPSiw9bEB5182h1QkKYVHgOZ3yK8Glf9NDf8wgBWiiN5mNe0kw73LFFCZ1-57tNs5EhLbw2r-soOUalM-dHhU5D39N037KY/s1600/Syncope-Connector-6.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="186" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhL-HwFgu6ur2QezZ-GcYqrlQ5nnogTM8Ntc9Y3MYWK5oNKUPSiw9bEB5182h1QkKYVHgOZ3yK8Glf9NDf8wgBWiiN5mNe0kw73LFFCZ1-57tNs5EhLbw2r-soOUalM-dHhU5D39N037KY/s320/Syncope-Connector-6.jpg" width="320" /></a></div>
</li>
<li>Click Save</li>
</ol>
<h4>
Add Synchronization Task </h4>
To import users from your database you need to setup a synchronization task.<br />
<ol>
<li>Click on Task -> Synchronization Tasks -> Create<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5A6tnEhTfgOfFi-6oiYBe4_5Iti0pZwfhzqR_vRpE-PP_NGZOz8MPko1Ev3nFXHgMStt75ifWiGTVomxTKxY1AlpzGCoX1pUpXwQ8XLIJxfnES95Zh-uMfS2Ry2kHUOauwZCaNvl5I9A/s1600/Syncope-Connector-7.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="284" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5A6tnEhTfgOfFi-6oiYBe4_5Iti0pZwfhzqR_vRpE-PP_NGZOz8MPko1Ev3nFXHgMStt75ifWiGTVomxTKxY1AlpzGCoX1pUpXwQ8XLIJxfnES95Zh-uMfS2Ry2kHUOauwZCaNvl5I9A/s320/Syncope-Connector-7.jpg" width="320" /></a></div>
</li>
<li>Click Save</li>
<li>Execute your new synchronization task<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfFpr2Qy-GEwSMcfR-R9A9_yCIF3JHU3Ei_z3s4gMLoaPgoQhiCZzQ1RsnBntgxCQgY03BwBGwGDwThezNGVEeYk8Szwd7MZQBWQa4EErBIOrk2UP35C-z_cvvMzspZIGjcuiskJRccFg/s1600/Syncope-Connector-8.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="73" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfFpr2Qy-GEwSMcfR-R9A9_yCIF3JHU3Ei_z3s4gMLoaPgoQhiCZzQ1RsnBntgxCQgY03BwBGwGDwThezNGVEeYk8Szwd7MZQBWQa4EErBIOrk2UP35C-z_cvvMzspZIGjcuiskJRccFg/s400/Syncope-Connector-8.jpg" width="400" /></a></div>
</li>
</ol>
<ol>
</ol>
If your run was successful you will see alice as a new user under Users.<br />
<h4>
Create a new User</h4>
To test user propagation, you must create a new user and add this user to the H2-users Resource.<br />
<ol>
<li>Click Users -> List -> Create<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCAKpnAUSN1TnQEEGeUTXIWMLj6PLQtzYP_HapYUZL9d1BVFas3mZDBfmeeyJs-hloo0IpLvLd7WAYwdR0TQAHht1gb_IK2WNRCWcCkK56GpP8MqKc2En-vjT9IDUmAB9lHP5NHMXzsfg/s1600/Syncope-Connector-9.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="239" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCAKpnAUSN1TnQEEGeUTXIWMLj6PLQtzYP_HapYUZL9d1BVFas3mZDBfmeeyJs-hloo0IpLvLd7WAYwdR0TQAHht1gb_IK2WNRCWcCkK56GpP8MqKc2En-vjT9IDUmAB9lHP5NHMXzsfg/s320/Syncope-Connector-9.jpg" width="320" /></a></div>
<span id="goog_628506666"></span><span id="goog_628506667"></span></li>
<li>Select Resource<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj57qSF4Udps61F6L8y4dJrfZMUkofgiJpWGcOCIVOceorREefw8hut1ROQmAYkCt4nUWt-hetwRf0o618-m_GwMS0hvpHSucvoCmR5wIOQpQ2dGkyOZS9YkuPyUVnlhvqS0m_qcWwZMGk/s1600/Syncope-Connector-10.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="239" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj57qSF4Udps61F6L8y4dJrfZMUkofgiJpWGcOCIVOceorREefw8hut1ROQmAYkCt4nUWt-hetwRf0o618-m_GwMS0hvpHSucvoCmR5wIOQpQ2dGkyOZS9YkuPyUVnlhvqS0m_qcWwZMGk/s320/Syncope-Connector-10.jpg" width="320" /></a></div>
</li>
<li>Save<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiu7hRzPQ7yIyHPyOZ9sqlFlqRhrGT_GLMblCfRFlZTVowOaJW1rGVUbwy-caV804Qh-N1exn-W52UKwEgl-orIlXIsZscF6ibO2WZ29HJI2uHoSDBLaokoUlyRTq__HuOxPuGWnHzRVxs/s1600/Syncope-Connector-11.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="237" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiu7hRzPQ7yIyHPyOZ9sqlFlqRhrGT_GLMblCfRFlZTVowOaJW1rGVUbwy-caV804Qh-N1exn-W52UKwEgl-orIlXIsZscF6ibO2WZ29HJI2uHoSDBLaokoUlyRTq__HuOxPuGWnHzRVxs/s320/Syncope-Connector-11.jpg" width="320" /></a></div>
</li>
</ol>
You will now find Bob in your H2 database.<br />
<br />
<div class="text-info">
I was not able to do a role synchronization with my DB backend, due to missing support in the UI / connid handler.</div>
Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com6tag:blogger.com,1999:blog-5257008670669259276.post-34054961033111180962016-08-29T08:56:00.000+02:002016-08-29T08:56:34.510+02:00Custom JSSE Truststore to enable XKMS Certificate ValidationRecently I was involved in a project which uses a central <a href="https://en.wikipedia.org/wiki/XKMS" target="_blank">XKMS</a> Server for certificate and trust management. This was all working fine within the Talend runtime with a custom wss4j crypto provider. However the need raised to perform client certificate validations (mutal SSL) with <a href="http://cxf.apache.org/fediz.html" target="_blank">Apache Fediz</a> running inside an <a href="http://tomcat.apache.org/" target="_blank">Apache Tomcat</a> server.<br />
<br />
<br />
Usually I would use a JKS truststore for Tomcat to add trusted certificates (CAs). However this was not possible for this project, because all certificates will be managed inside an LDAP accessible via a XKMS service. Searching for a solution to extend Tomcat to support XKMS based certificate validation I came across the <a href="http://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/JSSERefGuide.html" target="_blank">JSSE Standard</a>.<br />
<br />
<div class="firstHeading" id="firstHeading" lang="en">
Reading throw the documentation was not so straightforward and clear. But searching through the internet finally helped me to achieve my goal. In this blog post, I'll show you what I had to do, to enabled XKMS based SSL certificate validation in Tomcat. </div>
<a name='more'></a>To manage your SSL truststore settings you can use standard System or Tomcat properties:<br />
<br />
<table>
<thead>
<tr>
<th><a href="https://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/JSSERefGuide.html#Customization" target="_blank">System Properties</a></th>
<th><a href="https://tomcat.apache.org/tomcat-7.0-doc/config/http.html#SSL%20Support%20-%20BIO%20and%20NIO" target="_blank">Tomcat Properties</a></th>
<th>Purpose</th>
</tr>
</thead>
<tbody>
<tr>
<td>javax.net.ssl.trustStore</td>
<td>truststoreFile</td>
<td>System location for JKS truststore file</td>
</tr>
<tr>
<td>javax.net.ssl.trustStorePassword</td>
<td>truststorePass</td>
<td>Password for JKS truststore</td>
</tr>
<tr>
<td>javax.net.ssl.trustStoreProvider</td>
<td>truststoreProvider</td>
<td>Provider for a truststoreFactory implementation</td>
</tr>
<tr>
<td>javax.net.ssl.trustStoreType</td>
<td>truststoreType</td>
<td>Type of your truststore. Default is "JKS"</td>
</tr>
<tr>
<td>n/a</td>
<td>trustManagerClassName</td>
<td>Custom trust manager class to use to validate client certificates</td>
</tr>
</tbody></table>
<br />
Settings are considered in the following order:<br />
<ol>
<li>Tomcat truststore properties</li>
<li>System Properties</li>
<li>Tomcat keystore properties</li>
<li>Default Values </li>
</ol>
If a trustManagerClassName is set, this implementation will be used and all other truststore settings will be ignored. If a truststore provider is defined any Java standard provider will be ignored.<br />
<br />
You can review this behavior in the Tomcat <a href="http://grepcode.com/file/repo1.maven.org/maven2/org.apache.geronimo.ext.tomcat/catalina/7.0.39.2/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java" target="_blank">JSSESocketFactory</a> init method.<br />
<br />
The easiest way to achieve my goal was to implement my own <code>XKMSTrustManager</code> implementing the <code>javax.net.ssl.X509TrustManager</code> interface.<br />
<pre class="brush: java">public class XKMSTrustManager implements X509TrustManager {
private static final Logger LOG = LoggerFactory.getLogger(XKMSTrustManager.class);
private XKMSInvoker xkms;
public XKMSTrustManager() throws MalformedURLException {
XKMSService xkmsService = new XKMSService(
URI.create(System.getProperty("xkms.wsdl.location", "http://localhost:8040/services/XKMS/?wsdl"))
.toURL());
xkms = new XKMSInvoker(xkmsService.getXKMSPort());
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
LOG.debug("Check client trust for: {}", chain);
validateTrust(chain);
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
LOG.debug("Check server trust for: {}", chain);
validateTrust(chain);
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[] {};
}
protected void validateTrust(X509Certificate[] chain) throws CertificateException {
if (chain == null) {
throw new CertificateException("Certificate chain is null");
}
if (!xkms.validateCertificate(chain)) {
LOG.error("Certificate chain is not trusted: {}", chain);
throw new CertificateException("Certificate chain is not trusted");
}
}
}
</pre>
<code>Tomcat\conf\server.xml</code>
<br />
<pre class="brush: xml"><Server port="9005" shutdown="SHUTDOWN">
<Service name="Catalina">
<Connector port="9443" protocol="org.apache.coyote.http11.Http11Protocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
keystoreFile="idp-ssl-key.jks"
keystorePass="tompass"
trustManagerClassName="org.talend.ws.security.jsse.XKMSTrustManager"
clientAuth="true"
sslProtocol="TLS" />
</Service>
</Server>
</pre>
<br />
However setting a trustManager is only possible if this option is provided by your application or if you have access to the source code of the SSL SocketFactory. In all other cases you will have to implement your own Security Provider providing your own truststore factory. This task is much more challenging. During my internet research for this topic I found several pages, which should be a good reference for you, if you have to go this way:<br />
<br />
<a href="http://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#Provider" target="_blank">JCA Reference Guide - Crypto Provider</a><br />
<br />
<a href="http://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/HowToImplAProvider.html" target="_blank">Howto Implement a JCA Provider</a><br />
<br />
<a href="http://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/JSSERefGuide.html#CustomizingStores" target="_blank">JSSE Reference Guide - Customized Certificate Storage</a><br />
<br />
<a href="http://stackoverflow.com/questions/24555890/using-a-custom-truststore-in-java-as-well-as-the-default-one" target="_blank">Custom CA Truststore in addition to System CA Truststore</a><br />
<h4>
HowTo Register global security provider </h4>
<br />
<code><java-home>/lib/security/java.security</code>
<br />
<pre class="brush: bash">security.provider.2=sun.security.provider.Sun
security.provider.3=sun.security.rsa.SunRsaSign
security.provider.4=sun.security.provider.SunJCE </pre>
Advantage: Multiple providers. Adding just the "missing piece".<br />
Disadvantage: System wide configuration<br />
<br />
<a href="http://stackoverflow.com/questions/4521119/java-argument-to-specify-java-security-file-for-jvm" target="_blank">Override security provider settings with system properties</a><br />
<h4>
Changing Security Settings via Code</h4>
<pre class="brush: java">Security.insertProviderAt(new FooBarProvider(), 1);
</pre>
<h4>
Register a TrustManager</h4>
<pre class="brush: java">put("TrustManagerFactory.SunX509", "sun.security.ssl.TrustManagerFactoryImpl$SimpleFactory");
put("TrustManagerFactory.PKIX", "sun.security.ssl.TrustManagerFactoryImpl$PKIXFactory");</pre>
<a href="https://nelenkov.blogspot.de/2011/12/using-custom-certificate-trust-store-on.html" target="_blank">Using a Custom Certificate Trust Store</a><br />
<a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/sun/security/ssl/SunJSSE.java?av=h#SunJSSE" target="_blank">Sun JSSE Provider Implementation</a>
Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com0tag:blogger.com,1999:blog-5257008670669259276.post-25585596369837268942016-08-04T12:25:00.003+02:002016-08-04T12:25:56.767+02:00Apache Fediz with Client Certificate Authentication (X.509)In this blog post I will explain how to generate your own SSL key-pair to perform certificate based authentication for SSO purposes with Apache Fediz IDP.<br />
<a name='more'></a><h3>
Client Key Authentication</h3>
<h4>
Generate Key-Pair</h4>
I like to use the <a href="http://www.keystore-explorer.org/" rel="nofollow" target="_blank">keystore-explorer</a> under windows, because it makes certificate management very easy. You don't have to lookup console commands but instead you get nice Wizards to get it all done. If you are running linux I can recommend <a href="https://www.sslshopper.com/article-most-common-java-keytool-keystore-commands.html" rel="nofollow" target="_blank">this page</a> to you, because it contains the most common Java Keytool commands you will need.<br />
<br />
After starting keystore-explorer create a new keykeystore (PKCS #12). Next click generate keypair. RSA with 2.048 bit should be fine. Now you should enter your name and after that click on extensions to define an "Extended Key Usage" for "TLS Web Client Authentication":<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-3-3I9YuS8p238snolcQ5EC0-Rm2xMrFUGK5UVotPKELe4_TGeQUPvfqV_ii-FRwKWDh0HuBICj98PWsYie9VnZjtE8nTcr3-mDBcjjBRsN3ENBl8PMTKX7QTO8YYXNpc_oJVjKeMbG0/s1600/generate-keypair-01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="222" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-3-3I9YuS8p238snolcQ5EC0-Rm2xMrFUGK5UVotPKELe4_TGeQUPvfqV_ii-FRwKWDh0HuBICj98PWsYie9VnZjtE8nTcr3-mDBcjjBRsN3ENBl8PMTKX7QTO8YYXNpc_oJVjKeMbG0/s400/generate-keypair-01.jpg" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqT7vSjavrufN2CDY1wizzEvFDULtQIuyHmqwNL1itHeQDHpUEiDCbzySM0StDD1OOSUkquKGLgYDtD5h7WhyCjT5QCNmHnB_7LNdM2Qyrp7v-Z53oPC8PR2tPyi8BGlZmWBSPMH0EIjE/s1600/generate-keypair-02.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="146" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqT7vSjavrufN2CDY1wizzEvFDULtQIuyHmqwNL1itHeQDHpUEiDCbzySM0StDD1OOSUkquKGLgYDtD5h7WhyCjT5QCNmHnB_7LNdM2Qyrp7v-Z53oPC8PR2tPyi8BGlZmWBSPMH0EIjE/s400/generate-keypair-02.jpg" width="400" /></a></div>
<br />
<div class="text-alert">
Make sure that this extension flag is really set for your key-pair. I first tried without this extension and I could not get any of my browsers to even show me a certificate selection popup when authentication against the IDP.</div>
<br />
Since you will have to import your personal certificate to the IDP truststore later on, I would recommend to you to export your public certificate at this step:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgO0lY7OA5WJ4i2tj9rfiRmHJQDFPeW5OuYITzQgQMbk4TXxlxPFxYO3AuRCC2zId9gBSapeTmDf96ysNALuoG2HdKzJTQ_L86OhplWMpTJSjnRBJcW4_hppK6Hl9IpFG0BdYOCO4oQ27U/s1600/generate-keypair-05.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="207" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgO0lY7OA5WJ4i2tj9rfiRmHJQDFPeW5OuYITzQgQMbk4TXxlxPFxYO3AuRCC2zId9gBSapeTmDf96ysNALuoG2HdKzJTQ_L86OhplWMpTJSjnRBJcW4_hppK6Hl9IpFG0BdYOCO4oQ27U/s400/generate-keypair-05.jpg" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiR3S9A2BLp2eJBdaOQIakEkbVMBA7hvjkEV9L-y1irk2gNwz9w_77i8rx90gYyRqmPFqfz_qUGxY3NZdJt4IW9wN8CpqtqdkrdFOAtD286IEdhl7vzQsTXowIsspE00HXU6q5xdxSLZKQ/s1600/generate-keypair-06.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="178" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiR3S9A2BLp2eJBdaOQIakEkbVMBA7hvjkEV9L-y1irk2gNwz9w_77i8rx90gYyRqmPFqfz_qUGxY3NZdJt4IW9wN8CpqtqdkrdFOAtD286IEdhl7vzQsTXowIsspE00HXU6q5xdxSLZKQ/s400/generate-keypair-06.jpg" width="400" /></a></div>
<br />
<h4>
Import Key-Pair to your Browser</h4>
Once your key generation was successful, you need to add this key-pair to your browser:<br />
<br />
In Chrome you need to open your <code>settings -> extended settings -> HTTPS/SSL -> Manage Certificates -> Import</code> select your p12 certificate and make sure that all extensions from the certificate are included:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiA_D5U6RvqxiUSjehDmFPH2lNjFypo0_T2r6tpVGi3XSqK_nk3tF7AlpGUSucu9QWV1gsvrO0vhdHtAwcTQ2CRgFhIfUj8MGXHrcxXLBimX9-4M2rNcSWL661b4bWismWod-k88qkXfTo/s1600/generate-keypair-03.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="288" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiA_D5U6RvqxiUSjehDmFPH2lNjFypo0_T2r6tpVGi3XSqK_nk3tF7AlpGUSucu9QWV1gsvrO0vhdHtAwcTQ2CRgFhIfUj8MGXHrcxXLBimX9-4M2rNcSWL661b4bWismWod-k88qkXfTo/s320/generate-keypair-03.jpg" width="320" /></a></div>
<br />
Since chrome and IE will use the same certificate store. So there is no need to do this twice if you have done this once for one of the two.<br />
<br />
For Firefox you need to go to <code>Options -> Advanced -> Certificates -> View Certificates -> Your Certificates -> Import</code><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg58QiKP4cC0TvquV769Gx0ETDEasY7uKNgziFo1UPxo4xFnM-1OSG-oqfWlU5LGDZJ4uy-ZsGlf_BRxDGczIr4FV6z26ea9ALaFCg6bmbviMiDKhKDXc7F4dh2Eeq0uj60xCHXU6mmjM8/s1600/generate-keypair-04.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="229" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg58QiKP4cC0TvquV769Gx0ETDEasY7uKNgziFo1UPxo4xFnM-1OSG-oqfWlU5LGDZJ4uy-ZsGlf_BRxDGczIr4FV6z26ea9ALaFCg6bmbviMiDKhKDXc7F4dh2Eeq0uj60xCHXU6mmjM8/s320/generate-keypair-04.jpg" width="320" /></a></div>
<br />
<div class="text-tip">
I had to restart my machine before my browsers would show me the option to select my certificates for client authentication. Some articles in the internet also recommended to add the IDP URL to your list of trusted sides in the Internet Explorer.</div>
<h3>
Setup Fediz IDP</h3>
You can find a full IDP / Web-App setup instruction in one of my <a href="https://janbernhardt.blogspot.de/2015/01/single-logout-with-fediz-ws-federation.html">previous articles</a>. In this article I will only highlight steps that are related to SSL slient authentication.<br />
<br />
Add SSL support to your tomcat <code>conf/server.xml</code>
<br />
<pre class="brush: xml"><Connector port="9443" protocol="org.apache.coyote.http11.Http11Protocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
keystoreFile="idp-ssl-key.jks"
keystorePass="tompass"
truststoreFile="idp-ssl-trust.jks"
truststorePass="ispass"
truststoreType="JKS"
clientAuth="want"
sslProtocol="TLS" />
</pre>
If you want all clients to authenticate with a client SSL Certificate against your IDP you must set the <code>clientAuth</code> attribute to <code>"true"</code> instead of <code>"want"</code>. However if you want to support multiple authentication styles even without a client certificate you should set <code>clientAuth</code> to <code>"want"</code>.<br />
<br />
Open your <code>idp-ssl-trust.jks</code> with your keystore-explorer to import your personal certificate from your desktop (see previous export step above).<br />
<h3>
Validate Setup</h3>
Open your browser to the Fediz Hello World page: <a href="https://localhost:9443/fediz-idp/">https://localhost:9443/fediz-idp/</a>. Your browser should show you a selection popup for your client certificate:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiY2I7KMVQE3PxC5S04hUiwqUl-JTMLUjienzEEBKNRwZFyQPBY9HoDChuQ8z6alB_hSe6GoR5yB1dG3vdhoLTsU4f8Glmob5XqccXQsyXg92rDulfnt5p-XEuqf1FBNbA1nmoaauWltCw/s1600/generate-keypair-07.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="232" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiY2I7KMVQE3PxC5S04hUiwqUl-JTMLUjienzEEBKNRwZFyQPBY9HoDChuQ8z6alB_hSe6GoR5yB1dG3vdhoLTsU4f8Glmob5XqccXQsyXg92rDulfnt5p-XEuqf1FBNbA1nmoaauWltCw/s400/generate-keypair-07.jpg" width="400" /></a></div>
<br />
If you imported this certificate correctly to your tomcat IDP truststore you should now see a "Hello World!" welcome page from Fediz.<br />
<br />
Please also take a look at <a href="http://coheigea.blogspot.ie/2015/06/apache-cxf-fediz-120-tutorial-part-ii.html" target="_blank">colms blog</a> about this topic. Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com0tag:blogger.com,1999:blog-5257008670669259276.post-10780764303488554462016-07-20T17:58:00.005+02:002016-09-01T10:57:41.532+02:00Karaf JDBC JAAS ModuleKaraf relys on JAAS for user authentication. JAAS makes it possible to plugin multiple modules for this purpose. By default Karaf will use the <code>karaf</code> realm with a JAAS module getting its user and role information from a property file: <code>runtime/etc/users.properties</code><br />
<br />
In this blog post I will show you how to use the Karaf JAAS console commands and how to setup a JDBC module to authenticate against a database.<br />
<a name='more'></a><br />
<div class="text-info">
All code was tested on Karaf version 4.0.3 respectively Talend ESB version 6.1.1</div>
<h3>
JDBC Setup</h3>
<h4>
Register Datasource</h4>
At first you need to install the Karaf JDBC feature:<br />
<pre class="brush: bash">karaf@trun()> feature:install jdbc
karaf@trun()> feature:install pax-jdbc-h2
</pre>
Check all available DataSourceFactory:
<br />
<pre class="brush: bash">karaf@trun()> service:list DataSourceFactory
[org.osgi.service.jdbc.DataSourceFactory]
-----------------------------------------
osgi.jdbc.driver.version = 1.3.172
osgi.jdbc.driver.class = org.h2.Driver
osgi.jdbc.driver.name = H2
service.id = 453
service.bundleid = 360
service.scope = singleton
Provided by :
H2 Database Engine (360)
[org.osgi.service.jdbc.DataSourceFactory]
-----------------------------------------
osgi.jdbc.driver.class = org.h2.Driver
service.id = 454
service.bundleid = 360
service.scope = singleton
Provided by :
H2 Database Engine (360)
</pre>
Next you can create a new Datasource:<br />
<pre class="brush: bash">karaf@root()> jdbc:ds-create -dn H2 -url "jdbc:h2:file:C:/Talend/6.1.1/db/users" -u sa -p secret users</pre>
With the <code>-dn H2 </code>option you define a datasource of type <code>H2</code>. Alternative you could also use <code>generic, oracle, mysql, postgres, derby, hsql</code> as your datasource type. Please make sure to install also the matching jdbc pax feature for your datasource type.<br />
The <code>-u sa</code> option defines the datasource username. Finally <code>users</code> is the datasource name.<br />
<h4>
Add sample data
</h4>
<pre class="brush: bash">jdbc:execute users CREATE TABLE users ( username VARCHAR(255) PRIMARY KEY NOT NULL, password VARCHAR(255) NOT NULL );
jdbc:execute users CREATE TABLE roles ( username VARCHAR(255) NOT NULL, role VARCHAR(255) NOT NULL, PRIMARY KEY (username,role) );
jdbc:execute users INSERT INTO users values('alice','e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4');
jdbc:execute users INSERT INTO roles values('alice','manager');</pre>
Validate your input:
<br />
<pre class="brush: bash">karaf@trun()> jdbc:query users SELECT * FROM roles
ROLE | USERNAME
------------------
manager | alice</pre>
<h3>
JAAS Console Commands</h3>
Karaf provides some nice console commands to manage your JAAS realms.<br />
<h4>
List JAAS realms with assigned modules</h4>
<pre class="brush: bash">karaf@trun()> jaas:realm-list
Index | Realm Name | Login Module Class Name
-----------------------------------------------------------------------------------
1 | karaf | org.apache.karaf.jaas.modules.properties.PropertiesLoginModule
2 | karaf | org.apache.karaf.jaas.modules.publickey.PublickeyLoginModule
3 | karaf | org.apache.karaf.jaas.modules.audit.FileAuditLoginModule
4 | karaf | org.apache.karaf.jaas.modules.audit.EventAdminAuditLoginModule</pre>
<h4>
</h4>
<h4>
</h4>
<h4>
List users and assigned roles</h4>
<pre class="brush: bash">karaf@trun()> jaas:realm-manage --realm karaf
karaf@trun()> jaas:user-list
User Name | Group | Role
--------------------------------------
tadmin | admingroup | admin
tadmin | admingroup | manager
tadmin | admingroup | viewer
tadmin | admingroup | systembundles
tadmin | | sl_admin
tesb | admingroup | admin
tesb | admingroup | manager
tesb | admingroup | viewer
tesb | admingroup | systembundles
tesb | | sl_maintain
karaf | admingroup | admin
karaf | admingroup | manager
karaf | admingroup | viewer
karaf | admingroup | systembundles
karaf@trun()> jaas:cancel</pre>
<h4>
Adding a user</h4>
<pre class="brush: bash">karaf@trun()> jaas:realm-manage --realm karaf
karaf@trun()> jaas:user-add alice secret
karaf@trun()> jaas:update
</pre>
If you execute "List users" again you will see alice added to the realm. You will also find alice added to the <code>users.properties</code> file.<br />
<h3>
Register JDBC JAAS Module</h3>
Create a file <code>db_jaas.xml</code> within the <code>deploy</code> folder of your karaf installation:<br />
<pre class="brush: xml"><?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:jaas="http://karaf.apache.org/xmlns/jaas/v1.0.0"
xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"
xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0">
<!-- Allow usage of System properties, especially the karaf.base property -->
<ext:property-placeholder placeholder-prefix="$[" placeholder-suffix="]"/>
<!-- AdminConfig property place holder for the org.apache.karaf.jaas -->
<cm:property-placeholder persistent-id="org.apache.karaf.jaas.db" update-strategy="reload">
<cm:default-properties>
<cm:property name="encryption.name" value="basic"/>
<cm:property name="encryption.enabled" value="true"/>
<!--cm:property name="encryption.prefix" value="{CRYPT}"/>
<cm:property name="encryption.suffix" value="{CRYPT}"/-->
<cm:property name="encryption.algorithm" value="SHA1"/>
<cm:property name="encryption.encoding" value="hexadecimal"/>
<cm:property name="detailed.login.exception" value="false"/>
<cm:property name="audit.file.enabled" value="true"/>
<cm:property name="audit.file.file" value="$[karaf.data]/security/audit.log"/>
<cm:property name="audit.eventadmin.enabled" value="true"/>
<cm:property name="audit.eventadmin.topic" value="org/apache/karaf/login"/>
</cm:default-properties>
</cm:property-placeholder>
<jaas:config name="karaf" rank="10">
<jaas:module className="org.apache.karaf.jaas.modules.jdbc.JDBCLoginModule" flags="required">
datasource = osgi:javax.sql.DataSource/(osgi.jndi.service.name=users)
query.password = SELECT PASSWORD FROM USERS WHERE USERNAME=?
query.role = SELECT ROLE FROM ROLES WHERE USERNAME=?
insert.user = INSERT INTO USERS VALUES(?,?)
insert.role = INSERT INTO ROLES VALUES(?,?)
delete.user = DELETE FROM USERS WHERE USERNAME=?
delete.role = DELETE FROM ROLES WHERE USERNAME=? AND ROLE=?
delete.roles = DELETE FROM ROLES WHERE USERNAME=?
encryption.enabled = ${encryption.enabled}
encryption.name = ${encryption.name}
encryption.algorithm = ${encryption.algorithm}
encryption.encoding = ${encryption.encoding}
detailed.login.exception = ${detailed.login.exception}
</jaas:module>
<jaas:module className="org.apache.karaf.jaas.modules.audit.FileAuditLoginModule" flags="optional">
enabled = ${audit.file.enabled}
file = ${audit.file.file}
</jaas:module>
<jaas:module className="org.apache.karaf.jaas.modules.audit.EventAdminAuditLoginModule" flags="optional">
enabled = ${audit.eventadmin.enabled}
topic = ${audit.eventadmin.topic}
</jaas:module>
</jaas:config>
</blueprint></pre>
By adding a configuration file <code>org.apache.karaf.jaas.db.cfg</code> to your <code>etc</code> folder you will be able to update the configuration of your jaas bundle during runtime.<br />
<pre class="brush: bash">encryption.enabled = true
encryption.name = basic
encryption.algorithm = SHA1
encryption.encoding = hexadecimal
detailed.login.exception = false</pre>
Now you can login to Karaf via SSH with you alice DB user.<br />
<pre class="brush: bash">ssh -p 8101 alice@localhost</pre>
Password will be a: <code>secret</code>
Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com0tag:blogger.com,1999:blog-5257008670669259276.post-80657824160290320022016-02-05T21:19:00.000+01:002016-02-15T13:40:01.199+01:00Apache Fediz installation in productionIn 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.<br />
<br />
Basically you need to change all default passwords and certificates.<br />
<br />
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.<br />
<br />
<a name='more'></a><h2>
IDP Changes</h2>
<h4>
Remove Files</h4>
<pre class="brush: bash">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
</pre>
<h4>
Rename Files</h4>
<pre class="brush: bash">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
</pre>
<h4>
Modify Files</h4>
<ul>
<li>Change <code>fediz-idp</code> to <code>idp</code> as <code>finalName</code> in <code>services/idp/pom.xml</code>. 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.</li>
<li>Apply the following changes to your <code>entities-realm-myCompany.xm</code></li>
<ul>
<li>Rename all <code>realmA</code> settings to <code>realmYourCompany</code></li>
<li>Change your realm identifier </li>
<div class="text-tip">
Use <code>http://</code> or <code>urn:</code> at the beginning of your <code>realm</code> identifier to ensure interoperability with Microsoft ADFS</div>
<li>Change Keystore settings, especially the <code>certificatePassword</code></li>
<li>Update <code>stsUrl</code> and <code>idpUrl</code> to reflect your installation</li>
<li>Remove <code>fedizhelloworld</code> from your <code>applications</code></li>
<li>Remove <code>oidc</code> application if not used, or update <code>passiveRequestorEndpointConstraint</code> if oidc will be used</li>
<li>Remove or update all <code>trustedIdps</code></li>
</ul>
<li>Regenerate your own IDP SSL keys for <code>services/idp/src/main/resources/idp-ssl-key.jks</code> and store new certificate in <code>services/idp/src/main/resources/idp-ssl-trust.jks</code>. Remove all other certificates in <code>idp-ssl-trust.jks</code></li>
<li>Update settings for your database in <code>services/idp/src/main/resources/persistence.properties</code></li>
<li>Change passwords in <code>services/idp/src/main/resources/stsKeystoreMyCompany.properties</code></li>
<li>Change usernames and passwords in <code>services/idp/src/main/resources/users.properties</code>. Use <a href="http://bcrypt-generator.com/" target="_blank">Bcrypt</a> passwords instead of plaintext passwords.</li>
<li>Update <code>wsdlLocation</code> to reflect your STS URL in <code>services/idp/src/main/webapp/WEB-INF/idp-servlet.xml</code></li>
<li>Ensure correct <code>realm</code> value within your <code>services/idp/src/main/webapp/WEB-INF/web.xml</code></li>
<li>Apply the following changes within <code>services/idp/src/main/webapp/WEB-INF/security-config.xml</code></li>
<ul>
<li>Change realm identifier in federationEntryPoint</li>
<li>Enable <code>bCryptPasswordEncoder</code></li>
<li>Enable <code>form-login</code> if desired and provide custom login screen in <code>services/idp/src/main/webapp/WEB-INF/views/signinform.jsp</code></li>
<li>Remove all authentication alternatives, which you don't need</li>
<li>Change username and password in <code>securityProperties</code> if you need certificate based authentication</li>
<li>Remove all <code>stsUPPortFilter</code> settings, because they are only usefull for demo setups when your STS runs within the same Tomcat as your IDP.</li>
<li>Update all <code>wsdlLocation</code> to match your STS URL</li>
</ul>
<li>Add your desired database library to your dependencies at <code>services/idp/pom.xml</code></li>
</ul>
<h4>
Create Files</h4>
<ul>
<li>Provide your own keystore at <code>services/idp/src/main/resources/stsrealm_myCompany.jks</code>. This one should be the same as the one used later for the STS.</li>
</ul>
<h3>
STS Changes </h3>
<h4>
Remove Files</h4>
<pre class="brush: bash">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
</pre>
<h4>
Rename Files</h4>
<pre class="brush: bash">mv services/sts/src/main/resources/stsKeystoreA.properties services/sts/src/main/resources/stsKeystore.properties</pre>
<h4>
Modify Files</h4>
<ul>
<li>Add dependency to <code>services/sts/pom.xml</code> (only needed if you want to use JEXL for claim mappings)</li>
</ul>
<pre class="brush: xml"><dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-jexl</artifactId>
<version>2.1.1</version>
<scope>runtime</scope>
</dependency>
</pre>
<ul>
<li>Change private key password in keystore and in Callbackhandler:<code> services/sts/src/main/java/org/apache/cxf/fediz/service/sts/PasswordCallbackHandler.java</code> </li>
<li>Replace with your own <code>keystore.properties</code> file.</li>
<li>Change passwords in <code>services/sts/src/main/resources/stsTruststore.properties</code> </li>
<li>Change log level in <code>services/sts/src/main/resources/log4j.properties</code> </li>
<li>Remove all certificates in <code>services/sts/src/main/resources/ststrust.jks</code> and add your own.</li>
<li>Change user accounts in <code>services/sts/src/main/webapp/WEB-INF/passwords.xml</code><code> </code></li>
<li>Do the following changes within: <code>services/sts/src/main/webapp/WEB-INF/cxf-transport.xml</code></li>
<ul>
<li>Import file with user realm configuration, like <code>ldap.xml</code></li>
<li>Change Relationship settings</li>
<li>Add Claim Hanlder (if needed)</li>
<li>Rename all realmA in text to realmYourCompany</li>
<li>Remove all realmB settings / beans / endpoints</li>
</ul>
</ul>
<h4>
Create Files</h4>
<ul>
<li>Add ClaimMapping Scripts (if needed)<code><br />services/sts/src/main/resources/claimMapping-trusted-realm.script</code> </li>
<li>Add you own keystore <code>services/sts/src/main/resources/stsrealm_myCompany.jks</code></li>
</ul>
<h2>
Tomcat Installation</h2>
<h4>
Tomcat Home </h4>
<br />
<div class="text-tip">
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!
</div>
<br />
1. Download latest Tomcat Version:<br />
<a href="https://tomcat.apache.org/download-70.cgi">https://tomcat.apache.org/download-70.cgi</a><br />
<br />
2. Extract Tomcat to <code>/usr/share/</code><br />
<br />
3. Create a symbolic link pointing to your latest tomcat download:<br />
<pre class="brush: bash">ln -s /usr/share/apache-tomcat-7.0.67 /usr/share/tomcat
</pre>
<div class="text-tip">
Using of symbolic links will make it easier to switch to newer versions later on.</div>
<br />
4. Restrict tomcat installation<br />
<pre class="brush: bash"># 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 {} +
</pre>
<h4>
IDP Tomcat Setup</h4>
Setup a tomcat base environment for your IDP<br />
<pre class="brush: bash"># 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/
</pre>
Create a system startup script <code>/etc/init.d/tomcat-idp</code> file, with the following content:<br />
<pre class="brush: bash">#!/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
</pre>
Update file permissions<br />
<pre class="brush: bash"># 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
</pre>
Register Tomcat for autostart:<br />
<pre class="brush: bash">chkconfig tomcat-idp on</pre>
Start, Wait and Stop Tomcat<br />
<pre class="brush: bash">/etc/init.d/tomcat-idp start
tail -f /usr/share/tomcat-idp/logs/catalina.out
/etc/init.d/tomcat-idp stop
</pre>
Your <code>idp.war</code> file should now be extracted.<br />
Copy the idp keystore to your tomcat-idp root folder<br />
<pre class="brush: bash">
cp /usr/share/tomcat-idp/webapps/idp/WEB-INF/classes/idp-ssl-key.jks /usr/share/tomcat-idp/
</pre>
Adjust settings of <code>/usr/share/tomcat-idp/conf/server.xml</code><br />
<ul>
<li>Remove all out-commented blockes to improve readability.</li>
<li>Change shutdown password to something more complex:</li>
</ul>
<pre class="brush: xml">
<server port="8005" shutdown="ComPlexWord"></pre>
<ul>
<li>Enable SSL Support</li>
</ul>
<pre class="brush: xml"><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" />
</pre>
<ul>
<li>Disable autoDeploy </li>
</ul>
<pre class="brush: xml">
<Host appbase="webapps" name="localhost"
unpackWARs="true" autoDeploy="false">
. . .
</host>
</pre>
Update file permissions<br />
<pre class="brush: bash">
# 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
</pre>
Start Tomcat-IDP again and check if startup was successful<br />
<pre class="brush: bash">/etc/init.d/tomcat-idp start
tail -f /usr/share/tomcat-idp/logs/catalina.out
</pre>
<h4>
STS Tomcat Setup</h4>
<br />
<div class="text-info">
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.</div>
<br />
The STS Tomcat setup is almost the same as for the IDP. <br />
Setup a tomcat base environment for your STS<br />
<pre class="brush: bash"># 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/</pre>
Create a system startup script <code>/etc/init.d/tomcat-sts</code> file, with the following content:<br />
<pre class="brush: bash">#!/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
</pre>
Update file permissions<br />
<pre class="brush: bash"># 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
</pre>
Register Tomcat for autostart:<br />
<pre class="brush: bash">chkconfig tomcat-sts on</pre>
Start, Wait and Stop Tomcat<br />
<pre class="brush: bash">/etc/init.d/tomcat-sts start
tail -f /usr/share/tomcat-sts/logs/catalina.out
/etc/init.d/tomcat-sts stop</pre>
Your <code>sts.war</code> file should now be extracted.<br />
Copy the sts keystore to your tomcat-sts root folder:<br />
<pre class="brush: bash">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/</pre>
Adjust settings of <code>/usr/share/tomcat-sts/conf/server.xml</code><br />
<ul>
<li>
Remove all out-commented blockes to improve readability.</li>
<li>Change shutdown password to something more complex:<br />
</li>
</ul>
<pre class="brush: xml">
<server port="9005" shutdown="ComPlexWord"></pre>
<ul>
<li>Enable SSL Support</li>
</ul>
<pre class="brush: xml"><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" /></pre>
<ul>
<li>Disable autoDeploy</li>
</ul>
<pre class="brush: xml"><host appbase="webapps" name="localhost"
unpackWARs="true" autoDeploy="false">
. . .
</host></pre>
Update file permissions<br />
<pre class="brush: bash"># 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
</pre>
Start Tomcat-STS again and check if startup was successful<br />
<pre class="brush: bash">/etc/init.d/tomcat-sts start
tail -f /usr/share/tomcat-sts/logs/catalina.out </pre>
<h3>
OIDC Installation</h3>
Just in case, that you would want to use OIDC also, you need to do the following steps, to get it up and running:<br />
<br />
<div class="text-info">
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 <code>tomcat-oidc</code>. In that case you need to change the file locations & settings accordingly.</div>
<br />
<a href="http://search.maven.org/#search|gav|1|g%3A%22org.apache.cxf.fediz%22%20AND%20a%3A%22fediz-tomcat7%22" target="_blank">Download</a> Fediz Client Plugin (<a href="http://search.maven.org/remotecontent?filepath=org/apache/cxf/fediz/fediz-tomcat7/1.2.1/fediz-tomcat7-1.2.1-zip-with-dependencies.zip" target="_new">zip-with-dependencies.zip</a>) and extract libraries to <code>/usr/share/tomcat-idp/lib</code><br />
<pre class="brush: bash">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
</pre>
<br />
Next you must add the plugin configuration at /usr/share/tomcat-idp/conf/fediz_config.xml<br />
<br />
<pre class="brush: 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></pre>
<br />Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com1tag:blogger.com,1999:blog-5257008670669259276.post-56612118384658108722016-01-16T15:46:00.001+01:002016-01-20T18:22:35.290+01:00Understanding Spring Web-Flow in Apache Fediz - Part 2After explaining in <a href="http://janbernhardt.blogspot.de/2016/01/understanding-spring-web-flow-in-apache.html">Part 1</a> 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.<br />
<br />
The flow registry knows three flows:<br />
<ol>
<li>Federation Validate Request Flow</li>
<li>Federation Signin Request Flow</li>
<li>Federation Signin Response Flow</li>
</ol>
The first flow is linked to the <code>fediz-idp/federation</code> URL within the <code>idp-servlet.xml</code> file which is the usual entry point for the IDP. The two other flows are sub-flows which will be executed from within the first flow.<br />
<pre class="brush: xml"><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>
</pre>
<h4>
Validate Request Flow</h4>
<br />
The main federation flow can be customized within the <code>WEB-INF/flows/federation-validate-request.xml</code> file. The standard flow looks like this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDXPTssOcF6dV5FudtA2JfwQzkxYP88XC9pnuHE7S26Cccz0EK26jg7li5P8QRnOOHjcNMbiZNLtKaWp-GXikqWS2-sdyjLU3nZUqKuJ9splbZHlHrQV3zFBsCSm0cqL1A7zwY372tAzE/s1600/Apache-Fediz-Validate-Flow.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="532" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDXPTssOcF6dV5FudtA2JfwQzkxYP88XC9pnuHE7S26Cccz0EK26jg7li5P8QRnOOHjcNMbiZNLtKaWp-GXikqWS2-sdyjLU3nZUqKuJ9splbZHlHrQV3zFBsCSm0cqL1A7zwY372tAzE/s640/Apache-Fediz-Validate-Flow.png" width="640" /></a></div>
<br />
<a name='more'></a>Any given request send to the <code>fediz-idp/federation</code> URL will be processed by this flow.<br />
If it is a logout action the logout process will be triggered. Otherwise it could be a WS-Federation signin action triggering the flow in the middle or a SAML Response from a 3rd Party IDP according to SAML Web Browser SSO Profile.<br />
<br />
The bold line shows a common scenario when the user was redirected from a RP application with an existing session at the IDP and therefor reusing a cached SAML token to receive a new SAML token applicable for the RP.<br />
<h4>
Signin Request Flow</h4>
<br />
The signin request flow can be customized within the <code>WEB-INF/flows/federation-signin-request.xml</code> file. The standard flow looks like this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgooiTQQUBTtu-0iwV5VefkwttvoJ58wEn4orVqfa9tW9JqbuddkbROWdqUMvMpNXaShH8wIBBU9c5xg6Ps9GJI8GrAFV-pgM8I-t-sBqFDJpdbHmGijRL44mPGijE6QKvnr_hE7bIhNH4/s1600/Apache-Fediz-Request-Flow-New.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="512" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgooiTQQUBTtu-0iwV5VefkwttvoJ58wEn4orVqfa9tW9JqbuddkbROWdqUMvMpNXaShH8wIBBU9c5xg6Ps9GJI8GrAFV-pgM8I-t-sBqFDJpdbHmGijRL44mPGijE6QKvnr_hE7bIhNH4/s640/Apache-Fediz-Request-Flow-New.png" width="640" /></a></div>
<br />
At first the home realm discovery will take place. Then the IDP
validates if he is responsible for the users home realm himself or if the user
is managed by another 3rd party IDP. In any case it will be checked if
the user has already a valid session token. If this is the case, the
user can receive a new SAML token for the RP. If not, the user first
needs to login to the local/remote IDP.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjksmhY1VhwSIdRBHeNL7ozPhvOEaz-VgWSAMYb8a2J_rsSAFwUHHrpSMg-Grb4Gn8Sqyc3ru27hWNg-W2BtKZLgWt2pcAvEsYdjKHwX2Xruk8H5g0r55IaFabg4J2n_yYUe-ENEtjfNWk/s1600/Apache-Fediz-HRDS.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="267" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjksmhY1VhwSIdRBHeNL7ozPhvOEaz-VgWSAMYb8a2J_rsSAFwUHHrpSMg-Grb4Gn8Sqyc3ru27hWNg-W2BtKZLgWt2pcAvEsYdjKHwX2Xruk8H5g0r55IaFabg4J2n_yYUe-ENEtjfNWk/s640/Apache-Fediz-HRDS.png" width="640" /></a></div>
<br />
The HomeRealm Discovery is not a separate flow within the federation-singin-request flow, but shown here for a better understanding of how the discovery works. The result of the HRDS can be null. In that case the federation-singin-request flow will continue by providing a selection view for the user.<br />
<br />
<div class="text-info">
The above flow is used in Apache Fediz since version 1.3.0. Before that HRDS based on Spring EL was not implemented and the flow looked like the diagram below.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdwUrsgsK4SN8sECXNrj697JDGNjwlgpzxN_0IqXgBDaHkgK7-T2IXMG6UqYcJM6-cGZWRb2PpN9acZPjgPt4HdUuNduWJr39JMKgji-JEPdKbjGjwsGpEr6hmGSQkYf5VfbVXMuaVch8/s1600/Apache-Fediz-Request-Flow.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="512" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdwUrsgsK4SN8sECXNrj697JDGNjwlgpzxN_0IqXgBDaHkgK7-T2IXMG6UqYcJM6-cGZWRb2PpN9acZPjgPt4HdUuNduWJr39JMKgji-JEPdKbjGjwsGpEr6hmGSQkYf5VfbVXMuaVch8/s640/Apache-Fediz-Request-Flow.png" width="640" /></a></div>
<br />
<h4>
Signin Response Flow</h4>
<br />
The signin response flow can be customized within the <code>WEB-INF/flows/federation-signin-response.xml</code> file. The standard flow looks like this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSNpHuh8Dw87HI5lJAwCJOtBEiJejE3GqY6tE31wZ7tjmoepe2UcK_D-Hj_27uYAARvkb68biPZjt-FU028DfpNd_Nlq12-5w896-GFxA7XeWcV39fEDdNsDfuxW7zLQVd-3-IC5CZDYU/s1600/Apache-Fediz-Response-Flow.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="158" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSNpHuh8Dw87HI5lJAwCJOtBEiJejE3GqY6tE31wZ7tjmoepe2UcK_D-Hj_27uYAARvkb68biPZjt-FU028DfpNd_Nlq12-5w896-GFxA7XeWcV39fEDdNsDfuxW7zLQVd-3-IC5CZDYU/s640/Apache-Fediz-Response-Flow.png" width="640" /></a></div>
<br />
<br />
When receiving a token from a trusted 3rd party IDP, this token will be validated and possibly cached, before it will be used to receive a SAML token applicable to the RP.Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com4tag:blogger.com,1999:blog-5257008670669259276.post-48911446199130336462016-01-07T16:20:00.000+01:002016-01-07T16:20:21.287+01:00Understanding Spring Web-Flow in Apache Fediz - Part 1When I started to work with Apache Fediz, most of the actions looked like magic to me, because I was not able to understand how <a href="http://docs.spring.io/spring-security/site/docs/4.0.3.RELEASE/reference/htmlsingle/" target="_blank">Spring Security</a> and <a href="http://docs.spring.io/spring-webflow/docs/2.4.2.RELEASE/reference/html/" target="_blank">Spring Web Flow</a> have been used in <a href="https://cxf.apache.org/fediz.html" target="_blank">Apache Fediz</a>. After several hours of learning and investigation I finally understood how all this works together.<br />
<br />
In this post I would like to share with you from what I understood of how Fediz works internally.<br />
<a name='more'></a>When you take a look inside the <code>WEB-INF/web.xml</code> you will find three URL mappings:<br />
<pre class="brush: xml"><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></pre>
<ul>
<li><code>/services/*</code> provides access to all REST services for updating the IDP configuration </li>
<li><code>/FederationMetadata/2007-06/FederationMetadata.xml</code> provides access to the generated IDP metadata document which is usually used in application wizards to setup the correct IDP configuration
</li>
<li><code>/federation</code> provides access to the configured Spring Web-Flow</li>
</ul>
<br />
If you take a look inside the <code>WEB-INF/web.xml</code> you will see that the <code>/federation</code> URL is linked with <code>org.springframework.web.servlet.DispatcherServlet</code>. The initialization of the Spring Flow however takes place within the <code>WEB-INF/idp-servlet.xml</code>.<br />
So how is the <code>DispatcherServlet</code> linked to the <code>idp-servlet.xml</code>?<br />
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 <code>servlet-name</code> and ending with "<code>-servlet.xml</code>". To apply this knowledge you can see that the <code>/federation</code> URL is mapped to the servlet name <code>idp</code> and thus the default configuration spring file which will be loaded from the <code>DispatcherServlet</code> is <code>idp-servlet.xml</code> <br />
<h4>
Spring Configuration</h4>
Within the <code>idp-servlet.xml</code> you will find a spring configuration to setup the Spring Web Flow.<br />
First Spring will do a component scan to instantiate and autowire all beans with a <code>@Component</code> annotation located within the beans package. These beans usually provide specific actions which are executed within the flows.<br />
<pre class="brush: xml"><context:component-scan base-package="org.apache.cxf.fediz.service.idp.beans" />
</pre>
Now the JSP views and HTML resources like images will be made available for the spring web flow:<br />
<pre class="brush: xml"><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" />
</pre>
At next the actual spring web flows will get registered. All beans setup within this spring config will be available within the web flows.<br />
<pre class="brush: xml"><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>
</pre>
Adding security restrictions to the flow will allow spring security to be included in the flow for user authentication.<br />
<pre class="brush: xml"><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>
</pre>
The spring security configuration can be found within the <code>WEB-INF/security-config.xml</code> file. Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com0tag:blogger.com,1999:blog-5257008670669259276.post-58278118880029207952015-12-18T23:35:00.000+01:002016-03-01T14:27:57.256+01:00Register trusted 3rd party IDP with SAML Web Browser SSO ProfileIn 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 <a href="https://docs.oasis-open.org/security/saml/v2.0/saml-profiles-2.0-os.pdf" target="_blank">SAML Web Browser SSO Profile</a>.<br />
<br />
In my previous posts about Apache Fediz I focused on the <a href="http://docs.oasis-open.org/wsfed/federation/v1.2/os/ws-federation-1.2-spec-os.html#_Toc223175002" target="_blank">WS-Federation passive protocol</a> 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.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEix5vC5u3tc1V4x-r41XyyDZXWeVEb1KJ6ATkRTHCvgHhVYjeVS7SUBgEvhA1szjTfuIZcafHxdzBSiupyePCvRXnKtlAwzjUxDec_wspPQFjIqLAAwo0z75b50M-JYZoTk7ZLGQyEgOuY/s1600/SAML-SSO-IDP-04.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="222" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEix5vC5u3tc1V4x-r41XyyDZXWeVEb1KJ6ATkRTHCvgHhVYjeVS7SUBgEvhA1szjTfuIZcafHxdzBSiupyePCvRXnKtlAwzjUxDec_wspPQFjIqLAAwo0z75b50M-JYZoTk7ZLGQyEgOuY/s400/SAML-SSO-IDP-04.jpg" width="400" /></a></div>
<br />
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 <a href="http://coheigea.blogspot.de/2015/08/apache-cxf-fediz-120-tutorial-part-vii.html?showComment=1450365310451#c8309043829215915176" target="_blank">Colms post</a> about this topic.
<br />
<a name='more'></a><h3>
Preconditions</h3>
I 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 <a href="http://janbernhardt.blogspot.de/2015/01/single-logout-with-fediz-ws-federation.html" target="">previous post</a> about Fediz, as well as <a href="http://coheigea.blogspot.ie/2015/06/apache-cxf-fediz-120-tutorial-part-i.html" target="_blank">this post</a> from Colm.<br />
<h3>
Install SAML IDP</h3>
Fediz 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).<br />
<br />
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:<br />
<br />
1. Clone the Fediz Sources on your computer with GIT<br />
<pre class="brush: bash">> git clone -v https://github.com/apache/cxf-fediz.git
</pre>
2. Goto the systestfolder and build the systest with maven<br />
<pre class="brush: bash">> cd cxf-fediz/systests/federation/samlIdpWebapp/
> mvn -Pfastinstall
</pre>
3. Copy war file to tomcat webapps folder<br />
<pre class="brush: bash">> cp target/*.war ${tomcat.fediz.idp.home}/webapps
</pre>
4. Start Fediz-IDP and Fediz Demo app (if not already done yet)<br />
<pre class="brush: bash">> ${tomcat.fediz.idp.home}/bin/startup.sh
> ${tomcat.fediz.rp.home}/bin/startup.sh </pre>
<h3>
Register 3rd Party IDP</h3>
Next 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.<br />
<br />
<div class="text-info">
The REST Service API requires a Basic user authentication. Default username is <code>admin</code> and password is <code>password</code>.</div>
<br />
1. Register a new 3rd Party IDP<br />
<code>POST https://localhost:9443/fediz-idp/services/rs/trusted-idps</code>
<br />
<pre class="brush: xml"><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></pre>
<div class="text-info">
If you use a POST Binding for the <code>SAMLResponse</code> your response will most likely not be deflated. If you use the GET Binding your response will most likely be deflated. Adjust the <code>support.deflate.encoding</code> value accordingly.</div>
<br/>
2. Assign this new 3rd Party IDP to your Realm-A Fediz IDP<br />
<code>POST https://localhost:9443/fediz-idp/services/rs/idps/urn%3Aorg%3Aapache%3Acxf%3Afediz%3Aidp%3Arealm-A/trusted-idps</code><br />
<pre class="brush: xml"><ns2:trustedIdp xmlns:ns2="http://org.apache.cxf.fediz/">
<realm>urn:org:apache:cxf:fediz:idp:realm-C</realm>
</ns2:trustedIdp> </pre>
<h3>
Test: Perform a federated Login</h3>
<br />
<div class="text-tip">
Make sure to delete any <code>localhost</code> 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.</div>
<br />
Now you can perform a login by invoking the following URL:<br />
<a href="https://localhost:8443/fedizhelloworld/secure/fedservlet" target="_blank">https://localhost:8443/fedizhelloworld/secure/fedservlet</a> <br />
<br />
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 <code>ALICE</code> and <code>ECILA</code> as your password.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQ5xYbb8q5WHO88PGbu1KAVrVJUndAiXsCtJEUwsFQH0U8JOl0tWE61qyGkNycyqbAR6hZQOmDl5Jz8EgRrHhACsYXjiDVOqyUfde6cHHWnMWk0wfAjh2zqfAUPnJ3dm3DRnVyC5QuDnw/s1600/SAML-SSO-IDP.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="127" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQ5xYbb8q5WHO88PGbu1KAVrVJUndAiXsCtJEUwsFQH0U8JOl0tWE61qyGkNycyqbAR6hZQOmDl5Jz8EgRrHhACsYXjiDVOqyUfde6cHHWnMWk0wfAjh2zqfAUPnJ3dm3DRnVyC5QuDnw/s400/SAML-SSO-IDP.jpg" width="400" /></a></div>
<br />
After some redirect you should see the demo page with your federated user account from alice: <br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiV3fPUfoV23rVAwVerbd-rUDEQtbwD9yb-Aus-iG63rMtrRoKu2Z6vgXDKfh8YHdevirO5Q40WLQs3jYJLrLUItbWygoG67CKLv2_BKMYpWMW3E8yq5wNZ33pbR9TJyW4bmFl4L6eV2NM/s1600/SAML-SSO-IDP-02.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="217" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiV3fPUfoV23rVAwVerbd-rUDEQtbwD9yb-Aus-iG63rMtrRoKu2Z6vgXDKfh8YHdevirO5Q40WLQs3jYJLrLUItbWygoG67CKLv2_BKMYpWMW3E8yq5wNZ33pbR9TJyW4bmFl4L6eV2NM/s400/SAML-SSO-IDP-02.jpg" width="400" /></a></div>
<h3>
Review Redirects in Detail</h3>
If you use a monitoring tool like <a href="http://www.telerik.com/download/fiddler" target="_blank">Fiddler</a>, you will be able to analyze the redirects in greater detail.<br />
<br />
After invoking the fedizhelloworld demo app, I'll get redirected to the Fediz IDP:
<br />
<pre class="brush: bash">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</pre>
<br />
The Fediz IDP will show you the home realm selection page and after selection will redirect you to the SAML SSO IDP<br />
<pre class="brush: bash">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</pre>
<br />
You can use for example <a href="https://notepad-plus-plus.org/" target="_blank">Notepad++</a> to decode SAML-P Requests & Responses.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBdRGInfH4h4vqtjwb21r9AN00s4GduOTkZsA9Phz2b8wG0EAHnCMY1GzbQjnto4Sz-q0DxtxZth0U8g7AqnA2ECiDXKzQHOe0zNsMgYLkGK68FkcQQuHpljGIuNcQ2wS1jbH0QCAimuk/s1600/SAML-SSO-IDP-03.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="256" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBdRGInfH4h4vqtjwb21r9AN00s4GduOTkZsA9Phz2b8wG0EAHnCMY1GzbQjnto4Sz-q0DxtxZth0U8g7AqnA2ECiDXKzQHOe0zNsMgYLkGK68FkcQQuHpljGIuNcQ2wS1jbH0QCAimuk/s320/SAML-SSO-IDP-03.jpg" width="320" /></a></div>
<br />
After decoding the <code>SAMLRequest</code> you will see the following SAML <code>AuthnRequest</code>:<br />
<pre class="brush: xml"><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>
</pre>
<br />
After login at the SAML IDP the user will be redirected back to Fediz-IDP:<br />
<pre class="brush: bash">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-090e180c91f3</pre>
<div class="text-info">
Usually you would receive a <code>POST</code> message from the SAML IDP instead of a <code>GET</code> redirect, as done here by the mockup IDP.</div>
<br />
A decoded <code>SAMLResponse</code> will look like this:<br />
<pre class="brush: xml"><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>
</pre>
<br />
Fediz-IDP is configured to do a identity mapping and will return a SAML token back to the demo application according to WS-Federation.<br />
<pre class="brush: bash">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</pre>
<br />
The final <code>wresult</code> which will be sent to the demo app looks like this:
<br />
<pre class="brush: xml"><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>
</pre>
<br />Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com0tag:blogger.com,1999:blog-5257008670669259276.post-16151715507212384042015-12-17T11:24:00.000+01:002015-12-18T23:36:47.999+01:00Liferay Portal Integration with Fediz OpenID Connect 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.<br />
<br />
<div class="text-info">
You will need <b>Apache Fediz version 1.3.0</b> or higher, if you want to setup this use case by yourself</div>
<h3>
<a name='more'></a>Install Liferay Portal with Fediz Plugin</h3>
First <a href="https://www.liferay.com/downloads/liferay-portal/available-releases" target="_blank">download</a> and extract Liferay bundled with Tomcat. (I used liferay-portal-6.2-ce-ga5)<br />
<br />
Enable HTTPs port in <code>liferay-portal-6.2-ce-ga5/tomcat-7.0.62/conf/server.xml</code><br />
<pre class="brush: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>
</pre>
I reused the <code>idp-ssl-key.jks</code> 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 <code>liferay-portal-6.2-ce-ga5/tomcat-7.0.62/</code>.<br />
<br />
Now you can start Liferay for a first setup. Simply execute <code>liferay-portal-6.2-ce-ga5/tomcat-7.0.62/bin/startup.sh</code><br />
<br />
After Tomcat startup is complete you can invoke the server page at <a href="https://localhost:8443/" target="_blank">https://localhost:8443/</a><code></code>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0mi5ZQ_sLO1o73q0vEjKVZUKByCIdvynrfwSdZrBv1EIZ58ZpJUrTepELgQMmQwywj_MCy8zbaeRHK5GreEzNuws9bdobzbMpQG36oquH3em6bh0c0rSF_QQsUQmrI4jXuIHhQzwy7tw/s1600/Liferay-Installation-01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="282" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0mi5ZQ_sLO1o73q0vEjKVZUKByCIdvynrfwSdZrBv1EIZ58ZpJUrTepELgQMmQwywj_MCy8zbaeRHK5GreEzNuws9bdobzbMpQG36oquH3em6bh0c0rSF_QQsUQmrI4jXuIHhQzwy7tw/s400/Liferay-Installation-01.jpg" width="400" /></a></div>
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.<br />
<br />
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 <code>control panel -> Users -> User Groups -> Add</code><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnzGORpXuoax0ry04uGit6oa3SeJBAZbwh8d12ZWeuQcHwYGEPZV8bcKntllXQp9T6eniGrsdrT9eWd4z_00lTLrot_MNK-1n6MXxb-uVFELvugGhr3-a_dVQctOnUbFsnaCV3Vi3UsVs/s1600/Liferay-Installation-04.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnzGORpXuoax0ry04uGit6oa3SeJBAZbwh8d12ZWeuQcHwYGEPZV8bcKntllXQp9T6eniGrsdrT9eWd4z_00lTLrot_MNK-1n6MXxb-uVFELvugGhr3-a_dVQctOnUbFsnaCV3Vi3UsVs/s320/Liferay-Installation-04.jpg" width="290" /></a></div>
<br />
Your Liferay Portal is now up and running so lets continue next on enabling OpenID Connect for your portal.<br />
<h3>
Register Liferay Portal at OIDC Provider</h3>
After starting your OIDC Service, you can register the Liferay Portal under the following URL: <a href="https://localhost:9443/fediz-oidc/clients/register">https://localhost:9443/fediz-oidc/clients/register</a>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpKlfuosVA17ViTDcnOKX4f5AKTwV4AUKsdlNNKqb_hE-f50dhVtfKtofwjmE0wR4kKxjrl5K4eTvaHOLmL9qzQEDM8XBLWB2YP2Y_pZcvoYAeTJppBWnoiGE_IwjL5ulIMeJ3fAk7R8M/s1600/Liferay-Installation-02.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpKlfuosVA17ViTDcnOKX4f5AKTwV4AUKsdlNNKqb_hE-f50dhVtfKtofwjmE0wR4kKxjrl5K4eTvaHOLmL9qzQEDM8XBLWB2YP2Y_pZcvoYAeTJppBWnoiGE_IwjL5ulIMeJ3fAk7R8M/s400/Liferay-Installation-02.jpg" width="350" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPpQ76EhQZJCnghQ3YHi_osaTqLGzdaRWq6zLpx39uO25VScJDTaqYsZ9kwhh_xOPmBKG2JObSAVNzxIpfk2oZXhvVRYlXMlhtbYeGeG8tsn3FhPNiASK4lOh1FkUp6GXjJgqMrxQRpOI/s1600/Liferay-Installation-03.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPpQ76EhQZJCnghQ3YHi_osaTqLGzdaRWq6zLpx39uO25VScJDTaqYsZ9kwhh_xOPmBKG2JObSAVNzxIpfk2oZXhvVRYlXMlhtbYeGeG8tsn3FhPNiASK4lOh1FkUp6GXjJgqMrxQRpOI/s400/Liferay-Installation-03.jpg" width="400" /></a></div>
You will need the client Identifier as well as the Client Secret in the following section.<br />
<h3>
Install OpenIdConnect Extension for Liferay</h3>
You will need the <a href="https://github.com/csgf/OpenIdConnectLiferay" target="_blank">OpenIdConnectLiferay</a> extension, which you can clone from Github. Further information on installing this extension can be found at the <a href="http://csgf.readthedocs.org/en/latest/OpenIdConnectLiferay/docs/" target="_blank">authors webpage</a>.<br />
<br />
You'll need to update the configuration within <code>it.infn.ct.security.liferay.openidconnect.utils.Authenticator</code><br />
<br />
<pre class="brush: java">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);
}
}
</pre>
<br />
Now you can build and deploy this extension.<br />
<code>$ mvn clean install</code><br />
You will find a jar file with all extensions at <code>OpenIdConnectLiferay/target/OpenIdConnectLiferay-0.1-jar-with-dependencies.jar</code>. You need to copy this jar file to <code>liferay-portal-6.2-ce-ga5/tomcat-7.0.62/lib/ext/</code>.<br />
<br />
Next you need to create (or modify if it already exists) the following file <code>liferay-portal-6.2-ce-ga5/tomcat-7.0.62/webapps/ROOT/WEB-INF/classes/portal-ext.properties</code> to activate the OpenID Connect Login handler:<br />
<pre class="brush: java">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
</pre>
<br />
Now you should restart your tomcat and after that you can invoke the following login URL: <a href="https://localhost:8443/c/portal/login?openIdLogin=true" target="_blank">https://localhost:8443/c/portal/login?openIdLogin=true</a>. 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.<br />
<br />
For debugging purposes is can also be helpful to increase the log level by adding the following line at <code>liferay-portal-6.2-ce-ga5/tomcat-7.0.62/conf/logging.properties</code> <br />
<pre class="brush: java">it.infn.ct.security.liferay.openidconnect.level = FINE
</pre>
<h3>
Test your Setup: Login with OpenID Connect</h3>
Now you can validate if your setup is working as expected. Open the following URL in your browser:<br />
<a href="https://localhost:8443/c/portal/login?openIdLogin=true">https://localhost:8443/c/portal/login?openIdLogin=true</a><br />
<br />
<div class="text-tip">
Make sure to logout first, if you are still logged in at your portal.</div>
<br />
You should get redirected to the Fediz IDP Login page and after login (bob:bob) you should get redirected back to your Liferay portal.
<br />
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.<br />
Once that is done, you will see the start screen of the Liferay Portal.<br />
Now you can logout and login again with the above URL. This time you will login directly without any additional steps/questions.<br />
<br />
You have been successful! Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com9tag:blogger.com,1999:blog-5257008670669259276.post-77091132956094439392015-12-14T14:46:00.000+01:002015-12-14T14:47:16.364+01:00Fediz with OpenID Connect Support and WS-Federation Bridge (2/2)<h2>
Setup a Demonstrator</h2>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDd157yBU9XovNi1iXwgIKVP9bftBm0v0bRvsKMl9qJAJr5VVMxp3tsxQ_KVtqiXAGQteZnX4XesFR_bpnGjg8ihxdcmuOoe2lodS1ZWrXwJB16-KvvUkdnssuLp-fJLBpIaWJ6TuMybw/s1600/OpenID+Connect+Bridge.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="192" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDd157yBU9XovNi1iXwgIKVP9bftBm0v0bRvsKMl9qJAJr5VVMxp3tsxQ_KVtqiXAGQteZnX4XesFR_bpnGjg8ihxdcmuOoe2lodS1ZWrXwJB16-KvvUkdnssuLp-fJLBpIaWJ6TuMybw/s400/OpenID+Connect+Bridge.jpg" width="400" /></a></div>
In this article I'll explain how to setup a demonstrator for the use case described in my <a href="http://janbernhardt.blogspot.de/2015/12/fediz-with-openid-connect-support-and.html">previous post</a>.<br />
<h3>
Setup Fediz IDP & OIDC</h3>
First you need to <a href="http://janbernhardt.blogspot.de/2015/01/single-logout-with-fediz-ws-federation.html">setup the Fediz IDP</a> as usual. To get the OIDC Service working you also need to do the following:<br />
<ol>
<li><a href="http://janbernhardt.blogspot.de/2015/01/single-logout-with-fediz-ws-federation.html">Install Fediz Plugin</a> for the Fediz IDP Server (usually you would do this for the client application only)<br />For the <code>fediz_config.xml</code> you can use the <a href="https://github.com/apache/cxf-fediz/blob/master/services/oidc/src/main/conf/fediz_config.xml">sample</a> provided with the OIDC Service.</li>
<li><a href="https://github.com/apache/cxf-fediz.git" target="_blank">Download</a> or <a href="https://maven.apache.org/" target="_blank">build</a> the OIDC service and then deploy the <code>fediz-oidc.war</code> file to your webapps folder (same place where you deployed STS & IDP)</li>
</ol>
<h3>
<a name='more'></a>Register an OpenID Connect Client </h3>
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:<br />
<br />
<a href="https://localhost:9443/fediz-oidc/clients/register">https://localhost:9443/fediz-oidc/clients/register</a><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFgEkqhgUk-uPt9fWdcrhZAQNlDQhYnc0bLbHBwMAeCFcyd3z3UvjDBtHIQCY2KT2CQBrkH-6G5ibtKKhsg7NCgPpwIZo7fBN_c5GglWk_UjvJqlTLc6_7YikY9kEoUxPeobIYy4gqe7c/s1600/Client-Registration+Form.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFgEkqhgUk-uPt9fWdcrhZAQNlDQhYnc0bLbHBwMAeCFcyd3z3UvjDBtHIQCY2KT2CQBrkH-6G5ibtKKhsg7NCgPpwIZo7fBN_c5GglWk_UjvJqlTLc6_7YikY9kEoUxPeobIYy4gqe7c/s320/Client-Registration+Form.jpg" width="234" /></a></div>
For Client Name and Client Description you can enter any human readable and meaningful value related to your service.<br />
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.<br />
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.<br />
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.<br />
<br />
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.
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiH5x6Ey4npEBSQkAUXUMeLgVmmhG3l789rAR2N3AQPyo9KcNWptSGmdWeJLsJXswtrZRbq62nPTewFU5aRCVdkN-BUpoTdKeROpAmhLArQFP4XDLfOKWgAvgYLigIlAAzZlzt9KMiNplA/s1600/Client-Registration+Overview.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="123" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiH5x6Ey4npEBSQkAUXUMeLgVmmhG3l789rAR2N3AQPyo9KcNWptSGmdWeJLsJXswtrZRbq62nPTewFU5aRCVdkN-BUpoTdKeROpAmhLArQFP4XDLfOKWgAvgYLigIlAAzZlzt9KMiNplA/s400/Client-Registration+Overview.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<h3>
</h3>
<h3>
Understanding the Web Portal</h3>
Your 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.<br />
<pre class="brush: xml"><!--
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>
</pre>
<br />
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. <br />
<pre class="brush: xml"><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>
</pre>
Within your code you need to inject the <code>OidcClientTokenContext</code>, for example via <code>@Context</code> annotation:
<br />
<pre class="brush: java">@Context
private OidcClientTokenContext oidcContext;
</pre>
Within your method when just before invoking the REST Service you must add the authorization header as follows:
<br />
<pre class="brush: java">ClientAccessToken accessToken = oidcContext.getToken();
backendServiceClient.authorization(accessToken);
</pre>
<h3>
Understanding the REST Service</h3>
Lets 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 <code>@Scopes</code> which will require that the used access token was provided for the scope <code>userinfo</code>. The other method will also require an access token, but without any scope enforcement.<br />
<pre class="brush: java">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 + "!";
}
}
</pre>
<br />
Within your Spring configuration you need to add two filters. The <code>OAuthRequestFilter</code> is needed to ensure that the provided access token is still valid, and the <code>OAuthScopesFilter</code> checks that the required scope for invoking a certain method will matches with the scope of the access token.<br />
<pre class="brush: xml"><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>
</pre>
Since validation is not yet standardized the <code>tokenValidatorClient</code> communicates with the OIDC service in a proprietary manner.
<br />
<br />Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com0tag:blogger.com,1999:blog-5257008670669259276.post-64614278547395203732015-12-09T16:53:00.001+01:002015-12-10T11:37:15.133+01:00Fediz with OpenID Connect Support and WS-Federation Bridge (1/2)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.<br />
<br />
This solution should work for Web-Portals, Mobile Apps & Desktop Applications.<br />
<br />
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.<br />
<br />
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.<br />
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.<br />
<br />
<a name='more'></a><h2>
Token Types & Token Handling </h2>
JSON Web Tokens (<a href="http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-13" target="_blank">JWT</a>) are similar to <a href="http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf" target="_blank">SAML</a> 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.<br />
<br />
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. <a href="http://coheigea.blogspot.de/" target="_blank">Colm O hEigeartaigh</a> has already done some improvements to the CXF STS to support JWT tokens at the STS.<br />
<br />
Instead of requesting a SAML Token with the following TokenType <code>http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0</code> you can now also request a JWT token with this TokenType <code>urn:ietf:params:oauth:token-type:jwt</code>.<br />
<br />
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.
<br />
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.<br />
<br />
<h2>
OpenID Connect</h2>
I would see <a href="http://openid.net/connect/" target="_blank">OpenID Connect</a> 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.<br />
<br />
OIDC is also based on the OAuth2 standard and thus inherits also all benefits and drawbacks of this protocol.<br />
<br />
Many big internet companies support OpenID Connect like Google, Facebook, Twitter, etc..<br />
OpenID Connect is related but not equal to OpenID on which some of the bigger companies dropped already the support for (like Google).<br />
<h3>
Simple Sequence Flow</h3>
OpenID 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.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCtPAC_wV1NSwR9fmtFvOeRva-AC-09MuHSBnLCUxjdBqFMz7zd5fi7ywPvCV02-MudmsfpwkVxFeginnWfpA7oBO9pH26lkXQBswvHUMqKRawSJK4IA1r1EEbV-57z5FSJPF2mg9XOaI/s1600/OpenID+Connect.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="317" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCtPAC_wV1NSwR9fmtFvOeRva-AC-09MuHSBnLCUxjdBqFMz7zd5fi7ywPvCV02-MudmsfpwkVxFeginnWfpA7oBO9pH26lkXQBswvHUMqKRawSJK4IA1r1EEbV-57z5FSJPF2mg9XOaI/s320/OpenID+Connect.jpg" width="320" /></a></div>
(1) The user invokes the WebPortal (same would apply if the user invokes a REST Service).<br />
<pre class="brush: bash">GET https://demo.portal.com/webPortal/index.html HTTP/1.1
Host: demo.portal.com</pre>
to be continued...
<br />
(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).
<br />
<pre class="brush: bash">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
</pre>
The user will see a login screen for authentication.
<br />
(3) After successful login the user will be redirected back to the provided redirect_uri with an authorization code:
<br />
<pre class="brush: bash">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
</pre>
(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.<br />
<pre class="brush: bash">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
</pre>
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.
<br />
<pre class="brush: jscript">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"
}
</pre>
The <code>id_token</code> contains three values of interest base64 encoded and separated by a dot '.':
<br />
<pre class="brush: jscript">eyJhbGciOiJSUzI1NiJ9
eyJzdWIiOiJib2IiLCJhdWQiOiJVVUY5RmRzNjdubnA2QSIsImlhdCI6MTQ0OTY3NDMyNywiZXhwIjoxNDQ5NzM0MzI3LCJnaXZlbl9uYW1lIjoiQm9iIiwiZW1haWwiOiJib2J3aW5kc29yQHJlYWxtYS5vcmciLCJmYW1pbHlfbmFtZSI6IldpbmRzb3IiLCJuYW1lIjoiQm9iIFdpbmRzb3IiLCJub25jZSI6IjFkNWM0MjhmZmJmZjNlZWQ5NTcyMTMzOWU2N2M1NmU4YzJhYTRhZGQ2YmI0OTNlNDM2MjQ5NTc4YzgxZjg4IiwiaXNzIjoiYWNjb3VudHMuZmVkaXouY29tIiwiYXRfaGFzaCI6InZvc1h4a1lhcW1aYmJiTWlVdWdYRUEifQ
VQB4QfI1nrka5cfgq8aOGyT0iv3EEE7BBETIzQHbee1t9BDr8wPNV55pGY1YqU6F5C9KIkWiIGLz8MBlKwQVfU7FfzXqm4gEF2zbq4i_LyL-f_RW38-id4VmfF3n6ybWDqdmLLXagFL2UurTdIuGWxbZVW_bgnuIc5dJfnQ_b2wi9hxoL-1u4PPufDLfTLBYRtP5zaedR01me9T5i6PCn2jZSdvfd9304Jf6MOf98Cvv-faeZ87ilUrd5k3q4tQl6dIL3IefPBTfbR8Ni69viD29A-PvtKLquQcGp6p3NEXnwOYF7c72ZsjuZI2pcItoeBeo2Whz9Ni21vfWsd3Iaw
</pre>
After base64 decoding the first value will tell us which algorithm has been used to secure the ID token:
<br />
<pre class="brush: jscript">{"alg":"RS256"}
</pre>
And the second value will contain the actual JWT token:
<br />
<pre class="brush: jscript">{
"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"
}
</pre>
The third parameter will contain the digital signature (binary value) thus I cannot display it here.
<br />
<br />
After consuming the authorization code the user will be redirected back to the initially requested resource
<br />
<pre class="brush: bash">HTTP/1.1 303 See Other
Location: https://demo.portal.com/webPortal/index.html
</pre>
<br />
<h2>
OpenID Connect with WS-Federation Login</h2>
Now 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.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGKIRc1WtkthcKxFxoEoT6VaNncAdo39YsC77cSoBaRqMRTN-_6EJzhpHkwEHf1Stp4FTr_awFBZc3xOoJIIVC0Y4mbUnHQFpqa7M_WLCa15lRvsm5WKlCRVTooL90d9KCwvdJ3JLJ3pE/s1600/OpenID+Connect+Bridge.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="308" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGKIRc1WtkthcKxFxoEoT6VaNncAdo39YsC77cSoBaRqMRTN-_6EJzhpHkwEHf1Stp4FTr_awFBZc3xOoJIIVC0Y4mbUnHQFpqa7M_WLCa15lRvsm5WKlCRVTooL90d9KCwvdJ3JLJ3pE/s640/OpenID+Connect+Bridge.jpg" width="640" /></a></div>
<br />
<br />
(1) In the first step the user invokes the web portal.<br />
(2) Since now existing session exists the user will be redirected to the OIDC Service according to OpenID Connect.<br />
(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.<br />
(4) The user will see a login screen and will be redirected back to the OIDC server after successful authentication with a SAML token.<br />
(5) The Fediz Plugin will store the SAML Token. OIDC will provide the requested code from step (2).<br />
(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.<br />
(7) The REST Service will be invoked with the access token received in the previous step<br />
<pre class="brush: bash">GET https://my.services.com/backend/service
Host: my.services.com
Authorization: Bearer a8de6a544738c9e9036318ee78dfe7
</pre>
(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)<br />
<br />
<i>In my second part of this post, I'll explain how to setup a demonstrator for the above described use case.</i><br />
<br />
<h2>
Federated SSO with WS-Federation & OpenID Connect</h2>
After 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.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiU-w9eIrWPBdsAIeIcS7X6kDPKWkyRy4uUNe1-zjOWJv3BRD92WpiwB9salpUFr2EnVmaLu993DK60hK0A_Dt6cqCFW5z0bktyxezdiLE3iSLiOarl0jCx8kxsvgBAW2F9FHEsqd8TnBA/s1600/Federated+OpenID+Connect+Bridge.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="304" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiU-w9eIrWPBdsAIeIcS7X6kDPKWkyRy4uUNe1-zjOWJv3BRD92WpiwB9salpUFr2EnVmaLu993DK60hK0A_Dt6cqCFW5z0bktyxezdiLE3iSLiOarl0jCx8kxsvgBAW2F9FHEsqd8TnBA/s640/Federated+OpenID+Connect+Bridge.jpg" width="640" /></a></div>
<br />
(1) A user from a partner company invokes the web portal.<br />
(2) Since now existing session exists the user will be redirected to the OIDC Service according to OpenID Connect.<br />
(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.<br />
(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).<br />
(5) After successful login the Requestor IDP will issue a SAML Token for the user and redirect the user back to the RP-IDP.<br />
(6) The RP-IDP will to do a <a href="http://janbernhardt.blogspot.de/2014/10/identity-federation-identity-mapping-vs.html">Claims or Identity Mapping</a> and after that issue a new SAML token applicable for the OIDC Service and redirects the user back to the OIDC service.<br />
(7) The Fediz Plugin at the OIDC service will store the SAML Token and OIDC will provide the requested code from step (2).<br />
(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.<br />
(9) The REST Service will be invoked with the access token received in the step (8).<br />
(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)<br />
<h3>
Home Realm Discovery</h3>
If 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 <a href="http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest" target="_blank">OpenID Connect Standard</a> provides a parameter <code>login_hint</code> for this purpose whereas <a href="http://docs.oasis-open.org/wsfed/federation/v1.2/os/ws-federation-1.2-spec-os.html#_Toc223175013" target="_blank">WS-Federation Standard</a> offers a <code>whr</code> parameter for this purpose.<br />
<br />
There are several ways to do a home realm discovery:<br />
<ol>
<li><b>Dedicated URLs</b><br />You can provide different URLs for each user group. This can be done by adding the <code>login_hint</code> 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 <code>login_hint</code> / <code>whr</code> parameter.</li>
<li><b>E-Mail Address</b><br />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 <code>login_hint</code>.The OIDC service could use the domain name of this E-Mail Address to set it as the <code>whr</code> 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.<br />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 <code>login_hint</code> but instead only a more static <code>whr</code> 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.</li>
<li><b>IP Range</b><br />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.</li>
<li><b>Miscellaneous</b><br />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.</li>
</ol>
Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com2tag:blogger.com,1999:blog-5257008670669259276.post-23571576159270373452015-01-30T15:25:00.001+01:002015-01-30T15:25:29.460+01:00Single Logout with Fediz - WS-FederationWS-Federation is primarily used to achieve Single Sing On (SSO). This raises the challenge how to securely logout from multiple applications once the user is done with his work. To navigate to each application previously used to hit the logout button would be quite inconvenient. Fortunately the WS-Federation standard does not only define how to do single sign on, but also how to do single logout.<br />
<br />
In this blog I'll explain how to setup a demonstrator to show single sing-on as well as single sing-off. Since single sing-off is implemented in CXF Fediz version 1.2, I'm going to use a snapshot build since 1.2 is not yet released.<br />
<a name='more'></a>First of all we need to <a href="http://tomcat.apache.org/download-70.cgi" target="_blank">download Tomcat 7</a> since we will deploy our IDP/STS as well as our two demo applications to a tomcat container each. I renamed the tomcat folder of my extracted tomcat zip to: <br />
<ul>
<li>Fediz-IDP</li>
<li>Fediz-RP1</li>
<li>Fediz-RP2</li>
</ul>
Next I opened a terminal within the cxf-fediz source code which I downloaded from <a href="https://github.com/apache/cxf-fediz" target="_blank">github</a> and run maven to build fediz:
<br />
<pre class="brush: js">mvn clean install</pre>
<h3>
Setup IDP</h3>
After my build was successfull I copied the <code>fediz-idp-sts.war</code> file from <code>cxf-fediz/services/sts/target/</code> into my <code>Fediz-IDP/webapps/</code> deployment folder. I also did the same with the <code>fediz-idp.war</code> file from <code>cxf-fediz/services/idp/target/</code>.<br />
Since the default https fediz port for the IDP and STS is 9443 and also to avoid port collisions with my two other tomcat instances, I need to update the port configuration in my tomcat <code>Fediz-IDP/conf/server.xml</code>. Here I update all ports starting with '8' to start with a '9'.<br />
<pre class="brush: xml"><Connector port="9443" protocol="org.apache.coyote.http11.Http11Protocol"
maxHttpHeaderSize="65536"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
keystoreFile="idp-ssl-key.jks"
keystorePass="tompass"
truststoreFile="idp-ssl-trust.jks"
truststorePass="ispass"
truststoreType="JKS"
clientAuth="want"
sslProtocol="TLS" />
</pre>
To enable SSL for my RP-IDP tomcat I need to provide a keystore as well as a truststore. For demo purposes I will simply copy the java key stores from my fediz build <code>cxf-fediz/services/idp/target/classes/</code> here I find the file <code>idp-ssl-key.jks</code> as well as <code>idp-ssl-trust.jks</code> which I'll copy to my <code>Fediz-IDP</code> root folder.<br />
Before you can start Fediz-IDP you also need to get the expected JDBC driver which is by default <a href="http://sourceforge.net/projects/hsqldb/files/hsqldb/hsqldb_2_3/hsqldb-2.3.2.zip/download" target="_blank">HyperSQL JDBC driver</a>. You need to download the zip file and then extract all jar files from <code>/hsqldb-2.3.2/hsqldb/lib/</code> to <code>Fediz-IDP/lib/</code>.<br />
Now you can start the Fediz-IDP tomcat server via <code>Fediz-IDP/bin/startup.sh</code>.
<br />
<div class="text-tip">
To avoid OutOfMemory erros you should add the following settings to your <code>CATALINA_OPTS</code> system environment variable: <code>-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled -XX:MaxPermSize=128M</code></div>
<br />
By default the Fediz IDP has only basic authentication activated for user login. This is done to make it easier to run some system tests. However for single logout HTTP Basic authentication is not recommended, because the browser will cache your user credentials and will automatically sent your credentials to the IDP. So you would have to close all your current browser windows to actually see the login popup again after logout. If you also enable form based authentication in your <code>webapps/fediz-idp/WEB-INF/security-config.xml</code> you will actually see a login form again after your logout action. Here is the sample configuration how to enable form based authentication:<br />
<pre class="brush: xml"><security:http use-expressions="true">
<security:custom-filter after="CHANNEL_FILTER" ref="stsPortFilter" />
<security:custom-filter after="SERVLET_API_SUPPORT_FILTER" ref="entitlementsEnricher" />
<security:intercept-url pattern="/FederationMetadata/2007-06/FederationMetadata.xml" access="isAnonymous() or isAuthenticated()" />
<!-- MUST be http-basic thus systests run fine -->
<security:form-login />
<security:http-basic />
<security:logout delete-cookies="FEDIZ_HOME_REALM,JSESSIONID" invalidate-session="true" />
</security:http></pre>
<div class="text-info">
You can also disable http basic authentication if you want to. But you can also just leave it enabled. In that case you can use both authentication styles. You will see an HTML authentication form if you are requested to login, but you could also provide HTTP-Basic authentication header to login.</div>
<br />
After you updated the IDP configuration you need to restart the IDP tomcat server to apply your changes.<br />
<h3>
Setup 1. Demo App</h3>
First of all we must provide the Fediz plugin dependencies to our RP tomcat container. For this purpose we need to create a <code>fediz</code> subfolder in <code>Fediz-RP1/lib/</code>. Next we extract the content of the tomcat plugin dependencies zip file (<code>cxf-fediz\plugins\tomcat\target\fediz-tomcat-1.2.0-SNAPSHOT-zip-with-dependencies.zip</code>) to the fediz subfolder.<br />
To make sure that tomcat loads these additional dependencies we must also update the <code>calatina.properties</code> in <code>Fediz-RP1/conf</code><code></code>.
<br />
<pre class="brush: js">common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar,${catalina.home}/lib/fediz/*.jar</pre>
For Fediz-RP1 we will keep all port settings as they are.
To keep things simple with the SSL connection we will reuse the <code>idp-ssl-key.jks</code> keystore from the Fediz-IDP and copy this keystore also to Fediz-RP1 root folder. The <code>server.xml</code> file needs to have the following SSL connector to be configured for Fediz-RP1:
<br />
<pre class="brush: xml"><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" />
</pre>
Before we start the demo app container, we need to copy the demo app to the <code>webapps</code> folders, which can be found at <code>cxf-fediz/examples/simpleWebapp/target/fedizhelloworld.war</code>.<br />
Finally we must provide a correct fediz configuration file to the config folder of the demo app container. For this purpose we can copy the demo config file from <code>cxf-fediz/examples/simpleWebapp/src/main/config/fediz_config.xml</code> to <code>Fediz-RP1/conf/</code>.<br />
To make sure that the SAML tokens issued by the STS can be validated at the RP we must also install the correct STS truststore. This we can do by copying <code>cxf-fediz/services/sts/target/classes/ststrust.jks</code> to Fediz-RP1 root folder.<br />
Now everything should be in place so that we can start Fediz-RP1.<br />
<br />
We should see no exceptions in the logfiles and we should see the metadata document from the RP at the following URL: <a href="https://localhost:8443/fedizhelloworld/FederationMetadata/2007-06/FederationMetadata.xml">https://localhost:8443/fedizhelloworld/FederationMetadata/2007-06/FederationMetadata.xml</a>
<br />
<h3>
Setup 2. Demo App</h3>
The second demo app will be quite similar to the first. Therefore we can simply copy the Fediz-RP1 folder and rename it to Fediz-RP2. To avoid port collisions, we also need to update some server ports.<br />
Therefore we will update all ports beginning with a leading '8' and replace it with a leading '7' in the <code>Fediz-RP2/conf/server.xml</code> file. <br />
<br />
Since we are going to start both tomcat container on the same machine (localhost), we must also change the context path of the second demo app. Otherwise both apps would use the same cookies. Thus we need to rename the <code>fedizhelloworld.war</code> file within the <code>Fediz-RP2/webapps</code>/ folder to <code>fedizhelloworld2.war</code>. <br />
<br />
To also make this application known at the IDP, you need to register this application via the IDP REST Interface. You can use SoapUI for example or simply curl from your command line.<br />
<br />
<code>POST https://localhost:9443/fediz-idp/services/rs/applications</code>
<br />
<pre class="brush: xml"><ns2:application xmlns:ns2="http://org.apache.cxf.fediz/">
<realm>urn:org:apache:cxf:fediz:fedizhelloworld2</realm>
<role>ApplicationServiceType</role>
<serviceDisplayName>Fedizhelloworld</serviceDisplayName>
<serviceDescription>Web Application to illustrate WS-Federation</serviceDescription>
<protocol>http://docs.oasis-open.org/wsfed/federation/200706</protocol>
<tokenType>http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0</tokenType>
<lifeTime>3600</lifeTime>
</ns2:application>
</pre>
Next you need to add all claims required for the helloworld application. Since the claim types are already known by the default fedizhelloworld application you only need to add a link between application and claims:<br />
<br />
<code>POST https://localhost:9443/fediz-idp/services/rs/applications/urn%3Aorg%3Aapache%3Acxf%3Afediz%3Afedizhelloworld2/claims </code>
<br />
<pre class="brush: xml"><ns2:requestClaim xmlns:ns2="http://org.apache.cxf.fediz/">
<claimType>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role</claimType>
<optional>false</optional>
</ns2:requestClaim>
</pre>
<pre class="brush: xml"><ns2:requestClaim xmlns:ns2="http://org.apache.cxf.fediz/">
<claimType>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname</claimType>
<optional>true</optional>
</ns2:requestClaim>
</pre>
<pre class="brush: xml"><ns2:requestClaim xmlns:ns2="http://org.apache.cxf.fediz/">
<claimType>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname</claimType>
<optional>true</optional>
</ns2:requestClaim>
</pre>
<pre class="brush: xml"><ns2:requestClaim xmlns:ns2="http://org.apache.cxf.fediz/">
<claimType>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress</claimType>
<optional>true</optional>
</ns2:requestClaim>
</pre>
Next you need to register this application to a given IDP realm.<br />
<code>POST https://localhost:9443/fediz-idp/services/rs/idps/urn%3Aorg%3Aapache%3Acxf%3Afediz%3Aidp%3Arealm-A/applications</code>
<br />
<pre class="brush: xml"><ns2:application xmlns:ns2="http://org.apache.cxf.fediz/">
<realm>urn:org:apache:cxf:fediz:fedizhelloworld2</realm>
</ns2:application>
</pre>
You can check if your application was registered correctly via <code>GET https://localhost:9443/fediz-idp/services/rs/idps</code>.
<br />
Now the IDP will be able to provide SAML token for the second demo application.<br />
<h3>
Test Single Sign-On</h3>
To test if single sign-on is working as expected you can open the following URL in your browser: <a href="https://localhost:8443/fedizhelloworld/secure/fedservlet">https://localhost:8443/fedizhelloworld/secure/fedservlet</a>. You should get redirected to the IDP and need to choose Realm-A as your home realm. Next you need to enter your credentials <code>bob:bob</code>.<br />
You should be redirected back to the fedservlet URL and should see your username, assigned roles as well as other claims.<br />
<br />
If you now enter <a href="https://localhost:7443/fedizhelloworld/secure/fedservlet">https://localhost:7443/fedizhelloworld/secure/fedservlet</a> in your browser you should get redirected to the IDP and then without the need to enter your credentials again the IDP should redirect you back to the demo application.<br />
<br />
Congratulation. Single Sing-on is working!<br />
<h3>
Test Single Sign-Off</h3>
Goal of this blog post was not to achieve single sign-on but rather single sign-off. For this you have two options to trigger single logout: <br />
<ol>
<li>You can invoke a logout request starting at the demo application: <br />https://localhost:8443/fedizhelloworld/secure/logout</li>
<li>You can invoke a logout request directly at the IDP: <br />https://localhost:9443/fediz-idp/federation?wa=wsignout1.0</li>
</ol>
After you triggered the logout process you will be redirected to a page listing all application which the IDP had previously issued security tokens for. You will also be asked if you really want to logout from all these applications. After you confirmed the logout request, you should see a confirmation page. This page contains the same list of applications as before but this time with a green check maker at the end of each line.<br />
<br />
This image is the key to preform the actual logout for all the remote applications. The image resource URL will point to the logout URL of these applications, and by resolving the image resource in your browser you will also invoke the logout URL off all these applications.<br />
<br />
If you invoke now any of the two applications you should now again be redirected to the login page of the IDP.<br />
Congratulation. Single Logout is working!<br />
<h3>
Limitations</h3>
The WS-Federation standard does not require from any application to provide a "logout image" at the logout URL. This has just shown to be best practice. However if the logout URL of an application does not provide an image, the confirmation page will show a broken image, even thou the logout was most likely successful.<br />
<br />
The Single Logout implementation for Fediz is currently not able to delegate a logout request to the requestors IDP. So for example if the user is not authenticated at realm-a but at realm-b instead, the IDP does not forward the wsingout action to realm-b. Thus the user will only be logged of at applications in realm-a but the user still remains an active session in realm-b.<br />
<br />
Hopefully a global logout will be supported by Fediz in the future as well.Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com3tag:blogger.com,1999:blog-5257008670669259276.post-17793205013718606752014-12-11T10:45:00.001+01:002015-02-02T08:54:45.159+01:00Understanding WS-Federation - Passive Requestor ProfileWS-Federation is an identity federation specification which makes it possible to setup a SSO federation including multiple security realms. A realm (sometimes also called domain) represents a single unit under security administration or a part in a trust relationship.<br />
<h3>
Entities</h3>
Within the WS-Federation standard the following entities are defined:<br />
<ul>
<li><b>Relying Party (RP)</b><br />The relying party is a resource (web application or service) which consumes security tokens issued by the Security Token Service.</li>
<li><b>Requestor</b><br />A requestor is a user who wants to access a resource (relying party).</li>
<li><b>Identity Provider (IDP)</b><br />An Identity Provider can act as an authentication service to a requestor (in this case it is also called “Requestor IDP” or “Home-Realm IDP”) as well as an authentication service to a service provider (also called “Relying Party IDP”). If a user tries to access a relying party within his own security domain, the “Requestor IDP” and the “RP-IDP” can be the same IDP instance. An IDP can also be seen as an Web-Frontend (Extension) of an STS.</li>
<li><b>Security Token Service (STS)</b><br />A Security Token Service is a web service that validates user credentials and issues security tokens which can include user attributes (also called claims). The security token can be used at the Relying Party to authenticate the requestor’s identity.</li>
</ul>
<h3>
Passive Requestor Profile</h3>
The “Passive Requestor Protocol” of the WS-Federation standard deals with web-browser based access of a resource like a web portal or a web application.<br />
<br />
<a name='more'></a>The following figure shows a standard scenario of a web application (Relying Party) which delegates the user authentication to an Identity Provider (IDP) according to the WS Federation standard. This way the web application does not need to implement multiple authentication styles for a user, as well as it allows interacting with users not known within the local security domain. Another benefit of delegating the authentication process is that the IDP can retain a session with the user, so that when a user accesses another web application and is redirected to the IDP again, the IDP does not need to request user credentials again und thus providing a SSO experience for the user.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4j4iAPfuH4HsE0JVRZ-bLxxdNJuDuFdEu8VDzCvLaHC-flDovfh6DgHSs0iCWpJk0EyoCcff66Fq4J8o-1wDh_JNEdqfUg0hSKc_XCeXGFHQ5deDKFF7aBBoBcGt8GqA0s8a1iF3Bkyo/s1600/Simple-Flow.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Simplified authentication flow" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4j4iAPfuH4HsE0JVRZ-bLxxdNJuDuFdEu8VDzCvLaHC-flDovfh6DgHSs0iCWpJk0EyoCcff66Fq4J8o-1wDh_JNEdqfUg0hSKc_XCeXGFHQ5deDKFF7aBBoBcGt8GqA0s8a1iF3Bkyo/s1600/Simple-Flow.png" height="321" title="Simplified authentication flow" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
The above figure shows a sequence diagram of a user (requestor) accessing a web application with his browser. Since the user was not authentication due to a recent session, the application redirects the user to the IDP for a user login (1). The IDP collects the credentials from the user and uses a Security Token Service (STS) to validate the credentials and also to get a SAML token from the STS (2). The STS itself is connected to a LDAP data store to validate the user credentials and also to retrieve additional information (claims) about the user, e.g. roles. On successful authentication (3) the IDP returns the SAML token issued by the STS (4) to the user and advices (auto-submitting form) the user to send this SAML token to the originally requested web application (5). The IDP takes care of providing a web user interface and handling URL redirects, whereas the STS is responsible for generating SAML Token and validating of user credentials. The web application validates the SAML token (6) and on success returns the desired web page (7).<br />
<br />
The above sample was designed to show a simple use case scenario where the Requestor IDP is equal to the Relying Part IDP. In a more sophisticated scenario the Requestor IDP will not be equal to the Relying Party IDP. In addition to that there is also a Reverse Proxy added to the web application ensuring that the home realm discovery (also see section 2.3.3) is going to work correctly. The resulting access sequence can be seen in the following figure.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsIcH1mmVWDISeSZmEaZc1fHpgO2rtO5n7kXJ3lADdeXbR8udRtQrJNndfjNRGIgbPyHQoy2nwvREsEgOoFq9LVCLK0XEEXzoa4qphsHpbbP1phQNHuEPvCkoQFc_oluOjRZ1TdzyVWSw/s1600/Advanced-Flow.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Detailed authentication flow" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsIcH1mmVWDISeSZmEaZc1fHpgO2rtO5n7kXJ3lADdeXbR8udRtQrJNndfjNRGIgbPyHQoy2nwvREsEgOoFq9LVCLK0XEEXzoa4qphsHpbbP1phQNHuEPvCkoQFc_oluOjRZ1TdzyVWSw/s1600/Advanced-Flow.png" height="354" title="Detailed authentication flow" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
The user enters the public WebApp URL in his browser which leads him to the Reverse Proxy (0). The WebApp has no recent session with the user and therefore does not know the identity of the user. Thus the WebApp redirects the user to its Relying Party IDP (1). The Reverse Proxy detects the redirect to the RP-IDP and adds a home realm parameter for the user (1). This IDP uses this home realm parameter to perform the home realm discovery (3) and thus knowing at which IDP can be redirected to for being authenticated (4). The WS-Federation standard does not define how the home realm discovery should be performed. Multiple options are usually available:<br />
<ul>
<li><b>User Selection</b><br />A list of known and trusted IDPs is shown to the user. The user selects the IDP at which he wants to be authenticated and is then redirected to that IDP.</li>
<li><b>IP Discovery</b><br />The user will be redirected automatically to another IDP based on his IP address.</li>
<li><b>whr Parameter</b><br />The URL to invoke the RP-IDP contains an additional ‘whr’ parameter to define the IDP name on which the user wants to be redirected to for authentication. The ‘whr’ parameter must be known at the RP-IDP and must either be mapped to an URL or can also already be the URL of another IDP). The ‘whr’ parameter is usually set by a Reverse Proxy or was added (by the user or a provided link) in the URL when initially calling the web application.</li>
<li><b>Custom Discovery</b><br />Any custom logic can be added to the IDP to perform the home realm discovery. The standard is not limited to any predefined behaviour.</li>
</ul>
After being redirected to the users home IDP (5) the IDP also has no recent session with the user and thus shows a login form to the user to enter his credentials (6). The user sends his username/password to the IDP, which itself creates an issue request to the STS with the received unsername/password embedded (7). The STS validates the user credentials by using the LDAP. Upon successful authentication the STS retrieves the requested user claims (e.g. roles) from the LDAP (8) and creates a SAML token (9) targeted for the RP-IDP. The Requestor IDP embeds this SAML token inside an auto-submitting (Java Script) web form (10) which is then posted to the RP-IDP (11a). The RP-IDP is now able to use this SAML token to authenticate on behalf of the user against the RP STS (11b) to request a SAML token for the previously requested web application. The RP-STS needs to perform an identity or claim mapping (12) to issue a second SAML token this time applicable for the requested web application (13). The RP-IDP puts this application specific SAML token again in a self-executing HTTP form (14) which is then automatically submitted to the web application via the reverse proxy (15). The Relying Party (the web application) validates the received SAML token by verifying that the issuer certificate of the SAML token is trusted. This should be the case, since the SAML token was issued by its own Relying Party IDP. Additional claims like the user roles can be added to the security context of the web application and thus allowing authorization above authentication.Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com8tag:blogger.com,1999:blog-5257008670669259276.post-90395209493133136402014-10-16T12:04:00.001+02:002014-10-16T12:07:46.920+02:00Integration Testing for STS Extensions with JettyRecently I had to develop some extensions (ClaimHandler, Validator) to the CXF STS. My problem at first was, how to write an integration test that proves the correct implementation of my extensions.<br />
<br />
At first I placed my Mockup classes and web config in the <code>src/main</code> folder from my maven project and added the jetty plugin to my <code>pom.xml</code> file. This way I was able to start my REST MockupService simply by typing <code>mvn jetty:run</code> on the console. After starting the service I was able to execute my test classes directly from Eclipse. But this approach did not satisfy me at all, because now I had lots of files in my main project folder, which would not be needed once I build and deploy my STS extensions to another STS installation. Somehow I needed to move all files (Mockup Service, Spring beans.xml, web.xml, etc.) to the test project folder.<br />
<br />
In this post I'll explain how to setup you maven pom file so that you can use Jetty in your integration test phase if your packaging goal is not a war file but a simple jar file instead and all your web configuration and classes are located in your test folder.<br />
<br />
<a name='more'></a>There are two Blogs which I found very helpful to get my use case up and running:<br />
<ol>
<li><a href="http://www.benoitschweblin.com/2013/03/run-jetty-in-maven-life-cycle.html" target="_blank">Run Jetty in the Maven life-cycle</a></li>
<li><a href="http://blog.52north.org/2013/03/07/end-to-end-client-server-integration-testing-with-maven-project-setup/" target="_blank">End-to-End Client-Server Integration Testing with Maven – Project Setup</a></li>
</ol>
First of all I moved my complete <code>src/main/webapp</code> folder to <code>src/test/webapp</code> as well as <code>src/main/resources</code> to <code>src/test/resources</code> since I needed these files only for testing. The same was true for some of my classes in <code>src/main/java</code> which I moved to <code>src/test/java</code>. Now my <code>src/main/</code> folder only contained my Java classes which I needed to provide my new STS extension.<br />
<br />
Next I modified my <code>pom.xml</code> file and changed the packaging from <code>war</code> to <code>jar</code>. My goal was to add this maven project later as a dependency to another project which would result as a lib in the STS war archive.<br />
<h4>
Allocating dynamic network ports to avoid test failures caused by port collisions</h4>
To get a dynamic port binding for my test services, I added a nice maven helper to my build allocating free ports for me:
<br />
<pre class="brush: xml"><project>
. . .
<build>
. . .
<plugins>
. . .
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>reserve-network-port</id>
<goals>
<goal>reserve-network-port</goal>
</goals>
<phase>process-test-resources</phase>
<configuration>
<portNames>
<portName>jettyServerPort</portName>
<portName>jettyServerStopPort</portName>
</portNames>
</configuration>
</execution>
</executions>
</plugin>
<plugins>
<build>
<project></pre>
<br />
To ensure that my test classes can know the correct location of my Mock Services I simply set these dynamic values as a system property, which can be picked up in my test class:<br />
<pre class="brush: xml"><project>
. . .
<build>
. . .
<plugins>
. . .
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.8.1</version>
<executions>
<execution>
<id>integration-test</id>
<goals>
<goal>integration-test</goal>
</goals>
<configuration>
<systemPropertyVariables>
<service.url>http://localhost:${jettyServerPort}/myRestService</service.url>
<sts.url>http://localhost:${jettyServerPort}/SecurityTokenService/UT</sts.url>
</systemPropertyVariables>
</configuration>
</execution>
<execution>
<id>verify</id>
<goals>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugins>
<build>
<project></pre>
<h4>
Jetty Plugin Configuration</h4>
And here comes the really interesting part of telling Jetty to run with classes and configuration files from the <code>src/test</code> project folder:<br />
<pre class="brush: xml"><project>
. . .
<build>
. . .
<plugins>
. . .
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>8.1.5.v20120716</version>
<configuration>
<systemProperties>
<systemProperty>
<name>java.security.auth.login.config</name>
<value>login.jaas</value>
</systemProperty>
<systemProperty>
<name>service.url</name>
<value>http://localhost:8080/myRestService</value>
</systemProperty>
</systemProperties>
<scanIntervalSeconds>5</scanIntervalSeconds>
<webAppConfig>
<resourceBases>
<resourceBase>${project.basedir}/src/test/webapp</resourceBase>
</resourceBases>
</webAppConfig>
<useTestScope>true</useTestScope>
<stopKey>STOP</stopKey>
<stopPort>${jettyServerStopPort}</stopPort>
</configuration>
<executions>
<execution>
<id>start-jetty</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
</goals>
<configuration>
<scanIntervalSeconds>0</scanIntervalSeconds>
<daemon>true</daemon>
<connectors>
<connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
<port>${jettyServerPort}</port>
<maxIdleTime>60000</maxIdleTime>
</connector>
</connectors>
<systemProperties>
<systemProperty>
<name>java.security.auth.login.config</name>
<value>login.jaas</value>
</systemProperty>
<systemProperty>
<name>service.url</name>
<value>http://localhost:${jettyServerPort}/myRestService</value>
</systemProperty>
</systemProperties>
</configuration>
</execution>
<execution>
<id>stop-jetty</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
<plugins>
<build>
<project></pre>
<br />
<div class="text-info">
I tried testing first with version <code>9.2.3.v20140905</code> of the Jetty plugin, but for some reasons I could not discover so quickly the <code>SelectChannelConnector</code> would not work as expected. My test would always run at port <code>8080</code> instead of a dynamically picked port. Therefore I switched back to version <code>8.1.5.v20120716</code> and all was running as desired.</div>
<br />
The most important parts to mention here is to set the <code>resourceBase</code> in the <code>configuration</code> to <code>${project.basedir}/src/test/webapp</code> as well as setting <code>useTestScope</code> to <code>true</code>.<br />
<br />
Since I still wanted to use the port <code>8080</code> when running <code> mvn jetty:run </code> but a dynamic port when running <code> mvn verify</code>, I had to override the port settings accordingly.<br />
<br />
After these changes I was able to build my extensions including the automated integration test, but without any test related code in my <code>src/main/</code> folder.Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com1tag:blogger.com,1999:blog-5257008670669259276.post-32145993337707250282014-10-14T10:05:00.002+02:002014-10-14T11:22:40.209+02:00Using the Talend PDP ouside of an OSGi ContainerIn a <a href="http://janbernhardt.blogspot.de/2014/09/rest-security-saml-authentication-xacml.html">previous post</a> I've explained how to setup a demo application using SAML token for authentication and XACML for authorization in context of REST services.<br />
In this blog I'm going to explain how to setup the Talend PDP ouside of the OSGi container in which it is usually located, so that you are able to use the PDP co-located to your demo application in any JavaEE container. This is especially helpful if your application cannot easily being deployed into the Talend runtime, but requires lots of authorization requests. In these cases it will be best to have the PDP co-located with your app, completely avoiding expensive network calls.<br />
<br />
<a name='more'></a>This post continues with the demo application described in my <a href="http://janbernhardt.blogspot.de/2014/09/rest-security-saml-authentication-xacml.html">previous post</a>. To follow this post you should first read my other post.<br />
<br />
All you need to do to get the PDP dependencies into your demo application war file is to add the following dependency to your to your <code>pom.xml</code> file:<br />
<pre class="brush: xml"><dependency>
<groupId>org.talend.esb.authorization</groupId>
<artifactId>tesb-xacml-pdp-rt</artifactId>
<version>5.4.1</version>
</dependency> </pre>
<br />
<div class="text-info">
<b>This dependency is available to Talend Enterprise Edition only!</b><br />
If
you do not want to use Talend EE you could also use the <a href="http://www.herasaf.org/">HERAS-AF</a> implementation directly. But in this case you will be missing some of the extensions which are only provided by Talend. </div>
<h4>
Standalone PDP </h4>
Next you can setup the PDP as a REST service, taking XACML requests in and returning XACML responses in your <code>/src/main/webapp/WEB-INF/beans.xml</code> file. In this case the demo service will use the localhost network interface to comunicate with the PDP. <br />
<pre class="brush: xml"><?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cxf="http://cxf.apache.org/core" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<context:property-placeholder />
<context:annotation-config />
<bean class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer" />
<bean class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer" />
<jaxrs:server id="services" address="/">
<jaxrs:serviceBeans>
<bean id="helloWorldService" class="org.talend.example.rest.HelloWorld" />
</jaxrs:serviceBeans>
<jaxrs:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
<bean id="samlHandler" class="org.apache.cxf.rs.security.saml.SamlHeaderInHandler" />
</jaxrs:providers>
<jaxrs:properties>
<entry key="ws-security.signature.properties" value="alice.properties" />
</jaxrs:properties>
<jaxrs:inInterceptors>
<bean class="org.talend.esb.authorization.xacml.rt.pep.CXFXACMLAuthorizingInterceptor" id="XACMLInterceptor">
<property name="pdpAddress" value="http://localhost:8080/pdp/authorize" />
<property name="requireRoles" value="false" />
</bean>
</jaxrs:inInterceptors>
</jaxrs:server>
<bean id="prpBean" class="org.talend.esb.authorization.xacml.pdp.herasaf.FilePolicyRetrievalPoint">
<property name="policyURL" value="WEB-INF/pdp-policy.xml" />
</bean>
<bean id="pdpBean" class="org.talend.esb.authorization.xacml.pdp.herasaf.HerasAFPolicyDecisionPoint">
<property name="policyRetrievalPoint" ref="prpBean" />
</bean>
<bean id="pdpServiceBean" class="org.talend.esb.authorization.xacml.pdp.service.PolicyDecisionPointService">
<property name="policyDecisionPoint" ref="pdpBean" />
</bean>
<jaxrs:server address="/pdp/">
<jaxrs:serviceBeans>
<ref bean="pdpServiceBean" />
</jaxrs:serviceBeans>
</jaxrs:server>
</beans> </pre>
<br />
In the above sample the PDP uses a file policy retrieval point to load its authorization policies. The policy file could look like this:<br />
<pre class="brush: xml"><?xml version="1.0" encoding="UTF-8"?>
<Policy PolicyId="ExamplePolicy"
RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:permit-overrides"
xmlns="urn:oasis:names:tc:xacml:2.0:policy:schema:os" >
<Target>
<Resources>
<Resource>
<ResourceMatch MatchId="urn:oasis:names:tc:xacml:1.0:function:string-regexp-match">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">/hello/echo/Sierra.*</AttributeValue>
<ResourceAttributeDesignator DataType="http://www.w3.org/2001/XMLSchema#string"
AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id"/>
</ResourceMatch>
</Resource>
</Resources>
</Target>
<Rule RuleId="ExecuteRule" Effect="Permit">
<Target>
<Actions>
<Action>
<ActionMatch MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">GET</AttributeValue>
<ActionAttributeDesignator DataType="http://www.w3.org/2001/XMLSchema#string"
AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id"/>
</ActionMatch>
</Action>
</Actions>
</Target>
</Rule>
</Policy></pre>
<br />
The above policies only allows GET request to the echo service which are starting with <code class="xml plain">Sierra</code>. This makes it easy to test your PDP endpoint. Calling the first URL should be successfull whereas the second should fail:<br />
<ol>
<li> <a href="http://localhost:8080/hello/echo/SierraTangoNevada">http://localhost:8080/hello/echo/SierraTangoNevada</a></li>
<li><a href="http://localhost:8080/hello/echo/TangoNevada">http://localhost:8080/hello/echo/TangoNevada</a></li>
</ol>
<h4>
Co-Located Setup</h4>
To switch from network connection to direct PDP invocation you need to modify your <code>beans.xml</code> as follows:<br />
<pre class="brush: xml"><?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cxf="http://cxf.apache.org/core" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<context:property-placeholder />
<context:annotation-config />
<bean class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer" />
<bean class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer" />
<jaxrs:server id="services" address="/">
<jaxrs:serviceBeans>
<bean id="helloWorldService" class="org.talend.example.rest.HelloWorld" />
</jaxrs:serviceBeans>
<jaxrs:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
<bean id="samlHandler" class="org.apache.cxf.rs.security.saml.SamlHeaderInHandler" />
</jaxrs:providers>
<jaxrs:properties>
<entry key="ws-security.signature.properties" value="alice.properties" />
</jaxrs:properties>
<jaxrs:inInterceptors>
<bean class="org.talend.esb.authorization.xacml.rt.pep.CXFXACMLAuthorizingInterceptor" id="XACMLInterceptor">
<property name="policyDecisionPoint" ref="pdpBean"/>
<property name="requireRoles" value="false" />
</bean>
</jaxrs:inInterceptors>
</jaxrs:server>
<bean id="prpBean" class="org.talend.esb.authorization.xacml.pdp.herasaf.RBACRegistryAtomPolicyRetrievalPoint">
<property name="registryAtomUrl" value = "http://localhost:8040/services/XacmlRegistryAtom"/>
<property name="policyCachingStrategy" value ="InMemory"/>
<property name="cacheConfiguration" value="pdp-ehcache.xml"/>
<property name="loadPermissionPoliciesOnInit" value="true"/>
<property name="policyReloadInterval" value="10"/>
<property name="validatePolicies" value="false"/>
<property name="authentication" value="NO"/>
<!--property name="username" value="tesb"/>
<property name="password" value="tesb"/-->
</bean>
<bean id="pdpBean" class="org.talend.esb.authorization.xacml.pdp.herasaf.HerasAFPolicyDecisionPoint">
<property name="policyRetrievalPoint" ref="prpBean" />
</bean>
</beans></pre>
<br />
In the above sample I replaced the file policy retrieval point with the Talend policy store retrieval point, thus being able to fetch authorization policies from a central server location. Since these policies will be cached in the PDP the network overhead will be quite low.I also removed the code to setup a remote accessible PDP endpoint but instead I injected the PDP instance directly to the XACML PEP interceptor of the demo application.Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com3tag:blogger.com,1999:blog-5257008670669259276.post-82919830901474516632014-10-13T16:38:00.001+02:002014-10-13T16:42:09.229+02:00Identity Federation - Identity Mapping vs. Claim MappingIdentity and claim mapping become important, when the target realm (A) of a web application is not equal to the home realm (B) of the user. In this case a SAML token from the user (issuer B) cannot directly be validated at the web application (trusting issuer A only). The relaying party IDP of the web application (in realm A) is able to exchange the SAML token from the (trusted) home realm (B) into a SAML token applicable for the target realm (A). This exchange can be based either on identity mapping or on claim mapping. In this post I'm going to explain what's the difference between these two mapping styles and when to use which alternative.<br /><br />
<a name='more'></a>
<div style="text-align: center;">
<!-- TODO: add picture here --></div>
<br />
When the relaying party IDP (A) requests a SAML token on behalf of the user (B) at its STS (A) for a specific application (A), then the relaying party IDP send the SAML token previously received from the users home IDP (B) to its STS (A). The STS validates the SAML token and detects that it was issued from another (trusted) security realm (B). Depending on the STS configuration the new SAML token can be created based on an identity or claim mapping.<br />
<h4>
Identity Mapping</h4>
Identity mapping is usually required if a user is registered in both (target and home realm) security domains with an individual user each. These users can be managed in both security domains independently. They do not need to share the same username, password or other kind of user attributes like assigned roles.<br />
<br />
A good example of this use case can be illustrated by Google and YouTube. Before Google acquired YouTube most users had a normal Google account as well as an independent YouTube account. After the acquisition, Google implemented an identity mapping so that a user with an active Google session (due to previous login) could login to YouTube and Google would ask the user if he/she wants to link both accounts. If the user agreed, he/she was now able to login to Google only, but at the same time he/she could use YouTube without re-authentication and with all settings, playlists, etc. which have been related to their former YouTube account.<br />
<br />
For identity mapping the following constrains apply:<br />
<ul>
<li>Independent user account (including attributes) per security domain </li>
<li>Each account is under local administration </li>
<li>A mapping needs to be defined between account names</li>
<li> No attributes are mapped from one identity to the other </li>
</ul>
<h4>
Claim Mapping</h4>
In case of claim mapping a user is completely managed and under the control of only one domain. Users do not need to be known and managed in other security domains. This reduces the need for identity synchronization and confidential information like user credentials do not need to be propagated to other security domains.<br />
<br />
When the STS receives a SAML token from another (trusted) security realm it does not need to look up a matching identity in his own security domain, but instead creates a new SAML token valid for the target security realm but with the same username as in the provided SAML token from the other domain. If user specific attributes (claims) are of interest for the target domain, the STS can simply copy these attributes into the newly created SAML token or execute a more complex mapping where original values do not need to match new claims neither in number, name nor value. If such a mapping is required, the STS needs to be configured accordingly. See my <a href="http://janbernhardt.blogspot.de/2014/10/sts-claim-mappings-using-jexl-scripts.html">other post</a> about how this can be done.<br />
<br />
A simple claim mapping could be implemented in a way that role claims from a SAML token are also included (one to one) in the newly created SAML token. Alternatively a mapping could be defined to map role claims from one domain into different role claims for the target realm.<br />
<br />
For claim mapping the following constrains apply:<br />
<ul>
<li>User account is only available and managed within its home realm</li>
<li>No user account information is stored in the target realm</li>
<li>If claims are needed in target realm, they need to be mapped accordingly</li>
</ul>
Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com0tag:blogger.com,1999:blog-5257008670669259276.post-84732813369370134582014-10-01T10:17:00.003+02:002014-10-13T11:02:24.738+02:00STS Claim Mappings using JEXL ScriptsBefore CXF version 2.7.13 it was quite difficult to use claim mappings in the STS, because CXF did not provide any generic claim mapping solution but instead required custom Java code for each claim mapping. Beginning of version <a href="https://issues.apache.org/jira/browse/CXF-5925">2.7.13</a> (not yet released) CXF comes with a <a href="https://github.com/apache/cxf/blob/3.0.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/mapper/JexlClaimsMapper.java" target="_blank">JexlClaimsMapper</a> which allows to define claim mappings at configuration time with <a href="http://commons.apache.org/proper/commons-jexl/reference/syntax.html" target="_blank">Java Expression Language</a> (JEXL).<br />
Also a new feature in CXF which goes hand in hand with the JexlCaimsMapper is a special <a href="https://github.com/apache/cxf/blob/3.0.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/mapper/ClaimUtils.java" target="_blank">ClaimUtils</a> class providing methods for common claim handling tasks.<br />
<br />
In this blog I'll write about:<br />
<ul>
<li>How to setup claim mappings in the STS</li>
<li>Basic JEXL Claim Handling </li>
<li>Several JEXL Claim Mapping Samples</li>
</ul>
<a name='more'></a><h3>
STS Claim Mapping Setup</h3>
The best and fastest way to setup a claim mapping scenario in my opinion is to use the <a href="http://cxf.apache.org/fediz.html">CXF Fediz </a>HelloWorld demonstrator. You can also take a look at my <a href="http://janbernhardt.blogspot.de/2014/09/sso-with-fediz-idp-and-kerberos.html">previous blog</a> where I described how to setup the demo app, as well as the IDP and STS. Of course you can omit the Kerberos related steps.<br />
<br />
Once you have the basic HelloWorld Sample up and running, I'll explain how to switch from identity mapping to a claim mapping next.<br />
<h4>
IDP Setup </h4>
First of all you need to tell the IDP in realm B that you need claims for realm A. To do so you must set the <code>requestedClaims</code> property in your <code>idp-realmA</code> bean in <code>idp-config-realmb.xml</code>. Your result should look like the following:<br />
<pre class="brush: xml"><beans >
. . .
<bean id="idp-realmA" class="org.apache.cxf.fediz.service.idp.model.ServiceConfig">
<property name="realm" value="urn:org:apache:cxf:fediz:idp:realm-A" />
<property name="protocol" value="http://docs.oasis-open.org/wsfed/federation/200706" />
<property name="serviceDisplayName" value="Resource IDP Realm A" />
<property name="serviceDescription" value="Resource IDP Realm A" />
<property name="role" value="SecurityTokenServiceType" />
<property name="tokenType" value="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0" />
<property name="lifeTime" value="3600" />
<property name="requestedClaims">
<util:list>
<bean class="org.apache.cxf.fediz.service.idp.model.RequestClaim">
<property name="claimType" value="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" />
<property name="optional" value="false" />
</bean>
<bean class="org.apache.cxf.fediz.service.idp.model.RequestClaim">
<property name="claimType" value="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" />
<property name="optional" value="false" />
</bean>
<bean class="org.apache.cxf.fediz.service.idp.model.RequestClaim">
<property name="claimType" value="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" />
<property name="optional" value="false" />
</bean>
<bean class="org.apache.cxf.fediz.service.idp.model.RequestClaim">
<property name="claimType" value="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role" />
<property name="optional" value="false" />
</bean>
</util:list>
</property>
</bean>
</beans>
</pre>
<br />
In your <code>idp-config-realma.xml</code> you need to change the <code>federationType</code> of your <code>trusted-idp-realmB</code> bean from <code>FederateIdentity</code> to <code>FederateClaims</code>:<br />
<br />
<div class="text-tip">
Since version 1.2 of Fediz the <code>federationType</code> value has changed to <code>FEDERATE_CLAIMS</code> respectively <code>FEDERATE_IDENTITY</code></div>
<pre class="brush: xml"><beans >
. . .
<bean id="trusted-idp-realmB" class="org.apache.cxf.fediz.service.idp.model.TrustedIDPConfig">
<property name="realm" value="urn:org:apache:cxf:fediz:idp:realm-B" />
<property name="cacheTokens" value="true" />
<property name="url" value="https://localhost:${realmB.port}/fediz-idp-remote/federation" />
<property name="certificate" value="realmb.cert" />
<property name="trustType" value="PEER_TRUST" />
<property name="protocol" value="http://docs.oasis-open.org/wsfed/federation/200706" />
<property name="federationType" value="FederateClaims" />
<property name="name" value="REALM B" />
<property name="description" value="IDP of Realm B" />
</bean>
</beans>
</pre>
<h4>
STS Setup </h4>
In case that your STS <code>pom.xml</code> file does not include the
JEXL dependency you can either add this dependency to your STS or
alternatively you can just add this library to your Tomcat lib folder.<br />
<pre class="brush: xml"><dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-jexl</artifactId>
<version>2.1.1</version>
</dependency></pre>
Next you need to update the STS of your relaying party IDP (Realm-A). Here you need to modify the relationship between <code>REALMA</code> and <code>REALMB</code>. For this scenario it would be sufficient to update only the second releationship in the <code>cxf-transport.xml</code> file, but to make the relationship homogeneous I'll set both relationships <code>type</code> from <code>FederateIdentity</code> to <code>FederateClaims</code>. In addition to that I need to add my <code>claimsMapper</code> bean with the <code>JexlClaimsMapper</code> implementation and set the <code>claimsMapper</code> instead of the <code>identityMapper</code> in my relationships.<br />
<pre class="brush: xml"><beans >
. . .
<bean id="claimsMapper" class="org.apache.cxf.sts.claims.mapper.JexlClaimsMapper">
<constructor-arg value="claimMapping.script" />
</bean>
<util:list id="relationships">
<bean class="org.apache.cxf.sts.token.realm.Relationship">
<property name="sourceRealm" value="REALMA" />
<property name="targetRealm" value="REALMB" />
<property name="claimsMapper" ref="claimsMapper" />
<property name="type" value="FederatedClaims" />
</bean>
<bean class="org.apache.cxf.sts.token.realm.Relationship">
<property name="sourceRealm" value="REALMB" />
<property name="targetRealm" value="REALMA" />
<property name="claimsMapper" ref="claimsMapper" />
<property name="type" value="FederatedClaims" />
</bean>
</util:list>
</beans></pre>
<br />
At last you need to add your <code>claimMapping.script</code> (could be any name you want) to your <code>WEB-INF</code> folder of your STS (or any other location that you chose for your <code>JexlClaimsMapper</code>). The content of the <code>claimMapping.script</code> will be discussed in the following sections.<br />
<h3>
Basic JEXL Claim Handling</h3>
The following variables will be available within your custom JEXL script and can be used to determine the outcome of the claim mapping process:<br />
<ul>
<li><code>sourceClaims</code><br />is a <a href="https://github.com/apache/cxf/blob/master/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/ProcessedClaimCollection.java">ClaimCollection</a> containing all claims provided from the requester IDP/STS (e.g. REALMB) at which the user was authenticated first (e.g. via username/password).</li>
<li><code>targetClaims</code><br />is a <a href="https://github.com/apache/cxf/blob/master/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/ProcessedClaimCollection.java">ClaimCollection</a> in which you need to add all claims that you want to be available after the claim mapping for your target application.</li>
<li><code>sourceRealm</code><br />Realm ID of the requester IDP/STS (e.g. REALMB)</li>
<li><code>targetRealm</code><br />Realm ID of the relaying party IDP/STS (e.g. REALMA)</li>
<li><code>claimsParameters</code><br /><a href="https://github.com/apache/cxf/blob/master/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/ClaimsParameters.java">ClaimsParameter</a> containing additional context information like the STS issuer name and <span class="n">applies to address.</span><span class="o"></span></li>
</ul>
JEXL also supports registration of custom classes to be used within your script. This makes it possible to transfer complex code to a Java class and thus simplifying your script code. By default the <a href="https://github.com/apache/cxf/blob/3.0.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/mapper/ClaimUtils.java" target="_blank">ClaimUtils</a> class will be available via the following syntax: <code>claims:<methodname>(<parameter>...)</code>. This util class provides several convenience methods to simplify claim handling like getting claims from a specific type out of a <a href="https://github.com/apache/cxf/blob/master/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/ProcessedClaimCollection.java">ClaimCollection</a>, mapping claim values, etc. You will find several samples in the following section.<br />
<br />
<div class="text-info">
The last statement in your script should always return the <code>targetClaims</code>!</div>
<br />
Each claim can contain an <code>issuer</code> and an <code>originalIssuer</code> attribute. By calling the<br />
<br />
<code>claims:updateIssuer(targetClaims, "new issuer")</code><br />
<br />
method you can set your current STS as the <code>issuer</code> of the <code>targetClaims</code> as well as setting the <code>originalIssuer</code> (in your <code>targetClaims</code>) which was the <code>issuer</code> in your <code>sourceClaims</code>. Since the <code>claimsParameters</code> are also available within your JEXL script you can set the current STS issuer name in your claims via <code>claimsParameters.stsProperties.issuer</code> instead of using a static String like <code>"new issuer"</code>.
<br />
<h3>
Claim Mapping Samples</h3>
In this section I'll show you some common scenarios that you might need, when you want to operate your IDP/STS in claim mapping mode.<br />
<h4>
Copy All</h4>
If all claims regardless of the type and value shall be copied from the original SAML token into the newly generated token the following expression would be sufficient: <br />
<pre class="brush: java">{
// Update claim issuer
targetClaims = claims:updateIssuer(sourceClaims, claimsParameters.stsProperties.issuer);
// Return all claims
return targetClaims;
}
</pre>
<h4>
Copy Roles Only</h4>
A simple JEXL script to copy all roles from the source SAML token
which was contained in the <code>onBehalfOf</code> token request to
the requested target SAML token could look like the following:<br />
<pre class="brush: java">{
// Get all role claims
var roleClaimType = 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role';
var roleClaim = claims:get(sourceClaims, roleClaimType);
// Copy role claims for new token
targetClaims = claims:add(targetClaims, roleClaim);
// Update claim issuer
targetClaims = claims:updateIssuer(targetClaims, claimsParameters.stsProperties.issuer);
// Return new claims
return targetClaims;
}</pre>
<h4>
Role Value Filter</h4>
The following sample can be used in a scenario when your source role claim contains all role values comma separated in a single claim value and you want the target claim to contain distinct role values which match a specific regular expression (e.g. start with 'ROLE_'): <br />
<pre class="brush: java">{
// Get role claim
var roleClaimType = 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role';
var roleClaim = claims:get(sourceClaims, roleClaimType);
// Split multi role values
roleClaim = claims:multiToSingleValue(roleClaim, ",");
// Filter role values
roleClaim = claims:filterValues(roleClaim, "ROLE_.*");
// Add mapped role claims for new token
targetClaims = claims:add(targetClaims, roleClaim);
// Update claim issuer
targetClaims = claims:updateIssuer(targetClaims, claimsParameters.stsProperties.issuer);
// Return new claims
return targetClaims;
}
</pre>
<h4>
Map Role Claims</h4>
The following sample shows a role mapping with a custom map (originalRoleName => newRoleName): <br />
<pre class="brush: java">{
// Role value mapping
var roleClaimType = 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role';
var roleClaim = claims:get(sourceClaims, roleClaimType);
var roleMappings = { "admin" : "administrator", "manager" : "manager" };
var mappedRoles = claims:mapValues(roleClaim, roleMappings, false);
// Add mapped role claims for new token
targetClaims = claims:add(targetClaims, mappedRoles);
// Update claim issuer
targetClaims = claims:updateIssuer(targetClaims, claimsParameters.stsProperties.issuer);
// Return new claims
return targetClaims;
}
</pre>
<h4>
Claim Merges</h4>
It is also possible to define script variables to improve readability. The following sample shows a many-too-one claim mapping whereby the first and last name of a person is transformed into a fullname claim, as well as copying all email addresses from the source SAML token: <br />
<pre class="brush: java">{
// Merge firstname and lastname to fullname claim
var delimiter = ' ';
var firstNameClaimType = 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname';
var lastNameClaimType = 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname';
var fullNameClaimType = 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name';
var fullNameClaim = claims:merge(sourceClaims, fullNameClaimType, delimiter, firstNameClaimType, lastNameClaimType);
// Simple claim copy
var emailClaimType = 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/mail';
var emailClaim = claims:get(sourceClaims, emailClaimType);
// Add fullname claim and email claim for new token
targetClaims = claims:add(targetClaims, fullNameClaim, emailClaim);
// Update claim issuer
targetClaims = claims:updateIssuer(targetClaims, claimsParameters.stsProperties.issuer);
// Return new claims
return targetClaims;
}
</pre>
<h4>
More complex Sample</h4>
The following sample shows a more "real life" sample of how roles claims are transferred from one domain to another by changing the role claim type, filtering for app specific roles, mapping one to many and normalizing the result:<br />
<pre class="brush: java">{
// Get roles
var sourceRoleClaimType = 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role';
var roleClaims = claims:get(sourceClaims, sourceRoleClaimType);
// Update role claim type
var targetRoleClaimType = 'http://schemas.mycompany.com/security/authorization/claims/role';
roleClaims = claims:setType(roleClaims, targetRoleClaimType);
// Normalize role claim values
roleClaims = claims:singleToMultiValue(roleClaims, ",");
// Application role filter
roleClaims = claims:filterValues(roleClaims, 'AppName_[a-zA-Z_]+');
// Map role claims
var roleMappings = {
"AppName_Agent" : "AppName_User, Agent",
"AppName_Broker_DE" : "AppName_User, AppName_Broker",
"AppName_Partner_Agents" : "AppName_User, AppName_Partner, External"
};
roleClaims = claims:mapValues(roleClaims, roleMappings, false);
roleClaims = claims:singleToMultiValue(roleClaims, ", ");
// Remove duplicates
if (roleClaims != null) {
var distinctValues = new("java.util.LinkedHashSet", roleClaims.values);
roleClaims.values.clear();
roleClaims.values.addAll(distinctValues);
}
// Collect claims for new token
if (roleClaims != null && roleClaims.values.size() > 0) {
targetClaims = claims:add(targetClaims, roleClaims);
}
// Set correct issuer
targetClaims = claims:updateIssuer(targetClaims, claimsParameters.stsProperties.issuer);
// Return new claims
return targetClaims;
}
</pre>
<h4>
Plain JEXL Only</h4>
If you do not want to use any util classes in your JEXL script you can also script more complex cases directly within your script. The following sample shall give you just an idea on who this could look like:<br />
<pre class="brush: java">{
// Role value mapping
var roleClaimType = 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role';
var roleMappings = { "admin" : "administrator", "manager" : "manager" };
for (c : sourceClaims) {
if(c.claimType == roleClaimType) {
var mappedValues = new("java.util.ArrayList");
for (v : c.values) {
v = v.toUpperCase();
var newValue = roleMappings.get(v);
if (newValue != null) {
mappedValues.add(newValue);
}
}
c.values = mappedValues;
targetClaims.add(c);
}
}
// Set correct issuer
for (c : targetClaims) {
if(c.originalIssuer == null) {
c.originalIssuer = c.issuer;
}
c.issuer = claimsParameters.stsProperties.issuer;
}
// Return new claims
return targetClaims;
}</pre>
Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com0tag:blogger.com,1999:blog-5257008670669259276.post-28257952941033103922014-09-29T14:13:00.000+02:002014-12-04T09:23:12.452+01:00SSO with Fediz IDP and Kerberos<h3 class="post-title entry-title" itemprop="name">
</h3>
<div class="post-header">
</div>
<a href="http://coheigea.blogspot.de/" target="_blank">Colm O hEigeartaigh</a> extended <a href="http://cxf.apache.org/fediz.html" target="_blank">Fediz IDP</a>
just recently to allow browser-based Kerberos authentication at the
IDP. In this blog I'm going to explain how to setup your system environment to provide WS-Federation
based SSO for a normal web application:<br />
<ul>
<li>Prepare your Active Directory</li>
<li>Installing the Fediz Demo Application</li>
<li>Installing Fediz IDP and a Kerberos enabled STS</li>
<li>Enable Kerberos for your Browser </li>
</ul>
<a name='more'></a><h3>
Preparing Active Directory</h3>
To setup my test environment I needed a Active Directory service
providing my test users and Kerberos support. After installing a Windows
Server 2008 R2 Enterprise Edition server, I added the Active Directory
feature according to a <a href="http://www.rackspace.com/knowledge_center/article/installing-active-directory-on-windows-server-2008-r2-enterprise-64-bit" target="_blank">well written post</a>, which I found on the internet.<br />
<h4>
Adding users and groups</h4>
After that I created two new security groups:<br />
<ul>
<li><code>manager</code></li>
<li><code>employee</code></li>
</ul>
For being able to choose trivial passwords for my test users, I <a href="http://serverfault.com/questions/19611/disable-password-complexity-rule-in-active-directory" target="_blank">disabled the global password policy</a> as well as the <a href="http://windows.microsoft.com/de-de/windows/change-password-policy-settings#1TC=windows-7" target="_blank">local password policy</a>.<br />
<br />
After that I added the following users to my active directory:<br />
<ul></ul>
<ul>
<li><code>alice@MYDOMAIN.COM</code></li>
<li><code>bob@MYDOMAIN.COM</code></li>
<li><code>idp/idp-host.mydomain.com@MYDOMAIN.COM</code></li>
</ul>
<ul></ul>
<br />
I also added Alice to the group <code>manager</code> and <code>employee</code>, as well as Bob to the group <code>employee</code> only.<br />
<h4>
</h4>
<h4>
Adding Service Principal Name to the IDP user</h4>
If a browser requests a Kerberos token for a webpage the Kerberos token
will always be requested for the following ServicePrincipalName: <code>HTTP/my.idp-website.com</code>.<br />
Therefore I need to add the matching SPN to my AD user <code>idp/myhost.mydomain.com@MYDOMAIN.COM</code>.<br />
<br />
<div class="text-info">
I my case I had some trouble with the normal account name, but with the pre-Windows2000 name it was working without issues. The pre-Windows200 account name of my idp would be <code>MYDOMAIN\idp_myhost</code>.</div>
<br />
You need to enter the following command on a console at your domain controller:<br />
<br />
<code>
C:\> setspn -A HTTP/idp-host.mydomain.com MYDOMAIN\idp_myhost</code><br />
<code>C:\> setspn -A HTTP/idp-host MYDOMAIN\idp_myhost</code><br />
<br />
<div class="text-tip">
If your IDP Server is accessible via multiple domain names (only DNS A-Records are considered), you should also add multiple SPNs to your IDP user.</div>
<br />
You can use the following command to validate that you set the correct SPNs:<br />
<br />
<code>C:\> setspn -Q HTTP/*</code><br />
<br />
You should also make sure that you have a SPN set only once! You can validate this with the following command:<br />
<br />
<code>C:\> setspn -X</code><br />
<br />
<div class="text-alert">
It is very important, that you also add the correct DNS names for your
IDP in your Windows DNS Server. You cannot use an IP address directly
for the IDP server. If you do so your browser will not request a correct
Kerberos ticket for your IDP!</div>
<h4>
Extracting service private key from Kerberos</h4>
<br />
<div class="text-info">
I used username/password authentication for the IDP user in the STS Kerberos token validator, which does not require to extract a keytab file from your Active Directory server. If you do use this keytab file you do not need to provide username/password instead.</div>
<br />
The STS needs access to its own keytab file for being able to
validate the Kerberos authentication of the user. Therefore we need to extract the private key to a file.<br />
<br />
<code>
ktpass -princ idp/idp-host.mydomain.com@MYDOMAIN.COM -mapuser
MYDOMAIN\IdpMyHost -pass password -crypto All -kvno 0 -ptype KRB5_NT_PRINCIPAL
-out c:\temp\IdpMyHost.keytab
</code>
<br />
<br />
The extracted keytab file must be transfered to the server where the IDP and STS will be installed.<br />
<h3>
Installing Demo Application</h3>
<a href="http://tomcat.apache.org/download-70.cgi" target="_blank">Download</a> and <a href="http://tomcat.apache.org/tomcat-8.0-doc/setup.html" target="_blank">setup</a> Apache Tomcat 7 as usual.<br />
<code> </code>
<br />
After that you must define a <code>fediz_config.xml</code> <a href="http://cxf.apache.org/fediz-configuration.html" target="_blank">configuration file</a> for the Fediz plugin in the <code>conf</code> folder from Tomcat. You can find <a href="http://cxf.apache.org/fediz-tomcat.html" target="_blank">further steps</a> to setup Tomcat on the Apache website.<br />
<br />
<pre class="brush: xml"><?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<FedizConfig>
<contextConfig name="/fedizhelloworld">
<audienceUris>
<audienceItem>urn:org:apache:cxf:fediz:fedizhelloworld</audienceItem>
</audienceUris>
<certificateStores>
<trustManager>
<keyStore file="ststrust.jks" password="storepass" type="JKS" />
</trustManager>
</certificateStores>
<trustedIssuers>
<issuer certificateValidation="PeerTrust" />
</trustedIssuers>
<maximumClockSkew>1000</maximumClockSkew>
<protocol xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="federationProtocolType" version="1.0.0">
<realm>urn:org:apache:cxf:fediz:fedizhelloworld</realm>
<issuer>https://localhost:9443/fediz-idp/federation</issuer>
<roleDelimiter>,</roleDelimiter>
<roleURI>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role</roleURI>
<claimTypesRequested>
<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role" optional="false" />
</claimTypesRequested>
</protocol>
</contextConfig>
</FedizConfig>
</pre>
Now you can <a href="https://github.com/apache/cxf-fediz" target="_blank">download</a> the the latest version of Fediz from github. Next you need to build all Fediz dependencies with <a href="http://maven.apache.org/" target="_blank">maven</a> and copy them to the <code>lib/fediz</code> folder of your Tomcat installation. Go to <code>cxf-fediz/plugins/tomcat</code> and execute the following command:<br />
<br />
<code>mvn clean install</code><br />
<br />
You must also update the <code>common.loader</code> property in <code>conf/catalina.properties</code>:<br />
<pre class="brush: js">common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar,${catalina.home}/lib/fediz/*.jar</pre>
<br />
Next you can build the example web application. Go to <code>cxf-fediz/examples/simpleWebapp</code> and build your webapp again with maven:<br />
<br />
<code>mvn clean install</code><br />
<br />
You must then copy the war file of the example web application to your Tomcat <code>webapps</code> folder.<br />
<br />
Now you can start your relying party Tomcat container.<br />
<br />
If you open <a href="http://localhost:8080/fedizhelloworld/" target="_blank">http://localhost:8080/fedizhelloworld/</a> in your browser you should see a "Hello World" message.<br />
If you go to <a href="http://localhost:8080/fedizhelloworld/secure/fedservlet" target="_blank">http://localhost:8080/fedizhelloworld/secure/fedservlet</a> you will be redirected to the IDP which we will setup next.<br />
<h3>
Installing Fediz IDP & STS</h3>
<h4>
Tomcat Setup</h4>
Make sure that the JDK has
<a href="http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html" target="_blank">unlimited security policies </a>installed. Since we already have a running
Tomcat 7 installation for the relying party we will just copy that
installation and deleting the <code>fedizhelloworld</code> web application from the <code>webapps/</code> folder as well as the <code>fediz_config.xml</code> configuration file in the <code>conf/</code>
folder. If we plan to run both Tomcat Server on the same machine we
must also update the server ports in the <code>conf/server.xml</code> file.<br />
<pre class="brush: xml"><Connector port="9443" protocol="org.apache.coyote.http11.Http11Protocol"
maxHttpHeaderSize="65536"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
keystoreFile="idp-ssl-server.jks"
keystorePass="tompass"
truststoreFile="idp-ssl-server.jks"
truststorePass="tompass"
truststoreType="JKS"
SSLVerifyClient="optional"
clientAuth="want"
sslProtocol="TLS" />
</pre>
<div class="text-alert">
It is very important that you increase the default max header size from tomcat. Otherwise some of your users will get a <code>401 Bad Request</code> Error if the Kerberos token is bigger than 8kb.
</div>
<br />
<div class="text-info">
You must also set <code>clientAuth</code> to <code>want</code> and configure a trust-store, if you run IDP and STS in the same Tomcat container, because the STS requires x509 client authentication.
</div>
<br />
Since the IDP uses JPA (since version 1.2) to store its configuration settings, we must also download
the matching <a href="http://mirrors.ibiblio.org/maven2/hsqldb/hsqldb/" target="_blank">JDBC driver</a> and place the driver to our Tomcat lib folder.
Next we must set the domain name or IP address of the KDC Kerberos server. This we can do best by setting a JVM parameter via <span style="font-family: "Courier New",Courier,monospace;">CATALINA_OPTS</span> by creating or updating the <span style="font-family: "Courier New",Courier,monospace;">setenv.bat</span> respectively <span style="font-family: "Courier New",Courier,monospace;">setenv.sh</span> in the Tomcat bin folder:
<br />
<pre class="brush: js">set CATALINA_OPTS=%CATALINA_OPTS% "-Djava.security.krb5.kdc=192.168.1.10 -Djava.security.krb5.realm=MYDOMAIN.COM -Djava.security.auth.login.config=file:/C:/Fediz-IDP-A/webapps/fediz-idp/WEB-INF/kerberos.jaas -Dsun.security.krb5.debug=true"</pre>
<div class="text-alert">
If you are planing on running your IDP/STS Tomcat container as a system service, you must modify the <code>service.bat</code> file to ensure that you set the required Kerberos JVM parameter correctly. Otherwise your Tomcat will start without these parameters and Kerberos authentication will fail.</div>
<h4>
SSL Certificate</h4>
Providing a trusted SSL Certificate for the
IDP helps to avoid irritating warnings from the browser when users
access the IDP via a HTTPs connection. Since all computer of a Active Directory Domain share common trusted domain certificates, we can create a new webserver key at the AD which will be trusted by all participants of the domain.
<br />
<br />
<div class="text-tip">
The certificate is only trusted at the Internet Explorer by default. To extend this trust to Firefox as well, you need to install the domain certificate manually into the trusted issuer store of Firefox.</div>
<br />
To do this you must define a
certificate webserver policy at the AD server which allows the export of
a private key. Next we need to create a new private/public key
pair at the server with the common name (CN) being equal to the domain
name of our IDP. After creating the certificate we need to export the key pair to a PKCS #12 file format.
I like to use the <a href="http://keystore-explorer.sourceforge.net/" target="_blank">KeyStore Explorer</a> best to manage Java keystores. The KeyStore Explorer is also able to import the keypair export from the AD server. To set the correct key for the IDP Tomcat server, you need to replace the <code>mytomidpkey</code> key in the <code>idp-ssl-server.jks</code> keystore.
<br />
<h4>
Download or Build the IDP/STS</h4>
You can either download the IDP/STS from Apache webpage or you can build the IDP and STS again with maven. If you build your services from code, you can also update the configuration files before you build your war files. In that case you do not need to modify them later on.
If you want to use Maven to build your own services execute the following command:
<code>mvn clean install -Pkerberos</code>
After deploying the <code>fediz-idp.war</code> and <code>fediz-idp-sts.war</code> to tomcat, you need to update the following configuration files according to your needs.
<br />
<h4>
STS Configuration</h4>
The <code>kerberos.jaas</code> file must be updated for the STS to match with our Kerberos idp principal:
<br />
<pre class="brush: java">idp {
com.sun.security.auth.module.Krb5LoginModule required
refreshKrb5Config=true
storeKey=true
principal="idp/idp-host.mydomain.com@MYDOMAIN.COM";
};
</pre>
Make sure that the <code>cxf-transport.xml</code> file imports the <code>kerberos.xml</code> file, which should already be the case if you build the STS with the <code>kerberos</code> Maven profile.
Most changes required to enable Kerberos Authentication and Active Directory Claim Handling needs to be configured in the <code>kerberos.xml</code> file. You need to add the LDAP Claim Handler as well as the Kerberos Token Validator. If you use a kerberos keytab file for the IDP you do not need to set a callbackHandler for the kerberos token validator but the location to your keytab file instead.
<br />
<pre class="brush: xml"><?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.0.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">
<util:list id="claimHandlerList">
<ref bean="claimsHandlerA" />
<ref bean="claimsHandlerB" />
</util:list>
<bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource">
<property name="url" value="ldap://ad-host.mydomain.com:389" />
<property name="userDn"
value="CN=IDP,OU=People,DC=mydomain,DC=com" />
<property name="password" value="secretPwd" />
</bean>
<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
<constructor-arg ref="contextSource" />
</bean>
<util:map id="claimsToLdapAttributeMapping">
<entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role" value="memberOf" />
<entry key="http://schemas.zurich.com/security/authorization/de/2013/05/claims/role" value="memberOf" />
<entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" value="givenName" />
<entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" value="sn" />
<entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" value="mail" />
<entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/country" value="c" />
</util:map>
<bean id="claimsHandlerA" class="org.apache.cxf.sts.claims.LdapClaimsHandler">
<property name="ldapTemplate" ref="ldapTemplate" />
<property name="claimsLdapAttributeMapping" ref="claimsToLdapAttributeMapping" />
<property name="userNameAttribute" value="userPrincipalName" />
<property name="userBaseDN" value="OU=People,DC=mydomain,DC=com" />
<property name="realm" value="REALMA" />
</bean>
<bean id="kerberosValidator" class="org.apache.ws.security.validate.KerberosTokenValidator">
<property name="contextName" value="idp"/>
<property name="serviceName" value="HTTP/idp-host.mydomain.com@MYDOMAIN.COM"/>
<property name="usernameServiceNameForm" value="true"/>
<property name="spnego" value="true"/>
<property name="callbackHandler">
<bean class="com.sun.jndi.ldap.sasl.DefaultCallbackHandler">
<constructor-arg index="0" value="idp/idp-host.mydomain.com@MYDOMAIN.COM"/>
<constructor-arg index="1" value="secretPwd"/>
<constructor-arg index="2" value="MYDOMAIN.COM"/>
</bean>
</property>
</bean>
<jaxws:endpoint id="transportSTSRealmAKerberos"
implementor="#transportSTSProviderBean" address="/REALMA/STSServiceTransportKerberos"
wsdlLocation="/WEB-INF/wsdl/ws-trust-1.4-service.wsdl"
xmlns:ns1="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
serviceName="ns1:SecurityTokenService" endpointName="ns1:TransportKerberos_Port">
<jaxws:properties>
<entry key="ws-security.bst.validator" value-ref="kerberosValidator"/>
</jaxws:properties>
</jaxws:endpoint>
<jaxws:endpoint id="transportSTSRealmBKerberos"
implementor="#transportSTSProviderBean" address="/REALMB/STSServiceTransportKerberos"
wsdlLocation="/WEB-INF/wsdl/ws-trust-1.4-service.wsdl"
xmlns:ns1="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
serviceName="ns1:SecurityTokenService" endpointName="ns1:TransportKerberos_Port">
<jaxws:properties>
<entry key="ws-security.bst.validator" value-ref="kerberosValidator"/>
</jaxws:properties>
</jaxws:endpoint>
</beans>
</pre>
<h4>
IDP Configuration</h4>
The content of the <code>security-config.xml</code> file must be replaced with the content of <code>security-config-kerberos.xml</code>:
<br />
<pre class="brush: xml"><?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<context:property-placeholder location="classpath:realm.properties"/>
<context:component-scan base-package="org.apache.cxf.fediz.service.idp"/>
<!-- Configure Spring Security -->
<security:http auto-config="false" use-expressions="true" entry-point-ref="kerberosEntryPoint">
<security:custom-filter after="CHANNEL_FILTER" ref="stsPortFilter" />
<security:intercept-url pattern="/FederationMetadata/2007-06/FederationMetadata.xml" access="isAnonymous() or isAuthenticated()" />
<!--<security:http-basic />-->
<!--<security:form-login />-->
<security:custom-filter ref="kerberosAuthenticationProcessingFilter" position="BASIC_AUTH_FILTER" />
</security:http>
<bean id="kerberosEntryPoint"
class="org.apache.cxf.fediz.service.idp.kerberos.KerberosEntryPoint" />
<bean id="kerberosAuthenticationProcessingFilter"
class="org.apache.cxf.fediz.service.idp.kerberos.KerberosAuthenticationProcessingFilter">
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="stsAuthProvider" />
</security:authentication-manager>
<bean id="stsPortFilter" class="org.apache.cxf.fediz.service.idp.STSPortFilter" />
<bean id="stsAuthProvider" class="org.apache.cxf.fediz.service.idp.STSAuthenticationProvider">
<property name="wsdlLocation" value="https://localhost:0/fediz-idp-sts/${realm.STS_URI}/STSServiceTransportKerberos?wsdl"/>
<property name="wsdlEndpoint" value="TransportKerberos_Port"/>
<property name="wsdlService" value="SecurityTokenService"/>
<property name="appliesTo" value="urn:fediz:idp"/>
<property name="tokenType" value="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0"/>
</bean>
</beans>
</pre>
<h3>
Enabling Kerberos Support for your browser</h3>
By default your browser will not send any Kerberos token to a normal Webpage.
In IE you need to add the IDP URL to the list of trusted sides or even to local intranet sides.
In Firefox you need to open <code>about:config</code> and add the IDP URL to <code>network.negotiate-auth.delegation-uris</code> and <code>network.negotiate-auth.trusted-uris</code>.
I found <a href="http://www.oracle.com/technetwork/articles/idm/weblogic-sso-kerberos-1619890.html" target="_blank">this article</a> from Oracle most helpful to setup my browser correctly.
<br />
<h3>
Troubleshooting</h3>
You can use the <code>klist</code> command at your client to verify that the correct Kerberos token are used on your local machine. <code>klist purge</code> will remove all cached Kerberos tokens on your computer.
You can use <a href="https://www.wireshark.org/" target="_blank">Wireshark</a> to analyse your web traffic. This is especially helpful to see what kind of token Kerbeidp-ssl-server.jksros/SPNEGO your browser is sending to the IDP.
<a href="http://www.telerik.com/fiddler" target="_blank">Fiddler</a> is helpful to analyze if all the redirects from your Webapp to the IDP and back actually work as expected.
<br />
<h3>
Links</h3>
<ul>
<li>http://docs.fedoraproject.org/en-US/Fedora/html/Security_Guide/sect-Security_Guide-Single_Sign_on_SSO-Configuring_Firefox_to_use_Kerberos_for_SSO.html</li>
<li>http://superuser.com/questions/5161/windows-domain-authentication-with-firefox</li>
<li>http://www-01.ibm.com/support/knowledgecenter/SSCKBL_8.5.5/com.ibm.websphere.nd.multiplatform.doc/ae/tsec_SPNEGO_config_dc.html</li>
<li>http://blogs.iis.net/brian-murphy-booth/archive/2007/03/09/the-biggest-mistake-serviceprincipalname-s.aspx</li>
<li>http://www.novell.com/documentation/novellaccessmanager/adminguide/data/b9uctt5.html</li>
<li>http://www.oracle.com/technetwork/articles/idm/weblogic-sso-kerberos-1619890.html</li>
</ul>
Jan Bernhardthttp://www.blogger.com/profile/04467648148765096890noreply@blogger.com1