Friday, March 20, 2015

[Salesforce / Trailhead] The beginning of your Force.com journey


Few days ago the Salesforce team released 4 new Trailhead modules, and I decided finally to have a look at it...with my style.

What is my style?

I may say "all in" or "all or nothing" style.

I decided to do all the modules and see which topics were covered (and how deeply).

With year of Force.com development it's been quite easy for me to complete in few hours all the modules, but I haven't earned all the points available (I did some mistakes when answering to questions) and I must admint I also learned something (expecially in modules I don't play a lot in my job).


After 16 modules I have to say this is a really good starting point to start learning the basics of the Force.com platform, and sometimes the documentation goes deeper than you could expect, covering important aspects that sometimes you find out only after months of "real world" practice.

The Trailhead modules page lists all the modules in alphabetical order, but you can follow the 3 steps on the Trailhead main page to have a better study order.

Recently some cool modules have been added:

  • Process Automation: you learn the basics of process automation and the new Process Builder and Visual Workflows tools, cool ways to get your complex processes up and running in few clicks!
  • Chatter Basics: this useful module teaches the basics of setting up Chatter on your org to improve social collaboration
  • Lightning Components: this is my favorite modulo above all, I love Lightning Components and can't wait to see them out of the Beta stage. Learn base and advanced aspects of this new powerful framework
  • Visualforce Mobile: learn how to create slick and smooth visualforce pages on the Salesforce1 mobile platform

This is the complete list of available modules:

And (awesomely) these are "can't wait" upcoming modules:
  • Reports & Dashboards: Build real-time reports and charts to visualize key business metrics
  • Apex Integration Services: Integrate with external apps using Apex REST and SOAP services
  • Asynchronous Apex: Write more efficient Apex code with asynchronous processing
  • Visualforce & JavaScript: Use JavaScript to enhance and customize your Visualforce pages
  • App Deployment: Learn best practices for team app development and lifecycle management

Stay tuned for more modules!

I'm gonna definitely suggest all my Company's interns to start learning Force.com using Trailhead, a funny and awesome way to learn the Force!

And once for all:

Monday, March 9, 2015

[Salesforce / SSO] Implementing Delegated SSO


Playing with code is cool, but playing with useless stuff is even better :)

Ok, I'm kidding, I just want to say that sometimes you have to get your hands dirty to understand what lies underneath things and try to build useless stuff to see simple "Hello world!" appear!

This is the case of Delegated SSO.

Few weeks ago with Paolo (a colleage of mine), I was checking deeper on Salesforce SSO, trying to figure out from the docs how to implement it.

The first thing that came across my eyes was the difference between Delegated and Federated SSO.
It wans't that clear at that time, that's why Paolo played with the code for some time and did a cool thing that I reproduced in the following Github repo.

Federated SSO is done using well known protocols such as SAML, granting a secure identity provisioning: with Microsoft ADFS you can use your own company domain to log on your Salesforce CRMs as well.

Which is the problem with this kind of SSO?

To implement its bases you don't need a single line of code.


Too bad we are dirty men that like to play with mud!


That's why this post!


With Delegated SSO you need 2 actors:
  • An Identity provider (e.g. your Domain server)
  • The Salesforce ORG in which you want to be logged in without remembering username/password

The first wall you splash into is the fact the you have your ORG to be enabled to Delegated SSO: this should be enabled by Salesforce support, so you need a way to contact support (if you're not using an ORG with built in support).

After your ORG is enabled to Delegated SSO, this is where the config has to be enabled in your "delegated" ORG:

The Delegated Gateway URL contains the URL of the webservice of the "delegating" server.

Then you have to enable the Is Single Sign-On Enabled flag in the Administrative Permissions section of your users' profile.

This is where we got our hands dirty while making out research: why not using a Salesforce ORG as the identity provider?

Challenge accepted!

What happens with delegated SSO? When you try to log in into your delegated ORG, Salesforce at first try to access the "Delegated SSO" webservice: if this accept the request, than you are automatically logged in; if the server gives a KO, than the ORG checks for username/password to be correct.

This is the message that the delegated ORG sends to the identity provider:
<?xml version="1.0" encoding="UTF-8" ?>
<soapenv:Envelope
   xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Body>
      <Authenticate xmlns="urn:authentication.soap.sforce.com">
         <username>[email protected]</username>
         <password>myPassword99</password>
         <sourceIp>1.2.3.4</sourceIp>
      </Authenticate>
   </soapenv:Body>
</soapenv:Envelope>

It basically asks for a user/password couple with a source IP, and receives this response:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope 
   xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Body>
      <AuthenticateResult xmlns="urn:authentication.soap.sforce.com">
         <Authenticated>false</Authenticated>
      </AuthenticateResult>
   </soapenv:Body>
</soapenv:Envelope>

The Authenticated field conveys the OK/KO result.

You can use the password field to host a unique and temporary token to make the connection more secure.

To log-in from your identity provider page, use this example page (see the /apex/DelegateLogin page):

Each of this users is a delegated user on another ORG, that is stored in the DelegatedUser__c SObject:

It stores Username and Remote ORG ID, because it is used to create the login URL to make the authentication go smootly for the user:
public PageReference delegateAuthentication(){
 String password = generateGUID();
 insert new DelegatedToken__c(Token__c = password, 
         Username__c = this.usr.DelegatedUsername__c,
         RequestIP__c = getCurrentIP());
 String url = 'https://login.salesforce.com/login.jsp?'
    +'un='+EncodingUtil.urlEncode(this.usr.DelegatedUsername__c, 'utf8')
    +'&orgId='+this.usr.Delegated_ORG_ID__c 
    +'&pw='+EncodingUtil.urlEncode(password, 'utf8')
    +'&rememberUn=0&jse=0';
 //you can also setup a startURL, logoutURL and ssoStartPage parameters to enhance usre experience
 PageReference page = new PageReference(url);
 page.setRedirect(false);
 return page;
}

This way you can request a login action for every user you have stored in your objects (this case has the same ORG but you can have wathever ORG you want, no limits); the token is stored in a DelegatedToken__c SObject that is used to handle temporary tokens, usernames and IPs: this way, when the delegated ORG asks our ORG with this infos, our webservice can succesfully authenticate the requesting user.

This is done through the public webservice exposed by the RESTDelegatedAuthenticator class:
    @HttpPost
    global static void getOpenCases() {
        RestResponse response = RestContext.response;
        response.statusCode = 200;
        response.addHeader('Content-Type', 'application/xml');
        Boolean authResult = false;
        try{
            Dom.Document doc = new DOM.Document(); 
            doc.load(RestContext.request.requestBody.toString());  
            DOM.XMLNode root = doc.getRootElement();
            Map<String,String> requestValues = walkThrough(root);
            
            
            authResult = checkCredentials(requestValues.get('username'), 
                                          requestValues.get('password'),
                                          requestValues.get('sourceIp'));
        }catcH(Exception e){
            insert new Log__c(Description__c = e.getStackTraceString()+'\n'+e.getMessage(), 
                       Request__c = RestContext.request.requestBody.toString());
        }finally{
            insert new Log__c(Description__c = 'Result:'+authResult, 
                       Request__c = RestContext.request.requestBody.toString());
        }
        String soapResp = '<?xml version="1.0" encoding="UTF-8"?>'
            +'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">'
            +'<soapenv:Body>'
            +'<authenticateresult xmlns="urn:authentication.soap.sforce.com">'
            +'<authenticated>'+authResult+'</Authenticated>'
            +'</AuthenticateResult>'
            +'</soapenv:Body>'
            +'</soapenv:Envelope>';
        response.responseBody = Blob.valueOf(soapResp);
    }

This webservice simply checks the incoming SOAP XML request, extracts the fields on the request and tests its values with the checkCredentials() method.

If the token is not expired you'll be succesfully redirected to the new ORG logged as the user you wanted to.

A good practice is to use custom domains: you can thus replace "login.salesforce.com" with your "My Domain" of the corresponding ORG (you can also add a new field on the DelegatedUser__c SObject.

To enable public webservice, you simlpy need to create a new Site:

Then click on your Site, click the button "Public Access Setting" and add the RESTDelegatedAuthenticator to the Apex classes accessible by this public profile.

The comple code is right here in this Github repository.

May the Force.com be with you!