9

I am basically facing the same challenge as @Evan here

Different Session Ids in Different contexts

I'm also running into SessionID related issues, but in a completely different use case. Background is the creation of an free and 100% native IDE for force.com development http://www.elastify.eu/apps/CodeFusion running as an managed package. Goal is to get something more convenient and faster than eclipse or Developer Console.

Now I'm implementing Execute Anonymous. Using a SoapAPI callout which works - but is seriously crippled if not invoked with a "First Class Citizen SessionID". The crucial thing is to get proper Debug Logs. Therefore Headers must be set. The Log comes back as in the response. Look at this:

public static string execute(string ApexCode) {
    Http h = new Http(); HttpRequest req = new HttpRequest();
    req.setEndpoint( URL.getSalesforceBaseUrl().toExternalForm() + '/services/Soap/s/'+'30.0');
    req.setMethod('POST');
    req.setHeader('Content-Type', 'text/xml'); 
    req.setHeader('SOAPAction', '""');
    string body = ''
        +'<?xml version="1.0" encoding="UTF-8"?>'
        +'<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
          +'<env:Header>'
            +'<DebuggingHeader xmlns="http://soap.sforce.com/2006/08/apex">'
              +'<categories>'+'<level>'+'WARN'+'</level>'+'</categories>' // you can add more cats if needed
              +'<debugLevel>DEBUGONLY</debugLevel>'
            +'</DebuggingHeader>'
            +'<SessionHeader xmlns="http://soap.sforce.com/2006/08/apex">'
              +'<sessionId>'+UserInfo.getSessionId()+'</sessionId>' // The SessionID - different in vairous contexts...
            +'</SessionHeader>'
          +'</env:Header>'
          +'<env:Body>'
            +'<executeAnonymous xmlns="http://soap.sforce.com/2006/08/apex">'
              +'<String>'+ApexCode+'</String>'
            +'</executeAnonymous>'
          +'</env:Body>'
        +'</env:Envelope>'        
    ;
    req.setBody(body);
    HttpResponse res = h.send(req);
    return res.getBody();
}    

This works perfectly if put into a class which is directly created on an Org. However if you put it into a Managed Package and deploy it to a different Orgs, you will get a hard time.

I found this sources of SessionIds

  • {!$Api.Session_ID} called from an ApexPage inside an installed package ==> Non-FirstClass
  • {!$Api.Session_ID} called from an ApexPage directly on the org ==> Non-FirstClass
  • UserInfo.getSessionId() called from an ApexClass inside an installed package ==> Non-FirstClass
  • UserInfo.getSessionId() called from an ApexClass directly on the org ==> FIRST-CLASS
  • {!$Api.Session_ID} in a custom-link or button on native page-layout ==> FIRST-CLASS
  • getCookie('sid') invoked in different contexts ==> INVALID

Unfortunately I found only very hackish ways to retrieve a First-Class Ids ending up in either peek it via an iframe or complex re-routes and passes via an URL-parameter. Both is ugly, probably insecure and a hell to maintain. Now I have packaged the execute anonymous into a separate extension package to get the nasty code outside (having security review in mind).

In just using a First-Class SessionId I can't see a security issue, since you can do all the very bad things without. It feels a bit overprotective by salesforce to give us a so hard time to retrieve it. Of course the process of retrieving it should be clean.

So I'm wondering, if one of you might have also encountered and probably solved this challenge to get a working First-Class SessionId cleanly into a managed package?

  • Have the user provide their username and password to the managed package by a credentials object with encrypted fields. Then use the typical username/password authentication to get a session ID to use for the managed package function – Eric Jul 6 '14 at 20:18
  • @eric That would be an option. Could you post a link or tell me the function name on how to obtain the session id by providing user+password from within apex or visualforce? – Uwe Heim Jul 7 '14 at 7:00
  • You will have to parse the partner wsdl and add it to your package and use the login() method of the generated wsdl. You also will have to add the org the the remote site settings in your package. – Eric Jul 7 '14 at 13:05
3

Following @eric's recommendation, I was able to use login() which indeed seems to return a full powered first-class sessionId - at least for my requirement I finally got the logs!

Instead of using the WSDL I found a much simpler way to use the AJAX Toolkit just with

sforce.connection.login(username,passwordAndToken);

In the end it will do the same callout as @eric would get via the WSDL, I guess. More details and possible pitfalls you can find here: Call Login() to get a SessionID via sforce.connection.login()

Hope this information will help others.

  • Great to hear. I needed to do this in apex classes as well as async classes. The WSDL and tooling api was a god send. – Eric Jul 9 '14 at 4:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.