OpenAM as Identity Provider / Fedlet as Service Provider – Federated Single Sign On

Context

In this post, I will show how you can configure OpenAM as Identity Provider (IdP) and use another tomcat instance to install, deploy and configure a Fedlet. A Fedlet is a lightweight way for service providers to quickly federate with a SAML 2.0 identity provider. Let’s describe those steps in the detail.

Required Steps

  1. Configure OpenAM as Identity Provider, define the Circle of Trust (cot) and create a fedlet
  2. Create and Configure Fedlet from your OpenAM (IDP) instance
  3. Install another tomcat instance , deploy the fedlet and test the federation

Step1: Configure OpenAM as IdP

  • Login into your OpenAM instance as amAdmin, click Common Task and click on “Create Hosted Identity Provider”
  • Provide the following information:
    • Do you have metadata for this provider: No
    • Metadata Name: an accessible URL from internet and preferably secure with HTTPS for example https://cmok.kwaoo.me:8443/OpenAM-13.0.0
    • Metadata Signing Key: select test from the dropdown
    • Create a new Circle of Trust and provide a name e.g salesforce-cot
    • Create an attribute mapping between the attributes used in SAML assertion and attributes of your local data store
      • Name in Assertion: ssoid
      • Local Attribute Name: uid
    • Click Configure & Finished

 

IDP / Assertion Content Tab


IDP - Assertion Content - 2016-03-13_15-33-58

IDP / Assertion Processing Tab


IDP Assertion Processing - 2016-03-13_15-34-56

IDP / Service  Tab


IDP Services - 2016-03-13_15-35-50

IDP / Advanced  Tab


IDP Advanced - 2016-03-13_15-36-43

Step2: Create and configure a Fedlet

  • Connect to your OpenAM Idp and click on Common Task, create a Fedlet

    CreateAFedlet-2016-03-13_14-52-57


    Create your Fedlet - 2016-03-13_14-49-24

Step3: Install another tomcat instance, deploy the fedlet and test the federation

  1. Install another tomcat instance. As I have installed it on the same VM, I need to change the standard tomcat port to avoid conflict. I have added +100 to the following ports:
    1. 8005
    2. 8080
    3. 8009
    4. 8443
  • Open theses port in your firewall to allow access from Internet
  • Configure your tomcat instance to use HTTPS

Open your tomcat configuration file Server.xml and add this section :

<Connector protocol="org.apache.coyote.http11.Http11NioProtocol" port="8543" maxThreads="200" scheme="https" secure="true" SSLEnabled="true" keystoreFile="E:/apache-tomcat-8.0.26/certificate/tomcat8_keystore.jks" keystorePass="xxxxx" clientAuth="false" sslProtocol="TLS" URIEncoding="UTF-8"/>	
  • Unzip the Fedlet Zip generated in $HOME/OpenAM-12.0.0/myfledlets/fedlet/Fedlet.zip
  • Copy the WAR into your $TOMCAT/webapp location folder (I have unzip the fedlet.war in order to change some JSP code, reflecting my needs)
  • Configure the fedlet using this URL :  https://cmok.kwaoo.me:8543/fedlet/

  • FedletConfiguration_2016-03-13_15-13-05


    Validate Fedlet Setup - 2016-03-13_15-15-15

  • Click on the link Fedlet (SP) Initiated Login

  • Successfull SSO with OpenAM as Idp - 2016-03-13_15-21-49

Fedlet SP / Assertion Content


Fedlet SP Assertion Content - 2016-03-13_15-38-34

Fedlet SP / Assertion Processing


Fedlet SP Assertion Processing - 2016-03-13_15-39-26

Fedlet SP / Services


Fedlet SP Services - 2016-03-13_15-40-19

Fedlet SP / Advanced


Fedlet SP Advanced - 2016-03-13_15-40-56

IdP – Federation Tab


IDP Federation Tab - 2016-03-13_15-41-43

IdP – Circle of Trust


IDP Circle of Trust - 2016-03-13_15-42-18

 
Thanks for reading.

Advertisements
Posted in Salesforce | Tagged , , ,

OpenAM as Identity provider / Salesforce as Service Provider – Federated Single Sign On

Context

Working with Salesforce, you often need to integrate with an enterprise scale Identity Provider like OpenAM. In this post, I will show how you can configure OpenAM as Identity Provider (IdP) and use Salesforce as Service provider (either to access the Salesforce Org itself as an Administrator, or accessing a Salesforce Community as a partner user).  The way of how Salesforce build its product make the Single Sign On configuration done in a few click. We need more steps and configuration on the OpenAM side. Let’s describe those steps in the detail.

Required Steps

  1. Configure OpenAM as Identity Provider, define the Circle of Trust (cot) and create attributes mapping
  2. Configure Salesforce as Service Provider: activate My Domain, get the OpenAM public certificate, setup the Single Sign On setting, set the Federation ID
  3. Import the Salesforce Metadata into OpenAM and verify/configure the federation settings
  4. Test the Single Sign On – SP initiated login
  5. SP initiated login – Technical messages exchanges

Step1: Configure OpenAM as IdP

  • Login into your OpenAM instance as amAdmin, click Common Task and click on “Create Hosted Identity Provider”
  • Provide the following information:
    • Do you have metadata for this provider: No
    • Metadata Name: an accessible URL from internet and preferably secure with HTTPS for example https://cmok.kwaoo.me:8443/OpenAM-13.0.0
    • Metadata Signing Key: select test from the dropdown
    • Create a new Circle of Trust and provide a name e.g salesforce-cot
    • Create an attribute mapping between the attributes used in SAML assertion and attributes of your local data store
      • Name in Assertion: ssoid
      • Local Attribute Name: uid
    • Click Configure & Finished


Create a SAML v2 Identity Provider on this Server_2016-03-13_10-51-11

IDP / Assertion Content Tab


IDPAssertionContent_2016-03-13_10-55-22

IDP / Assertion Processing Tab


Assertion Processing - 2016-03-13_11-04-12

IDP / Service  Tab


Services Tab - 2016-03-13_11-05-42

IDP / Advanced  Tab


IDP Advanced - 2016-03-13_11-09-06

Step2: Configure Salesforce as SP

  • Setup My Domain : activate the 4 steps
    1. Choose Domain Name
    2. Domain Registration Pending
    3. Domain Ready for Testing
    4. Domain deployed to Users


Salesforce My Domain - 2016-03-13_11-16-58

  •  Export the public key from OpenAM
    • got to your $HOME/OpenAM-13.0.0/OpenAM-13.0.0 mine is C:\Users\Chenda\OpenAM-13.0.0\OpenAM-13.0.0
    • run the following command:  keytool -export -keystore keystore.jks -alias test -file openAM13_certificate.cer
  • Setting up Single Sign On Setting


SSO Setting - 2016-03-13_11-30-38

  • Configure the Federation Identifier for your test user – Connecting to your Salesforce as admin user
    • search for your admin user, edit it, assign the federation identifier to demo
    • demo is the OOTB user existing in the default realm (remember we specify SSOID=uid). As we are using uid’s value for the Federation ID between Salesforce and OpenSSO, the Federation ID of this Salesforce test user is assigned with value – demo


AdminUser_FederationIdentifier_2016-03-13_11-38-23

 

Step3: Import Salesforce SP Metadata into OpenAM IdP

  • Go back to your openAM instance as IdP and log with amAdmin
  • Click Federation tab, Entity Provider Section, Click on Import Entity
    • Select the metadata file downloaded from your Salesforce Org instance
    • your SP entry has been added
    • Add your SP into the Circle of Trust

SP / Assertion Content


SP Assertion Content - 2016-03-13_12-34-27

SP / Assertion Processing


SP Assertion Processing - 2016-03-13_12-36-03

SP / Services


SP Services - 2016-03-13_12-37-18

SP / Advanced


SP Advanced - 2016-03-13_12-38-29

IdP – Federation Tab

IDP Federation Tab - 2016-03-13_12-40-15

IdP – Circle of Trust


Circle of Trust - 2016-03-13_12-41-37

Step4: Testing the Single Sign On – SP initiated login

  1. Try to access a private page on Salesforce: https://chendademoidentity-dev-ed.my.salesforce.com/home/home.jsp


    SP Initiated Login - 2016-03-13_13-34-03

  2. If you have multiple IdP defined in Salesforce, select the one you want to test: mine is OpenAM13 IdP
  3. You will be redirect to the OpenAM login page
  4. Enter your credential ( I select user the ootb demo user defined in Your Realm/Subjects) OpenAM

    OpenAM Login Page - 2016-03-13_13-37-26
  5. After a successful login, OpenAM will redirect you to your Salesforce (SP) home page. Et voilà, all done.

    Salesfor Home Page - 2016-03-13_13-39-13

Step5: SP initiated login – Technical messages exchanges

Below the technical steps happening behind the scene

POST
RelayState: /home/home.jsp
SAMLRequest: PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c2FtbHA6QXV0aG5SZXF1ZXN0IHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIEFzc2VydGlvbkNvbnN1bWVyU2VydmljZVVSTD0iaHR0cHM6Ly9jaGVuZGFkZW1vaWRlbnRpdHktZGV2LWVkLm15LnNhbGVzZm9yY2UuY29tP3NvPTAwRDU4MDAwMDAwS0tHZSIgRGVzdGluYXRpb249Imh0dHBzOi8vY21vay5rd2Fvby5tZTo4NDQzL09wZW5BTS0xMy4wLjAvU1NPUE9TVC9tZXRhQWxpYXMvaWRwIiBJRD0iXzJDQUFBQVZRQUV1REtNRTh3TlRnd01EQXdNREEwUXprMkFBQUF5Tld4ZzRnOVVkeVFkYXd2SExRNmF2MHhhZVM5bGNkNk5YYmZseHdld0RRZGpIOE5jcVhEYU41SkpHdVVjblQxOUhMekxGZlJ4Z3FUQjA5UVVXdm1aLTE0VzRuY1lvRGNBdVlMRjE0ZWtFREQwbjBuTkJkSTF0bFU2TVhfanVZYmc4MHN5NG9Ib1FkMTFHZFVqR3NkdkViZ2l2RnVXLVdhbmRXOGQ3OWd6UDVkS1lnZzBLbzUzR0dXYVFHQjAtTjNkd3N6ZHBrRmY3RERZclktZDB3aUhSZW1UUE1QY0ZXQlc0VGt4cHpkNUFqX3pSNEpSMnBNUHFhVWJadWdyZmRjYWciIElzc3VlSW5zdGFudD0iMjAxNi0wMy0xM1QxMjowODo1My40NTlaIiBQcm90b2NvbEJpbmRpbmc9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpiaW5kaW5nczpIVFRQLVBPU1QiIFZlcnNpb249IjIuMCI+PHNhbWw6SXNzdWVyIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iPmh0dHBzOi8vY2hlbmRhZGVtb2lkZW50aXR5LWRldi1lZC5teS5zYWxlc2ZvcmNlLmNvbTwvc2FtbDpJc3N1ZXI+PGRzOlNpZ25hdHVyZSB4bWxuczpkcz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyI+CjxkczpTaWduZWRJbmZvPgo8ZHM6Q2Fub25pY2FsaXphdGlvbk1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPgo8ZHM6U2lnbmF0dXJlTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI3JzYS1zaGExIi8+CjxkczpSZWZlcmVuY2UgVVJJPSIjXzJDQUFBQVZRQUV1REtNRTh3TlRnd01EQXdNREEwUXprMkFBQUF5Tld4ZzRnOVVkeVFkYXd2SExRNmF2MHhhZVM5bGNkNk5YYmZseHdld0RRZGpIOE5jcVhEYU41SkpHdVVjblQxOUhMekxGZlJ4Z3FUQjA5UVVXdm1aLTE0VzRuY1lvRGNBdVlMRjE0ZWtFREQwbjBuTkJkSTF0bFU2TVhfanVZYmc4MHN5NG9Ib1FkMTFHZFVqR3NkdkViZ2l2RnVXLVdhbmRXOGQ3OWd6UDVkS1lnZzBLbzUzR0dXYVFHQjAtTjNkd3N6ZHBrRmY3RERZclktZDB3aUhSZW1UUE1QY0ZXQlc0VGt4cHpkNUFqX3pSNEpSMnBNUHFhVWJadWdyZmRjYWciPgo8ZHM6VHJhbnNmb3Jtcz4KPGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNlbnZlbG9wZWQtc2lnbmF0dXJlIi8+CjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiPjxlYzpJbmNsdXNpdmVOYW1lc3BhY2VzIHhtbG5zOmVjPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiIFByZWZpeExpc3Q9ImRzIHNhbWwgc2FtbHAiLz48L2RzOlRyYW5zZm9ybT4KPC9kczpUcmFuc2Zvcm1zPgo8ZHM6RGlnZXN0TWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI3NoYTEiLz4KPGRzOkRpZ2VzdFZhbHVlPkcxSHhza0wxZThxeVFyaWdpeGR1VnFxUVVyQT08L2RzOkRpZ2VzdFZhbHVlPgo8L2RzOlJlZmVyZW5jZT4KPC9kczpTaWduZWRJbmZvPgo8ZHM6U2lnbmF0dXJlVmFsdWU+Ck9PcnMrRHdBekRzbWFuSnh2Zkh4Kzl5c1NnSUYrZmZMR3RXSUwzVnFLNlZ5dEhRVW1LNDdhaUtBNFd0SjMvT1J1dXVNRXdYellTVUsKQm8rUVR4aVEyTytjcWxLQlpZQ3hwdDAvTytNN3hQYnJTVm91MDlRbHA2cWNUOGNBMFliVXZmZkVqZ2p1aytPcUlBd1FzMVl5S0czLwo0empZVXFCYjVYK2d0WC9tcS9EWmhhdTE1NjlwQnIzNHBkR1RQODhVRDhwQnVLNFY0SWpXRjhTbTJ0bzRzZjJGT0JWejlmSHU0ejNuCms5dFNYR2ZONnhxaVFveCtCdzlRM3lLVTlnR0UxNllOT2hya2hucnUrakFwOWtQNTZScVBNTGdHYmliTVpkN1R4MXBTaDRGMjY4ZTgKNWg2bkpIcG80RWRSWXZnNWNTYWxJQUozNGI4SXRkSkszVDZNY0E9PQo8L2RzOlNpZ25hdHVyZVZhbHVlPgo8ZHM6S2V5SW5mbz48ZHM6WDUwOURhdGE+PGRzOlg1MDlDZXJ0aWZpY2F0ZT5NSUlFckRDQ0E1U2dBd0lCQWdJT0FWTEhrZUZYQUFBQUFBUmk5NjR3RFFZSktvWklodmNOQVFFTEJRQXdnWkF4S0RBbUJnTlZCQU1NCkgxTmxiR1pUYVdkdVpXUkRaWEowWHpBNVJtVmlNakF4Tmw4eE9UUTJNVEl4R0RBV0JnTlZCQXNNRHpBd1JEVTRNREF3TURBd1MwdEgKWlRFWE1CVUdBMVVFQ2d3T1UyRnNaWE5tYjNKalpTNWpiMjB4RmpBVUJnTlZCQWNNRFZOaGJpQkdjbUZ1WTJselkyOHhDekFKQmdOVgpCQWdNQWtOQk1Rd3dDZ1lEVlFRR0V3TlZVMEV3SGhjTk1UWXdNakE1TVRrME5qRXlXaGNOTVRnd01qQTVNVEl3TURBd1dqQ0JrREVvCk1DWUdBMVVFQXd3ZlUyVnNabE5wWjI1bFpFTmxjblJmTURsR1pXSXlNREUyWHpFNU5EWXhNakVZTUJZR0ExVUVDd3dQTURCRU5UZ3cKTURBd01EQkxTMGRsTVJjd0ZRWURWUVFLREE1VFlXeGxjMlp2Y21ObExtTnZiVEVXTUJRR0ExVUVCd3dOVTJGdUlFWnlZVzVqYVhOagpiekVMTUFrR0ExVUVDQXdDUTBFeEREQUtCZ05WQkFZVEExVlRRVENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DCmdnRUJBS2NOT1B1UjVIWXRiV0RrLzU4T283bHdoQy9EMnZ3L3FpSSt5YmhLSm9vMTFLQ3liSjB3b2EwR3NRRktyODAvU3Q4R2ZXbEIKck9IVGNueDV3N09RdmpUaXQ2SVJuNklVTXI3dHA2azRrNUVxYStCUFFiNnNERlk2MFRNcno0ZlJBcnZBWGpqVFpLeng0bFVOU1dJcQpueVBVRkh3TXJpSEZ4em95bDBaWFZJVGw2MDlUSmczd2M0MW9Hb3pGTm5FQzNsRnp1WjVvZU5jRDgxNnk0M21uYlZHOUtsNmphdW8yCmJMblVZMXh2bWF6bEs3dnZVLzBIUUxrREdEaEVxejNraWc0RjVhRE1pbnhnN2JNVG0zeEZtUEdqcitlVHdycjBLd0NYL3BCeFR3TS8KVWQwSHJtS1FNMmxURXJoQTgzcnc4b1liUnpxQ205Z2xaYlFoWkgzcUtyOENBd0VBQWFPQ0FRQXdnZjB3SFFZRFZSME9CQllFRkd1ZQpzRld3dXlVOUlNYUhRSHJJRlhHZ2xnV0hNQThHQTFVZEV3RUIvd1FGTUFNQkFmOHdnY29HQTFVZEl3U0J3akNCdjRBVWE1NndWYkM3CkpUMGd4b2RBZXNnVmNhQ1dCWWVoZ1pha2daTXdnWkF4S0RBbUJnTlZCQU1NSDFObGJHWlRhV2R1WldSRFpYSjBYekE1Um1WaU1qQXgKTmw4eE9UUTJNVEl4R0RBV0JnTlZCQXNNRHpBd1JEVTRNREF3TURBd1MwdEhaVEVYTUJVR0ExVUVDZ3dPVTJGc1pYTm1iM0pqWlM1agpiMjB4RmpBVUJnTlZCQWNNRFZOaGJpQkdjbUZ1WTJselkyOHhDekFKQmdOVkJBZ01Ba05CTVF3d0NnWURWUVFHRXdOVlUwR0NEZ0ZTCng1SGhWd0FBQUFBRVl2ZXVNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUFJTXNYK0YzUlgyMmR1WGtSc1VOTi9hRHFEaVFvcWN1ckQKaU15V2JmdTh5dE1vLzNDQy81YzBCYzR6ODBVSW1Mbm9xTUhYa0ljNFpnNVUvSk9QK0RUY0ZqZ1psVDZUMHFCY05NaGtXOE91WXJ0NApDWUkySzlaVVpGS2V5WTFUUFdxWmJLWldHb1lzTWVzQU1IZHdWVWREUWtTUnlzVXprbWtqZ1VlVjByc2MwQ21zM0U3WDNSdWVTOHlpCkxESlZSQmlaa1R4N2wzNzVDb2RVY0VHSlZOMkx5RjZJYzh4eTJjL0puR0JmZlVWVXN0SmNZOTd3dW1yTnJIN3NDQmFHZm1LSWxKWVMKQ3BJR2tpTm1FTm9YVTBQTEU1Q2ZaUkV2TlhmMEViZ0EvNDBXYll0S1BrbEJPTFNFdkFGVUFpeTlaL2M5L2JpdUI1ODh5aXdyQ3R1YQpOakNBPC9kczpYNTA5Q2VydGlmaWNhdGU+PC9kczpYNTA5RGF0YT48L2RzOktleUluZm8+PC9kczpTaWduYXR1cmU+PC9zYW1scDpBdXRoblJlcXVlc3Q+

SAML Request

<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" AssertionConsumerServiceURL="https://chendademoidentity-dev-ed.my.salesforce.com?so=00D58000000KKGe" Destination="https://cmok.kwaoo.me:8443/OpenAM-13.0.0/SSOPOST/metaAlias/idp" ID="_2CAAAAVQAEuDKME8wNTgwMDAwMDA0Qzk2AAAAyNWxg4g9UdyQdawvHLQ6av0xaeS9lcd6NXbflxwewDQdjH8NcqXDaN5JJGuUcnT19HLzLFfRxgqTB09QUWvmZ-14W4ncYoDcAuYLF14ekEDD0n0nNBdI1tlU6MX_juYbg80sy4oHoQd11GdUjGsdvEbgivFuW-WandW8d79gzP5dKYgg0Ko53GGWaQGB0-N3dwszdpkFf7DDYrY-d0wiHRemTPMPcFWBW4Tkxpzd5Aj_zR4JR2pMPqaUbZugrfdcag" IssueInstant="2016-03-13T12:08:53.459Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0" >
    <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">https://chendademoidentity-dev-ed.my.salesforce.com</saml: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="#_2CAAAAVQAEuDKME8wNTgwMDAwMDA0Qzk2AAAAyNWxg4g9UdyQdawvHLQ6av0xaeS9lcd6NXbflxwewDQdjH8NcqXDaN5JJGuUcnT19HLzLFfRxgqTB09QUWvmZ-14W4ncYoDcAuYLF14ekEDD0n0nNBdI1tlU6MX_juYbg80sy4oHoQd11GdUjGsdvEbgivFuW-WandW8d79gzP5dKYgg0Ko53GGWaQGB0-N3dwszdpkFf7DDYrY-d0wiHRemTPMPcFWBW4Tkxpzd5Aj_zR4JR2pMPqaUbZugrfdcag">
                <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="ds saml samlp" />
                    </ds:Transform>
                </ds:Transforms>
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
                <ds:DigestValue>G1HxskL1e8qyQrigixduVqqQUrA=</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>
OOrs+DwAzDsmanJxvfHx+9ysSgIF+ffLGtWIL3VqK6VytHQUmK47aiKA4WtJ3/ORuuuMEwXzYSUK
Bo+QTxiQ2O+cqlKBZYCxpt0/O+M7xPbrSVou09Qlp6qcT8cA0YbUvffEjgjuk+OqIAwQs1YyKG3/
4zjYUqBb5X+gtX/mq/DZhau1569pBr34pdGTP88UD8pBuK4V4IjWF8Sm2to4sf2FOBVz9fHu4z3n
k9tSXGfN6xqiQox+Bw9Q3yKU9gGE16YNOhrkhnru+jAp9kP56RqPMLgGbibMZd7Tx1pSh4F268e8
5h6nJHpo4EdRYvg5cSalIAJ34b8ItdJK3T6McA==
</ds:SignatureValue>
        <ds:KeyInfo>
            <ds:X509Data>
                <ds:X509Certificate>MIIErDCCA5SgAwIBAgIOAVLHkeFXAAAAAARi964wDQYJKoZIhvcNAQELBQAwgZAxKDAmBgNVBAMM
H1NlbGZTaWduZWRDZXJ0XzA5RmViMjAxNl8xOTQ2MTIxGDAWBgNVBAsMDzAwRDU4MDAwMDAwS0tH
ZTEXMBUGA1UECgwOU2FsZXNmb3JjZS5jb20xFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xCzAJBgNV
BAgMAkNBMQwwCgYDVQQGEwNVU0EwHhcNMTYwMjA5MTk0NjEyWhcNMTgwMjA5MTIwMDAwWjCBkDEo
MCYGA1UEAwwfU2VsZlNpZ25lZENlcnRfMDlGZWIyMDE2XzE5NDYxMjEYMBYGA1UECwwPMDBENTgw
MDAwMDBLS0dlMRcwFQYDVQQKDA5TYWxlc2ZvcmNlLmNvbTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNj
bzELMAkGA1UECAwCQ0ExDDAKBgNVBAYTA1VTQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAKcNOPuR5HYtbWDk/58Oo7lwhC/D2vw/qiI+ybhKJoo11KCybJ0woa0GsQFKr80/St8GfWlB
rOHTcnx5w7OQvjTit6IRn6IUMr7tp6k4k5Eqa+BPQb6sDFY60TMrz4fRArvAXjjTZKzx4lUNSWIq
nyPUFHwMriHFxzoyl0ZXVITl609TJg3wc41oGozFNnEC3lFzuZ5oeNcD816y43mnbVG9Kl6jauo2
bLnUY1xvmazlK7vvU/0HQLkDGDhEqz3kig4F5aDMinxg7bMTm3xFmPGjr+eTwrr0KwCX/pBxTwM/
Ud0HrmKQM2lTErhA83rw8oYbRzqCm9glZbQhZH3qKr8CAwEAAaOCAQAwgf0wHQYDVR0OBBYEFGue
sFWwuyU9IMaHQHrIFXGglgWHMA8GA1UdEwEB/wQFMAMBAf8wgcoGA1UdIwSBwjCBv4AUa56wVbC7
JT0gxodAesgVcaCWBYehgZakgZMwgZAxKDAmBgNVBAMMH1NlbGZTaWduZWRDZXJ0XzA5RmViMjAx
Nl8xOTQ2MTIxGDAWBgNVBAsMDzAwRDU4MDAwMDAwS0tHZTEXMBUGA1UECgwOU2FsZXNmb3JjZS5j
b20xFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xCzAJBgNVBAgMAkNBMQwwCgYDVQQGEwNVU0GCDgFS
x5HhVwAAAAAEYveuMA0GCSqGSIb3DQEBCwUAA4IBAQAIMsX+F3RX22duXkRsUNN/aDqDiQoqcurD
iMyWbfu8ytMo/3CC/5c0Bc4z80UImLnoqMHXkIc4Zg5U/JOP+DTcFjgZlT6T0qBcNMhkW8OuYrt4
CYI2K9ZUZFKeyY1TPWqZbKZWGoYsMesAMHdwVUdDQkSRysUzkmkjgUeV0rsc0Cms3E7X3RueS8yi
LDJVRBiZkTx7l375CodUcEGJVN2LyF6Ic8xy2c/JnGBffUVUstJcY97wumrNrH7sCBaGfmKIlJYS
CpIGkiNmENoXU0PLE5CfZREvNXf0EbgA/40WbYtKPklBOLSEvAFUAiy9Z/c9/biuB588yiwrCtua
NjCA</ds:X509Certificate>
            </ds:X509Data>
        </ds:KeyInfo>
    </ds:Signature>
</samlp:AuthnRequest>

 

GET https://cmok.kwaoo.me:8443/OpenAM-13.0.0/XUI/#login/&realm=/&forward=true&spEntityID=https%3A%2F%2Fchendademoidentity-dev-ed.my.salesforce.com&goto=%2FSSOPOST%2FmetaAlias%2Fidp%3FReqID%3D_2CAAAAVQAEuDKME8wNTgwMDAwMDA0Qzk2AAAAyNWxg4g9UdyQdawvHLQ6av0xaeS9lcd6NXbflxwewDQdjH8NcqXDaN5JJGuUcnT19HLzLFfRxgqTB09QUWvmZ-14W4ncYoDcAuYLF14ekEDD0n0nNBdI1tlU6MX_juYbg80sy4oHoQd11GdUjGsdvEbgivFuW-WandW8d79gzP5dKYgg0Ko53GGWaQGB0-N3dwszdpkFf7DDYrY-d0wiHRemTPMPcFWBW4Tkxpzd5Aj_zR4JR2pMPqaUbZugrfdcag%26index%3Dnull%26acsURL%3Dhttps%253A%252F%252Fchendademoidentity-dev-ed.my.salesforce.com%253Fso%253D00D58000000KKGe%26spEntityID%3Dhttps%253A%252F%252Fchendademoidentity-dev-ed.my.salesforce.com%26binding%3Durn%253Aoasis%253Anames%253Atc%253ASAML%253A2.0%253Abindings%253AHTTP-POST&AMAuthCookie= HTTP/1.1

POST https://chendademoidentity-dev-ed.my.salesforce.com/?so=00D58000000KKGe HTTP/1.1

SAML Response

<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="s2565096ea70e9276f3008cc3c74253315cacab273" InResponseTo="_2CAAAAVQAEuDKME8wNTgwMDAwMDA0Qzk2AAAAyNWxg4g9UdyQdawvHLQ6av0xaeS9lcd6NXbflxwewDQdjH8NcqXDaN5JJGuUcnT19HLzLFfRxgqTB09QUWvmZ-14W4ncYoDcAuYLF14ekEDD0n0nNBdI1tlU6MX_juYbg80sy4oHoQd11GdUjGsdvEbgivFuW-WandW8d79gzP5dKYgg0Ko53GGWaQGB0-N3dwszdpkFf7DDYrY-d0wiHRemTPMPcFWBW4Tkxpzd5Aj_zR4JR2pMPqaUbZugrfdcag" Version="2.0" IssueInstant="2016-03-13T12:10:11Z" Destination="https://chendademoidentity-dev-ed.my.salesforce.com?so=00D58000000KKGe" >
    <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">https://cmok.kwaoo.me:8443/OpenAM-13.0.0</saml:Issuer>
    <samlp:Status xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
        <samlp:StatusCode xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
    </samlp:Status>
    <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="s24de3385510bdeab7d9d8ff8cc3271ed4898d1f22" IssueInstant="2016-03-13T12:10:11Z" Version="2.0" >
        <saml:Issuer>https://cmok.kwaoo.me:8443/OpenAM-13.0.0</saml: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="#s24de3385510bdeab7d9d8ff8cc3271ed4898d1f22">
                    <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>H0DEhp0G5td9ymHsg5YvXNKAWQ4=</ds:DigestValue>
                </ds:Reference>
            </ds:SignedInfo>
            <ds:SignatureValue>
Af+GBiJ2BSflbikYEZaCVEwCh/EI7vioqWdKKOuyEHPIA8D/RSr1VAW7drlX8L3yMmBXErsMPVDb
IIzZNgzYgRf0gxgJQQU9ESjXZN6P5rgHQxRIJ2jqXGfDZQvm3mVUwXmq5pqrR1RTyAX2zJPPI/nL
CE+0sejN8Nqvq+eo7AA=
</ds:SignatureValue>
            <ds:KeyInfo>
                <ds:X509Data>
                    <ds:X509Certificate>
MIICQDCCAakCBEeNB0swDQYJKoZIhvcNAQEEBQAwZzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNh
bGlmb3JuaWExFDASBgNVBAcTC1NhbnRhIENsYXJhMQwwCgYDVQQKEwNTdW4xEDAOBgNVBAsTB09w
ZW5TU08xDTALBgNVBAMTBHRlc3QwHhcNMDgwMTE1MTkxOTM5WhcNMTgwMTEyMTkxOTM5WjBnMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEUMBIGA1UEBxMLU2FudGEgQ2xhcmExDDAK
BgNVBAoTA1N1bjEQMA4GA1UECxMHT3BlblNTTzENMAsGA1UEAxMEdGVzdDCBnzANBgkqhkiG9w0B
AQEFAAOBjQAwgYkCgYEArSQc/U75GB2AtKhbGS5piiLkmJzqEsp64rDxbMJ+xDrye0EN/q1U5Of+
RkDsaN/igkAvV1cuXEgTL6RlafFPcUX7QxDhZBhsYF9pbwtMzi4A4su9hnxIhURebGEmxKW9qJNY
Js0Vo5+IgjxuEWnjnnVgHTs1+mq5QYTA7E6ZyL8CAwEAATANBgkqhkiG9w0BAQQFAAOBgQB3Pw/U
QzPKTPTYi9upbFXlrAKMwtFf2OW4yvGWWvlcwcNSZJmTJ8ARvVYOMEVNbsT4OFcfu2/PeYoAdiDA
cGy/F2Zuj8XJJpuQRSE6PtQqBuDEHjjmOQJ0rV/r8mO1ZCtHRhpZ5zYRjhRC9eCbjx9VrFax0JDC
/FfwWigmrW0Y0Q==
</ds:X509Certificate>
                </ds:X509Data>
            </ds:KeyInfo>
        </ds:Signature>
        <saml:Subject>
            <saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" NameQualifier="https://cmok.kwaoo.me:8443/OpenAM-13.0.0" >6dh3dC/pJbD47KYDd5R3W8HPBrXu</saml:NameID>
            <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <saml:SubjectConfirmationData InResponseTo="_2CAAAAVQAEuDKME8wNTgwMDAwMDA0Qzk2AAAAyNWxg4g9UdyQdawvHLQ6av0xaeS9lcd6NXbflxwewDQdjH8NcqXDaN5JJGuUcnT19HLzLFfRxgqTB09QUWvmZ-14W4ncYoDcAuYLF14ekEDD0n0nNBdI1tlU6MX_juYbg80sy4oHoQd11GdUjGsdvEbgivFuW-WandW8d79gzP5dKYgg0Ko53GGWaQGB0-N3dwszdpkFf7DDYrY-d0wiHRemTPMPcFWBW4Tkxpzd5Aj_zR4JR2pMPqaUbZugrfdcag" NotOnOrAfter="2016-03-13T12:20:11Z" Recipient="https://chendademoidentity-dev-ed.my.salesforce.com?so=00D58000000KKGe" />
            </saml:SubjectConfirmation>
        </saml:Subject>
        <saml:Conditions NotBefore="2016-03-13T12:00:11Z" NotOnOrAfter="2016-03-13T12:20:11Z" >
            <saml:AudienceRestriction>
                <saml:Audience>https://chendademoidentity-dev-ed.my.salesforce.com</saml:Audience>
            </saml:AudienceRestriction>
        </saml:Conditions>
        <saml:AuthnStatement AuthnInstant="2016-03-13T12:10:10Z" SessionIndex="s2fc96260ddd47755f8c5d8856b9ba93cb3e8fc801" >
            <saml:AuthnContext>
                <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
            </saml:AuthnContext>
        </saml:AuthnStatement>
        <saml:AttributeStatement>
            <saml:Attribute Name="SSOID">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string" >demo</saml:AttributeValue>
            </saml:Attribute>
        </saml:AttributeStatement>
    </saml:Assertion>
</samlp:Response>

Access to Salesforce

GET https://chendademoidentity-dev-ed.my.salesforce.com/secur/frontdoor.jsp?sid=00D58000000KKGe%21AQMAQJZt9bOXRXGJ6j7v2ulGJdKD8di4GmNUTnT_FutW.ktmU1vYp2Pj8ZwZn60TJW2jNsEh6Wrp5hE19oWDZoybO_Ma1khi&retURL=%2Fhome%2Fhome.jsp&loginURL=https%3A%2F%2Fsaml.salesforce.com%3Fssostartpage%3Dhttps%253A%252F%252Fcmok.kwaoo.me%253A8443%252FOpenAM-13.0.0%252FSSOPOST%252FmetaAlias%252Fidp%26saml_request_id%3D_2CAAAAVQAFFRJME8wNTgwMDAwMDA0Qzk2AAAAyJvKxj_hB_mTp8UAboi2jE6OZQKzHWf0KNTce0vtJ_LuvBDgqFXx5geppnPpwa-eqHHyOPh7-pW2YG2gm9iZBYmT3xOZSG_CCc4WaRm9TKNDVKtAwsc66oRVUrwllAnDDT7JLYMi7N74vL7kCqWJyRwyvgmKqi0AQpBAQO0ec2XOa9ML5ayJX6jFw9i-89zuSJ9vxfVvdjt7HMnPfte0NToXmXvMNDj7m44vPvgHp6BwqaOtFl5Bosf-iX11l3fKqQ%26logouturl%3Dhttps%253A%252F%252Fcmok.kwaoo.me%253A8443%252FOpenAM-13.0.0%252F&cshc=8000000TFw68000000KKGe HTTP/1.1

 
Thanks for reading.
 

Posted in Salesforce | Tagged , , ,

How to expose a public Salesforce Web Service using a top-down approach (contract first) WSDL interface ?

Problem

How can we expose a public Web service using Salesforce (e.g no authentication needed to access this web service) ? Let’s add some challenge by using a WSDL contract imposed by your service Provider and that you have to follow when implementing this web service using Salesforce.

Background

I have proposed a solution to support multiple delegated authentication service when having one Salesforce Organisation and said that this service can be exposed in Salesforce. After some investigation, it seems a little bit challenging to use a top-down approach when implementing web service in Salesforce. Why ?
There is no (documented?) way to expose a Web Service in Salesforce starting from WSDL. If you are coming from Java World, there is an option -server when you used WSDL2Java to generate the skeleton classes for the Web service implementation. I do not find a equivalent option in Salesforce using WSDL2Apex. My understanding of WSDL2Apex is that it’s provides you the stub classes to call a Web Service from Salesforce (Web Service Callout).
Salesforce propose a bottom-up model to implement your Web Service. The drawback of this approach is that you cannot set the different namespace/target namespace inherent to your Web Service, as it is automatically generated by Salesforce and you cannot override it (yet ?).

Proposed Solution

I have been working with Web Service since decade now and I remember that we can expose/call Web Service using the old plain HTTPRequest/ HTTPResponse with XML over HTTP(/HTTPS). This seems to be the right path to go. But in order to not re-inventing the wheel, i will “deviate” the REST annotation from Salesforce, and adapt it to my need to serve SOAP Request/Response (@RestResource annotation) imposed by the WSDL contract. You will find this strange and a bit overwhelmed solution (and yes it is ;-)), but I do not find any other solution. I really hope that Salesforce will proposed a way to expose a Web Service starting from the WSDL contract.

Required Steps

  • Get the WSDL Contract, in our case I will use the DelegatedAuthentication.wsdl exposed by Salesforce
  • Use the excellent SOAPUI tools to create SOAP requests and SOAP responses covering all uses cases. Do not forget to handle properly the SOAP Exception that might happened
  • To store theses SOAP templates, I was first thinking using Salesforce Custom Settings, but I found that I cannot create a text document greater that 255 characters. So converge to use the Static Resources for any Web Site published by Salesforce. Then I just have to load the SOAP Request/Response from this static resource and do required processing on thoses files (replacing tags template).
  • Create REST Apex Class that support @HttpGet and @HttpPost annotation. @HttpGet will just return the WSDL exposed by the REST Service and @Httppost will handle the SOAP request.
  • Go to you Org | Setup | Remote Site and add your remote site URL to avoid the error “Unauthorized endpoint”
  • Zip your static resources (SOAP Request and Response + WSDL Interface contract). Go to you Org | Setup | Static Resource and add your zip file. This access the XML file from the static resource, just use the following URL: https://cmok-developer-edition.eu5.force.com/developper/resource/SR_DelegatedAuthenticationService/DAS_Response_true.xml where
      developper is your site name,
      SR_DelegatedAuthenticationService is the name of your static resource,
      and DAS_Response_true.xml is the name of your XML file in the static resource.
  • The Apex code just use DOM Document to parse and validate the SOAP Request
  • Sample Apex Code

    @RestResource(urlMapping='/MultipleDelegatedAutNService')
    global class MultipleDelegatedAutNService {
        //https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_methods_system_restcontext.htm
        //https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_methods_system_restrequest.htm#apex_methods_system_restrequest
        @HttpGet
        global static void doGet() {
        	RestContext.response.addHeader('Content-Type', 'application/xml');
            String wsdlFile = 'https://cmok-developer-edition.eu5.force.com/developper/resource/SR_DelegatedAuthenticationService/DelegatedAuthentication.wsdl';
    		RestContext.response.responseBody = Blob.valueOf(getBody(wsdlFile));
        }
    
    
        // Just checking that it's actually XML
        private static String parseXMLStr(String toParse) {
          DOM.Document doc = new DOM.Document();
          
          try {
            doc.load(toParse);    
            DOM.XMLNode root = doc.getRootElement();
            return walkThrough(root);
            
          } catch (System.XMLException e) {  // invalid XML
            return e.getMessage();
          }
        }
    
        // Recursively walk through the XML
        /*
    		14:22:49.043 (43847766)|USER_DEBUG|[96]|DEBUG|*** parseXMLStr=
    		Element: Envelope namespace: http://schemas.xmlsoap.org/soap/envelope/
    		Element: Body namespace: http://schemas.xmlsoap.org/soap/envelope/
    		Element: Authenticate namespace: urn:authentication.soap.sforce.com
    		Element: username namespace: urn:authentication.soap.sforce.com, text=OKM.Customer.invensys@bridge-fo.com.devoct
    		Element: password namespace: urn:authentication.soap.sforce.com, text=5F91558D-0274-4423-B397-AA7065EA5074
    		Element: sourceIp namespace: urn:authentication.soap.sforce.com, text=INVENSYS
        */
        // Reference: http://developer.force.com/cookbook/recipe/parsing-xml-using-the-apex-dom-parser
        private static String walkThrough(DOM.XMLNode node) {
          String result = '\n';
          if (node.getNodeType() == DOM.XMLNodeType.COMMENT) {
            return 'Comment (' +  node.getText() + ')';
          }
          if (node.getNodeType() == DOM.XMLNodeType.TEXT) {
            return 'Text (' + node.getText() + ')';
          }
          if (node.getNodeType() == DOM.XMLNodeType.ELEMENT) {
            result += 'Element: ' + node.getName() + ' Namespace: ' + node.getNamespace();
            if (node.getText().trim() != '') {
              result += ', text=' + node.getText().trim();
            }
            if (node.getAttributeCount() > 0) { 
              for (Integer i = 0; i< node.getAttributeCount(); i++ ) {
                result += ', attribute #' + i + ':' + node.getAttributeKeyAt(i) + '=' + node.getAttributeValue(node.getAttributeKeyAt(i), node.getAttributeKeyNsAt(i));
              }  
            }
            for (Dom.XMLNode child: node.getChildElements()) {
              result += walkThrough(child);
            }
            return result;
          }
          return '';  //should never reach here
          
        }    
    
    
    	private Boolean isValid_DA_SOAPRequest(Dom.XMLNode node) {
    		Boolean isValidSoapRequest = false;
    		/*
    		left as an exercise - Applied your logic here
    		*/	        
    		return isValidSoapRequest;
    	}    
    
        private static String getBody(String url){
        	Http h = new Http();
    		HttpRequest webReq = new HttpRequest();
    		webReq.setMethod('GET');
    		webReq.setEndpoint(url);
    		HttpResponse res = h.send(webReq);
    		res.setHeader('Content-Type', 'application/xml'); 
    		return res.getbody();
        }   
    
    
        //1. Before you can access external servers from an endpoint or redirect endpoint using Apex or any other feature, you must add the remote site to a list of authorized remote sites in the Salesforce user interface. 
        //   Unauthorized endpoint, please check Setup->Security->Remote site settings - Add your site endpoint https://cmok-developer-edition.eu5.force.com
        //2.The return type of you WS MUST be void, so you can return any content type, in our case a valid SOAP response
        @HttpPost
        global static void doPost() {
        	//RestRequest restRequest = RestContext.request;
        	//String soapRequestBody= restRequest.requestBody ; 
        	String soapRequestBody = RestContext.request.requestBody.toString();
        	System.debug('*** soapRequestBody=' + soapRequestBody);
        	System.debug('*** parseXMLStr=' + parseXMLStr(soapRequestBody));    	
        	RestContext.response.addHeader('Content-Type', 'application/xml');
            String urlSuccess = 'https://cmok-developer-edition.eu5.force.com/developper/resource/SR_DelegatedAuthenticationService/DAS_Response_true.xml';
            //String urlFailed = 'https://cmok-developer-edition.eu5.force.com/developper/resource/SR_DelegatedAuthenticationService/DAS_Response_false.xml';
    		/*
    		left as an exercise - Applied your logic here
    		*/	        
    		RestContext.response.responseBody = Blob.valueOf(getBody(urlSuccess));
        }
        
    }
    

    Screen Shot of my PoC

    HTTP GET on URL https://cmok-developer-edition.eu5.force.com/developper/services/apexrest/MultipleDelegatedAutNService provide your the WSDL interface
    01-WSL Exposition from GET - 2015-09-20_17-48-59

    Calling you webservice from SOAPUI
    02-3-SOAPUI

    Configure the remote site setting to expose publically your Web Service
    02-1- Remote Site - 2015-09-20_17-31-00

    Use the static resource to store your SOAP Request/Response/ and WSDL files.
    02-2-Static resource - 2015-09-20_17-50-27

    Thanks for reading.

    Posted in Salesforce | Tagged , , , , , , , , , , , , ,

    Exposing OpenAM 12 instance on the internet

    Problem

    How can we expose an OpenAM instance on the internet ?

    Background

    Working with Salesforce often need to connect to an external IDP. I had previous experience working on OpenSSO 8.0 instance. So I will use the OpenSource version called OpenAM 12.0. The interface is pretty similar to OpenSSO 8.0 from SUN MicroSystem (acquired by Oracle in August 2008).

    Pre-requisiste

    • Install and configure a tomcat server. As you are exposing your instance on the internet, your need a *cheap but hackable* self-signed certificate. Please refer to this Apache Tomcat 8 – SSL/TLS Configuration HOW-TO
    • Configure and Open the port 4444, 50389 and 1689 in your router and authorize theses locals ports in your firewall rules setting

    Below a configuration of my router:
    Port_Router_2015-08-27_19-21-10

    Installation of OpenAM

    The installation wizzard proposed by OpenAM is pretty easy. You MUST choose the advanced installation otherwise it will failed, as you have to specify some ports for the JMX, Admin and LDAP ports.

    Below the configuration screen of my installation.
    OpenAMConfigurator_1_2015-08-27_19-34-56

    OpenAMConfigurator_2_2015-08-27_19-35-39

    OpenAMConfigurator_3_2015-08-27_19-35-56

    OpenAMConfigurator_4_2015-08-27_19-41-50
    OpenAMConfigurator_5_2015-08-27_19-42-06
    OpenAMConfigurator_6_2015-08-27_19-42-16
    OpenAMConfigurator_7_2015-08-27_19-42-42
    OpenAMConfigurator_8_2015-08-27_19-42-57
    OpenAMConfigurator_9_2015-08-27_19-44-15
    OpenAMConfigurator_10_2015-08-27_19-44-45

    Et voila, I have now a free openAM instance for my labs testing with Salesforce !

    Thanks for reading.

    Posted in Uncategorized

    How to support multiple delegated authentication service in one Salesforce Organisation ?

    Problem

    How can we support multiple delegated authentication service in one Salesforce Organisation ?

    Background

    As you may noticed, we can configure only one Delegated Authentication URL Service in the Single Sign On Setting of your Org. Now what’s happened if you have multiple different portal (with their own security mechanism) to integrate with Salesforce when you have only one Org instance and want to benefit from the delegated authentication Service provided by Salesforce ?

    Answer

    We can derive the facade pattern to implement this service. This service can be located anywhere in your network and must be publicly available (HTTPS is recommended here). You can even host this service in your Salesforce’s Org by exposing this service as a SOAP Service.

    The delegated authentication Service

    Please refer to the following documentation to understand the delegated authentication service:

    Salesforce provide top-down approach by providing the WSDL interface for this service. It is available in your Org (Setup| Develop | API | Download Delegated Authentication WSDL).

    Multiple Authentication Service - SE - Delegated Authentication SOAP Request-Response (1)

    Proof of Concept

    Let’s validate this by mocking a SOAPUI Service based on the WSDL provided by Salesforce, and use Groovy scripting functionality to route dynamically the request to the real implementation of this delegated service. For the purpose of this demo, I will used the sourceIp element in my SOAP request to identify the caller of this service. I would recommend to use either SOAP Header or HTTP header to store this “routing” information.

    Below the screensot of my SOAPUI Settings:
    MockDelegatedAuthenticationService_2015-08-23_14-21-05

    Below groovy code i have used to this purpose. I have used the groovy-wslite as a WS client (just download the JAR and put it in your SOAPUI library extension to made to available: C:\Program Files\SmartBear\SoapUI-5.1.3\bin\ext\groovy-wslite-1.1.2.jar).

    import wslite.soap.*
    import wslite.http.*
    import wslite.soap.SOAPClient
    import wslite.http.HTTPClientException
    import wslite.http.HTTPRequest
    import wslite.http.HTTPResponse
    import wslite.soap.SOAPClient
    import wslite.soap.SOAPFaultException
    import wslite.soap.SOAPResponse
    
    
    log.info "context=" + context
    def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
    log.info  "groovyUtils=" +groovyUtils
    log.info  "mockRequest.requestContent=" + mockRequest.requestContent
    
    // create XmlHolder for request content
    def holder = new com.eviware.soapui.support.XmlHolder( mockRequest.requestContent )
    def _username = holder["//*:username"]
    def _password = holder["//*:password"]
    def _sourceip = holder["//*:sourceIp"]
    log.info "_username=" + _username
    log.info "_password=" + _password
    log.info "_sourceip=" + _sourceip
    def DELEGATED_AUTH_URL_PORTAL1 = "http://PORTAL1/wsGCSBFO/DAuth.asmx"
    def DELEGATED_AUTH_URL_PORTAL2 = "https://PORTAL2/IMS-IdentityManager/services/AuthenticationService"
    def DELEGATED_AUTH_URL_PORTALDEFAULT = "https://PORTALDEFAULT/services/AuthenticationService"
    
    switch (_sourceip) {
            case ~/^PORTAL1$/:
                log.info "Routing to PORTAL1 Portal Delegated AuthN Service"          
                context.myContentResponse = call_DelegatedAuthenticationFacade(DELEGATED_AUTH_URL_PORTAL1, _username, _password, _sourceip)   
                return "SCRIPT_RESPONSE"
                break
            case ~/^PORTAL2$/:
                log.info "Routing to PORTAL2 Portal Delegated AuthN Service"          
                context.myContentResponse = call_DelegatedAuthenticationFacade(DELEGATED_AUTH_URL_PORTAL2, _username, _password, _sourceip)   
                return "SCRIPT_RESPONSE"
                break
            default:
                log.info "Routing to DEFAULT Portal Delegated AuthN Service"          
                context.myContentResponse = call_DelegatedAuthenticationFacade(DELEGATED_AUTH_URL_PORTALDEFAULT, _username, _password, _sourceip)   
                return "SCRIPT_RESPONSE"
                break
    }    
    
    String call_DelegatedAuthenticationFacade(String serviceLocationUrl, String _username, String _password, String _sourceip) {
    	def String defaultResponse = '''
    &lt;soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;
       &lt;soap:Body&gt;
          &lt;AuthenticateResult xmlns="urn:authentication.soap.sforce.com"&gt;
             &lt;AuthenticateResult&gt;
                &lt;Authenticated&gt;false&lt;/Authenticated&gt;
             &lt;/AuthenticateResult&gt;
          &lt;/AuthenticateResult&gt;
       &lt;/soap:Body&gt;
    &lt;/soap:Envelope&gt;
    '''
    	try {
    		SOAPClient client = new SOAPClient(serviceLocationUrl)
    	  	def response = client.send(SOAPAction:'') {  
    	      body {
    	          Authenticate('xmlns':'urn:authentication.soap.sforce.com') {
    	              username(_username)
    	              password(_password)
    	              sourceIp(_sourceip)
    	          }
    	      }
    	 	}
    	  	HTTPRequest myRequest = response?.httpRequest
    	  	HTTPResponse myResponse = response?.httpResponse
    	  	return debug(defaultResponse, myRequest, myResponse)
    	  		 
    	} catch (SOAPFaultException soapEx) {
    	    return debug(defaultResponse, soapEx.httpRequest, soapEx.httpResponse)
    	} catch (HTTPClientException httpEx) {
    	    return debug(defaultResponse, httpEx.request, httpEx.response)
    	} catch (Exception Ex) {
    	    return debug(defaultResponse, Ex.request, Ex.response)
    	}		
    }
    
    String debug(String defaultResponse, HTTPRequest request, HTTPResponse response) {
      log.info("*****************************************************************************************************")
      log.info("HTTPRequest $request with formatted content:\n${request?.contentAsString}")
      log.info("HTTPResponse $response with formatted content:\n${response?.contentAsString}")
      defaultResponse = "${response?.contentAsString}"
      log.info("RETURNED RESPONSE TO FACADE\n${defaultResponse}")
      return defaultResponse
      
    }
    

    The script response content SOAP response generated by the groovy SCRIPT.

    ${myContentResponse}
    

    Thanks for reading.

    Posted in Salesforce | Tagged , , , , , ,

    Jenkins Chatter Plugin

    There is a nice plugin called JenkinsChatterPlugin  which allow you to post to a Chatter group after a post-build action. Clone it (or get the compiled version) and installed it as a plugin in Jenkins.

    jenkins-plugin-2014-12-27_09-25-19

    jenkins-plugin-2014-12-27_09-25-20

    jenkins-plugin-2014-12-27_09-32-20

    Jenkins-Chatter-2014-12-27_09-42-00

    Posted in Uncategorized | Tagged , , ,

    Parallel development stream with Git using Branching & Merging

    Here is an example of sequence to handle Multiple Team development with Git Branching & Merging
    Sequence Diagram - Sequence Diagram - Git Branching & Merge

    Posted in Uncategorized