Sunday, June 22, 2014

Apex Data Loader in Linux

Salesforce Apex Data Loader is only officially supported on the Windows platform but the source code is available as an open source project for anyone to build it for another platform such as Linux or Mac. The data loader is written in Java using the Spring Framework so it can be easily rebuilt for any platform that supports the JDK and corresponding Eclipse SWT for GUI. If you don't care much for the GUI to do the mapping and simply want to use it from the command-line, then the good news is that the same JAR file from the Windows installation can be used to run the process in another platform without having to rebuild the code.

What's missing however are the Linux version of the utility scripts (in the bin\ directory in windows installation) to do the password encryption and process execution. I recently had to execute the data loader jobs from Linux and ended up writing the missing scripts so it is easy to mimic the Windows command line process (as explained in Chapter 5 in the guide).

The code is on github and includes the default configuration options and a sample extract process. The directories mirror the Windows version and the following steps walk you through the process:
  1. From your Linux (or Mac) terminal, execute the following command to clone the project from github
     $ git clone https://github.com/sthiyaga/dataloader.git 
  2. Copy the dataloader-30.0.0-uber.jar from the Windows installation to dataloader/ directory (from above)
  3. Generate the private key to encrypt the password 
    $ bin/encrypt.sh -g <some-random-seed-text>
  4. Copy the output from Step 3 above to the file conf/private.key (replacing the text in there)
  5. Encrypt the salesforce password (+security token, if required) using the generated private key 
    $ bin/encrypt.sh -e "password+securitytoken" conf/private.key 
  6. Copy the output from Step 4 above to the conf/config.properties file for the sfdc.password token value
  7. Update the conf/config.properties file with sfdc.username and sfdc.endpoint token values
  8. Optionally, adjust any other default parameters in the conf/config.properties file
  9. Run the sample account extract process 
    $ bin/process.sh csvAccountExtractProcess
That's it, you should have the sample extract in the data/ directory.

Enjoy and feel free to use the code!

-Senthil

Friday, June 6, 2014

Java Encryption, Apex Decryption

Ever had a need to decrypt something in Apex that was encrypted in an external app? Well, I just ran into a need for it where an external Java web app generates a token that is encrypted with AES and when it is sent to Salesforce.com, the token had to be decrypted to do a bunch of stuff. There are a couple of things to note if you have a similar need -- Salesforce supports encryption/decryption using AES algorithm (128 bits, 192 bits and 256 bits) but is particular about the encryption mode and padding. The mode has to be cipher block chaining (CBC) and the padding has to be PKCS5. These are different from what Java supports by default, so it is important to pass the correct settings to initialize the cipher in the encrypting application. Secondly, the initialization vector (IV) used during AES encryption can be provided separately or as part of the encrypted text and the appropriate method in the Crypto class in Apex should be used for decrypting. Refer to the docs for the Crypto class for all the gory details - http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_restful_crypto.htm

Ok, now here is a sample class in Java for generating the AES 128-bit key that will be used by both the web application to encrypt and the Apex code to decrypt the token:

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.xml.bind.DatatypeConverter;

public class AESKeyGen {
public static String generatePrivateKey() throws Exception {
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128);
SecretKey secretKey = keyGen.generateKey();
return DatatypeConverter.printBase64Binary(secretKey.getEncoded()); 
}
public static void main(String[] args) throws Exception {
String privateKey = generatePrivateKey();
System.out.println("Private Key = " + privateKey);
}
}

When run, this will produce a Base64 encoded AES private key that is 128-bits long. Needless to say, this should be kept private from the prying eyes.  

Private Key = useALumM/MAmHU1+hgsnPg==

Next is the Java class that actually encrypts the given text using this private key. In this case I'm including the IV data as part of the encrypted text by prefixing it before encoding to Base64 format.

import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;

public class AESEncrypt {
public static String encodeAES(String privateKey, String data) throws Exception {
final int AES_KEYLENGTH = 128;
byte[] iv = new byte[AES_KEYLENGTH / 8];
SecureRandom prng = new SecureRandom();
prng.nextBytes(iv);
Cipher aesCipherForEncryption = Cipher.getInstance("AES/CBC/PKCS5PADDING");
aesCipherForEncryption.init(Cipher.ENCRYPT_MODEnew SecretKeySpec(DatatypeConverter.parseBase64Binary(privateKey), "AES"), new IvParameterSpec(iv));
byte[] byteDataToEncrypt = data.getBytes();
byte[] byteCipherText = aesCipherForEncryption.doFinal(byteDataToEncrypt);

byte[] ivPlusCipher = new byte[iv.length + byteCipherText.length];
System.arraycopy(iv, 0, ivPlusCipher, 0, iv.length);
System.arraycopy(byteCipherText, 0, ivPlusCipher, iv.length, byteCipherText.length);
return DatatypeConverter.printBase64Binary(ivPlusCipher);
}
public static void main(String[] args) throws Exception {
if (args.length < 2) {
System.out.println("Usage: java AESEncrypt <private-key> <text>");
System.exit(-1);
}

System.out.println("Cipher Text = " + encodeAES(args[0], args[1]));
}
}

Here is a sample execution of the encryption class with the above private key: 

> java AESEncrypt "useALumM/MAmHU1+hgsnPg==" "Hello, (Encrypted) World!"

The output should be something similar to what you see below (it changes with each run as the IV is generated randomly each time) and again, the output includes the IV + Encrypted text in Base64 encoded format. 

Cipher Text = 86z+0A1LKPluwKEmeczUqMYMCLo6BlEOeHwx6zZh/bfsrXR8oRg2Z+csM9UHL59J

Now that we have our private key and encrypted text, the following lines of code will decrypt it in Apex (run through the Developer Console in this case) -- note the use of decryptWithManagedIV method since the encrypted text includes the IV in our case: 

Blob key = EncodingUtil.base64Decode('useALumM/MAmHU1+hgsnPg==');
Blob encData = EncodingUtil.base64Decode('86z+0A1LKPluwKEmeczUqMYMCLo6BlEOeHwx6zZh/bfsrXR8oRg2Z+csM9UHL59J');

Blob decryptedData = Crypto.decryptWithManagedIV('AES128', key, encData);

System.Debug( decryptedData.toString() );

Here is the output (from the debug log): 

18:16:50:025 USER_DEBUG [6]|DEBUG|Hello, (Encrypted) World!

That's it, feel free to reuse the code in your projects as needed. Happy Friday!

-Senthil

Thursday, December 5, 2013

Command line access to force.com #2

In the previous post I showed how to use cURL to login to salesforce.com and execute a query. It required creating a Connected App so you can use OAuth2 to authenticate and authorize. I was immediately asked by a few folks around here about the need to do that and if there was a simpler way to do this. So the good news is, yes, you can use the SOAP API to login and then use the session Id as the OAuth2 token -- it's perfectly fine.

Here is how you would issue a SOAP login request to salesforce.com using cURL without the need to configure anything:

curl -X POST https://test.salesforce.com/services/Soap/u/29.0
       -H "Content-Type:text/xml"
       -H "SOAPAction: login"
       -d "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:urn=\"urn:partner.soap.sforce.com\"><soapenv:Header/><soapenv:Body><urn:login><urn:username>YOUR_USERNAME_HERE</urn:username><urn:password>YOUR_PASSWORD_PLUS_SECURITY_TOKEN_HERE</urn:password></urn:login></soapenv:Body></soapenv:Envelope>"

Note that the above command must be in a single line. 

Now you should get a response back in XML with a bunch of details and among them the key fields to grab are the serverUrl and sessionId. The serverUrl will be of the form: https://XYZ.cs12.my.salesforce.com/services/Soap/u/29.0/00DV000000YYYYY
Just use the hostname part of the url and append /services/data/v29.0/query?q=your_query along with the sessionId as the Bearer token and you are good to go. The same query command as in the previous post should work fine with these values:

curl https://XYZ.cs12.my.salesforce.com/services/data/v29.0/query?q=Select+Name+From+Account+Limit+5 -H "Authorization: Bearer 00DV000000XXXXX!ARsAQNuDPT9Bhz9FPQFf.DZEUqATv7qbBIFc60YBOy3dvQEVEGYq4Q6iO379NYL5oeWW5yWGeBMfvrUYtyoYYYYYYY.PYFK"

The results are returned in JSON format, exactly like before!

Have fun!

Command line access to force.com

If you come from a Unix background you will surely miss the good ol' days of piping input and output between the different commands and seeing magic happen. In today's cloud connected world most of us end up working with web services and hardly do any command line anymore. There are still perfectly good use cases for using them though, especially for scripting and automating a few steps and in the case of force.com, doing deployments.

A few days ago I saw a post on developer.force.com blogs about the command line interface to force.com and I got all excited to try it out. It worked great for most part and I haven't played around with all the commands or even enough to script out a flow for specific use cases. However, the one thing that did catch me by surprise was the way authentication was done -- it uses a local HTTP server and connects to a web app hosted in heroku -- I didn't fully understand what was going on and I'm not a security expert to weigh in on the merits of this solution but I was wondering why it couldn't be done simply using OAuth2 Username/Password flow. I would have to brush up on Go programming language to perhaps extend the actual code (gladly, it's open source and on github, thank you!) but in the mean time I wanted to show how to authenticate and execute commands from the command line using cURL.

You would have to setup a Connected App as explained here. Once you set it up, you would have a Consumer Key and Consumer Secret. The next step is to get OAuth2 Access Token and for that issue the following cURL command (use test.salesforce.com for sandbox and login.salesforce.com for production or developer edition) substituting the appropriate values:

curl -X POST https://test.salesforce.com/services/oauth2/token
    -d "grant_type=password"
    -d "client_id=your_consumer_key"
    -d "client_secret=your_consumer_secret"
    -d "username=your_username"
    -d "password=your_password_plus_security_token"

Note that the above command must be issued in a single line and is shown in separate lines for clarity. 

Now SFDC should authenticate, authorize and provide the response in JSON format as follows (actual values changed for obvious reasons):

{
  "id":"https://test.salesforce.com/id/00DV00000087XXXXXX/00530000007stYYYYY",
  "issued_at":"1386263432924",
  "instance_url":"https://XYZ.cs12.my.salesforce.com",
  "signature":"WLituc1zj2tSwN7F77p1LY8slJBbGtE2kWb1mJ9H12k=",
  "access_token":"00DV00000087XXX!ARsAQNsi.0NW.mgEzP8ok_Pb.dQVam6x0ZS.1GQkjSfkTF5K"
}

The two key pieces of information that we need from the response are the instance_url and the access_token. The instance_url provides the actual sandbox (or production) instance to use and the access_token is the Session ID. Now you can make subsequent calls as follows: 

curl https://XYZ.cs12.my.salesforce.com/services/data/v29.0/query?q=Select+Name+From+Account+Limit+5 -H "Authorization: Bearer 00DV00000087XXX!ARsAQNsi.0NW.mgEzP8ok_Pb.dQVam6x0ZS.1GQkjSfkTF5K"

The Authorization header should include the access_token as the Bearer token. This request should now return the first five accounts in JSON format as follows: 

{
  "totalSize":5,
  "done":true,
  "records":[
{
             "attributes":{"type":"Account",
                             "url":"/services/data/v29.0/sobjects/Account/001V000000EWXXXYY1"},
             "Name":"Test Account #1"
        },
{
             "attributes":{"type":"Account",
                            "url":"/services/data/v29.0/sobjects/Account/001V000000EWXXXYY2"},
             "Name":"Test Account #2"
        },
{
             "attributes":{"type":"Account",
                             "url":"/services/data/v29.0/sobjects/Account/001V000000EWXXXYY3"},
             "Name":"Test Account #3"
        },
{
              "attributes":{"type":"Account",
                             "url":"/services/data/v29.0/sobjects/Account/001V000000EWXXXYY4"},
              "Name":"Test Account #4"
        },
{
             "attributes":{"type":"Account",
                            "url":"/services/data/v29.0/sobjects/Account/001V000000EWXXXYY5"},
             "Name":"Test Account #5"
        }
  ]
}

The OAuth2 access token is essentially your Session ID and should have the same validity as the Session Timeout for the Org. Also note that you don't get a refresh_token when using the username/password flow, so you would have to re-login when the session expires. 

UPDATE: Added a simpler approach in the next post to login using the SOAP API which doesn't require creation of the Connected App.

Enjoy!


Sunday, October 6, 2013

Salesforce CTA Part 2 Exam - Study Materials

A number of people have followed up with me after my earlier post on the exam about what are some of the study materials I used to prepare for the exam. To be perfectly honest, I didn't get a chance to read and review everything that I wanted to before taking the exam but I have been gathering a lot of reference material over time which I regularly reviewed and it helped when preparing for the exam. Most of them are presentations from Dreamforce '12 sessions which are available from the Salesforce Channel in YouTube and the rest are mostly articles or blogs on the developerforce.com site.

I grouped the materials into a few general areas which I think are very essential. These include (in no particular order of importance):

  • Force.com Platform
  • Platform Security
  • Integration
  • Large Data Volume Considerations
  • Single vs Multi-Org Strategy
  • Force.com Development
  • Deployment and Governance 

Again, these are just a few of the important topic areas and you should refer to the objectives in the Study Guide for the complete list.

I would highly recommend starting with this video from Dreamforce '12 which provides a good discussion around what is involved in getting the Technical Architect Certification.
http://www.youtube.com/watch?v=G2fOP7MKb6A

Force.com Platform:

The Force.com Multitenant Architecture
http://wiki.developerforce.com/page/Multi_Tenant_Architecture

Understanding Force.com Platform Internals Helps You Build Better Apps
http://blogs.developerforce.com/engineering/2013/04/understanding-force-com-platform-internals-helps-you-build-better-apps.html

Record-Level Access: Under the Hood
http://www.salesforce.com/docs/en/cce/record_access_uth/salesforce_record_access_under_the_hood.pdf

Designing Record Access for Enterprise Scale
http://www.salesforce.com/docs/en/cce/draes/draes.pdf

Platform Security:

Security Implementation Guide
http://www.salesforce.com/us/developer/docs/securityImplGuide/index.htm

A Guide to Sharing Architecture
https://na1.salesforce.com/help/doc/en/sharing_architecture.pdf

Taking a Pragmatic Look at the Salesforce Security Model

Security & Sharing Overview - You Hold the Keys
http://www.youtube.com/watch?v=UsX6mah9oKc

Managing the Role Hierarchy at Enterprise Scale
http://www.youtube.com/watch?v=FLXbt34cobg

Single Sign-On Best Practices
http://www.youtube.com/watch?v=8qTr4ulS-WU

Single Sign On with SAML
http://wiki.developerforce.com/page/Single_Sign-On_with_SAML_on_Force.com

OAuth the Big Picture
http://info.apigee.com/Portals/62317/docs/oauth_big_picture.pdf

Digging Deeper into OAuth 2.0 on Force.com
http://wiki.developerforce.com/page/Digging_Deeper_into_OAuth_2.0_on_Force.com

Single Sign-On for Desktop and Mobile Applications using SAML and OAuth
http://wiki.developerforce.com/page/Single_Sign-On_for_Desktop_and_Mobile_Applications_using_SAML_and_OAuth

You need to know all the OAuth and SAML flows in detail -- this is a MUST!

Integration:

Integration Wiki Page
http://wiki.developerforce.com/page/Integration

Integrating with the Force.com Platform

Large Data Volume Considerations:

Large Data Volume Deployments - Best Practices
http://www.youtube.com/watch?v=jgNlTMrox7g

Managing Large Data Volumes - Best Practices for Data Efficiency
http://www.youtube.com/watch?v=nrBqGkTBxMI

Extreme Salesforce Data Volumes
http://wiki.developerforce.com/page/Webinar:_Extreme_Salesforce_Data_Volumes_(2013-Feb)

Database Query and Search Optimization Cheat Sheet
http://s3.amazonaws.com/dfc-wiki/en/images/0/0e/Db-query-search-optimization-cheat-sheet.pdf

Best Practices for Deployments with Large Data Volumes:
http://wiki.developerforce.com/page/Best_Practices_for_Deployments_with_Large_Data_Volumes

Designing Dashboards and Reports for Force.com Implementations with Large Data Volumes
http://blogs.developerforce.com/engineering/2013/08/designing-dashboards-and-reports-for-force-com-implementations-with-large-data-volumes.html

Architect Salesforce Record Ownership Skew for Peak Performance in Large Data Volume Environments
http://blogs.developerforce.com/engineering/2012/06/architect-salesforce-record-ownership-skew-for-peak-performance-in-large-data-volume-environments.html

Reducing Lock Contention by Avoiding Account Data Skew
http://blogs.developerforce.com/engineering/2013/01/reducing-lock-contention-by-avoiding-account-data-skews.html

Working with Very Large SOQL Queries
http://www.salesforce.com/us/developer/docs/apexcode/Content/langCon_apex_SOQL_VLSQ.htm

Webinar: Inside the Force.com Query Optimizer
http://wiki.developerforce.com/page/Webinar:_Inside_the_Force.com_Query_Optimizer_(2013-Apr)

Maximizing the Performance of Force.com SOQL, Reports, and List Views
http://blogs.developerforce.com/engineering/2013/07/maximizing-the-performance-of-force-com-soql-reports-and-list-views.html

Single vs Multi-Org Strategy:

Why Single Org?
- 360 degree view and reporting
- Global forecasting
- Up-sell and cross-sell
- Collaboration
- Standardize Processes
- Support

Why Multi-Org?
- Legacy
- multiple businesses acquired through acquisitions
- Independent Business Units
- business units run independently of each other
- Functional
- different business processes - hr and sales
- Legal
- tax laws, compliance
- Org Limits
- salesforce governor limits, workflow, dashboard number limits
- Geographic/Language
- different regions are autonomous (US/ EMEA)

Single or Multi-org: What's Right for My Deployment?

What is the Right Org Architecture Strategy for your Enterprise?

Thinking Differently about Orgs

Force.com Development:

Salesforce Development Lifecycle Guide
http://www.salesforce.com/us/developer/docs/dev_lifecycle/salesforce_development_lifecycle.pdf

Triggers and Order of Execution
http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_triggers_order_of_execution.htm

Apex Design Patterns
http://www.youtube.com/watch?v=J372XmYds-A

Applying Enterprise Application Design Patterns on Force.com
http://www.slideshare.net/afawcett/df12-applying-enterprise-application-design-patterns-on-forcecom

Deploying Salesforce Globally
http://www.slideshare.net/Salesforce/deploying-salesforce-globally

Deployment and Governance:

Continuous Delivery with Force.com
http://www.youtube.com/watch?v=xeG5SonUuA8

Release Management for Large Organizations
http://www.youtube.com/watch?v=_3YeKq00a8I

Agile Release Management in a Large Enterprise
http://www.youtube.com/watch?v=mp8mgPQNOwg

Change and Release Management: Developing A Plan That Works For You
http://www.youtube.com/watch?v=czLxAa7XkS4

Performance Monitoring and Testing the Salesforce Cloud
http://www.youtube.com/watch?v=x2Jja81xxkE

As you can tell from just looking at the titles, even if you are not planning to take the exam any time soon, reviewing these materials in detail will give you a much better insight into the force.com platform and it's capabilities. Good luck!

Implementing a Stack in Apex

Apex collections comprise of Set, List and Map types and really nothing else. If you come from a Java or .Net background this must seem quite limiting at first given the variety of collections they support. However, in a metadata driven platform such as force.com you shouldn't have to worry about the nuances of a HashMap versus a Hashtable -- you just use a Map data structure and it is automatically optimized for you by the platform. As much as I like the simplicity of the force.com Apex programming I do miss some of the collection types that I have gotten used to in Java such as TreeMap, TreeSet and Stacks which can simplify the programming quite a bit.

Recently there was a need to implement a trigger logic which although could have been done using a List, was more appropriate for the use of a Stack. So I wrote a basic Stack class and sure enough it made the rest of the implementation a lot cleaner. There are really only three basic operations for a Stack -- push() to add an item on to the stack, pop() to remove the most recent (top most) item from the stack and peek() to take a look at the top most item without removing it from the stack. We can also add a size() method to return the number of items currently in the stack and an isEmpty() method to check if the stack is empty. You could optionally implement an iterator to iterate through the Stack but that is left as an exercise for the reader (no, you can't simply expose the List iterator :).

So here is the classic Stack implemented in Apex using the List.

public class Stack {
    private List<Object> items {get; set;}
    
    public Stack() {
        this.items = new List<Object>();
    }
    
    public Integer size() {
        return this.items.size();
    }

    public Boolean isEmpty() {
        return size() == 0;
    }
        
    public void push(Object itemToPush) {
        this.items.add(itemToPush);
    }
    
    public Object pop() {
        if (isEmpty()) {
            throw new StackUnderflowException();
        }
        
        return this.items.remove(size() - 1);
    }
    
    public Object peek() {
        if (isEmpty()) {
            throw new StackUnderflowException();
        }
        
        return this.items.get(size() - 1);
    }    
}

If we try to peek or pop from an empty stack, we would get an StackUnderflowException, which is a custom exception class: 

public class StackUnderflowException extends Exception {
    /* Custom exception */
}

That's pretty much it! Now you can use it for all sorts of LIFO (Last In First Out) type functions such as evaluating expressions or parsing a syntax tree. 

Stack s = new Stack();
s.push(10.0);
s.push(5.0);
s.push('+');

while (!s.isEmpty()) {
    Object o = s.pop();

    if (String.valueOf(o) == '+') {
        Double d1 = Double.valueOf(s.pop());
        Double d2 = Double.valueOf(s.pop());
        Double result = d1 + d2;
        System.Debug(d1 + ' + ' + d2 + ' = ' + result);
    } 
}

It should print:
5.0 + 10.0 = 15.0

Happy Stacking!

Friday, September 27, 2013

SAML Explained

So what is SAML? Well SAML stands for Security Assertion Markup Language and has become the predominant way that enterprises perform internet based Single Sign On (SSO) these days. Its been around for a while and there is plenty of documentation online that explains how it works. Still somehow every time I talk to someone about SAML and SSO, there is always some confusion. So here is an attempt at explaining the basic SAML flow in terms that you can hopefully remember.

Let's say that your rising kindergartner wants to join the soccer practice at school, what does he do? He goes to the teacher and asks if he could join the soccer practice. The teacher hands him a piece of paper and says please have your parents fill out this form and have them sign it. The kid brings that piece of paper to the parents, they look at it, consider his request, fill out the form, sign it and give it back to him, asking him to take it back to the teacher without messing with it. The kid takes the completed and signed form back to the teacher, who verifies it and lets the kid join the soccer practice. At the basic level this is exactly how SAML works -- just substitute the User for the kid, a Service Provider (SP) for the school teacher and an Identity Provider (IdP) for the parents.

Now, don't over think the analogy or expand too much upon it, I'm sure you can poke some holes; just use it to remember the basic flow of information. 

When the User tries to access a protected resource at the Service Provider, the SP will check the user's domain and will generate a SAML Request redirecting the user to the Organization's Identity Provider. The IdP will verify the identity of the user (by way of login, if not already logged in) and will generate a SAML Assertion (containing a Federated ID) and send a SAML Response back to the SP. The SP will verify the SAML Assertion (the Federated ID), log the user in and will provider access to the protected resource. Now, in all these different redirects the original URL to the protected resource that the User was trying to access will be preserved and passed in as the Relay State (not directly as a URL, but as some binding to it). Once logged in (after verifying the SAML Assertion), the SP will forward the User to the original request URL as maintained in the Relay State. Here is a picture of the flow (borrowed from article referenced below):

Saml flow.png
SAML 2.0 - Service Provider Initiated SSO

The above flow is known as the Service Provider initiated SSO in which the user first tries to access a resource at the SP and initiates the flow. A variation of this is the IdP initiated SSO where the user would login at the IdP and will click on a link to access the Service Provider. In that case, the IdP would generate the SAML Assertion when the user clicks on the Service Provider link and will take the user to the start page configured for the Service Provider. This start page at the SP should know how to validate the Assertion, automatically login the user and redirect to the home page. There is no Relay State involved here. 

The key to all this is that the Service Provider and Identify Provider have already established a trust relationship by setting up the required information, importing certificates, etc. at the time of setup -- similar to how the kid's school knows that you are the parent by requesting for the child's birth certificate, completed and signed forms etc. at the time of registration :) 

To understand in depth how SSO with SAML works in Salesforce.com, check out: 

For setting up SSO in Salesforce.com, along with examples of SAML Request and Response, Just In Time Provisioning, etc., check out the SSO Implementation Guide:
http://login.salesforce.com/help/doc/en/salesforce_single_sign_on.pdf

Finally, for setting up SSO for Desktop and Mobile apps with Salesforce, check out:
http://wiki.developerforce.com/page/Single_Sign-On_for_Desktop_and_Mobile_Applications_using_SAML_and_OAuth

Enjoy!