Take the 2-minute tour ×
Salesforce Stack Exchange is a question and answer site for Salesforce administrators, implementation experts, developers and anybody in-between. It's 100% free, no registration required.

Unfortunately, my managed package needs the ability to enforce a limit that isn't a user license. Therefore, I need my managed package, installed in subscriber orgs, to ask my LMO (License Management Org) for permission to perform a specific action. This will undoubtedly involve the subscriber org making an HTTPS callout with its Org Id to my LMO.

My thinking is that I'd create a REST method in my LMO, along with an API Only user that had access to just this REST method and nothing else. The "credentials" for this API Only user would be stored in my managed package Apex code, and thus would not be accessible to subscribers of my package. I'd rather not store a user name/password/security token combo, so I'm thinking I'd use a refresh token.

I'm fairly certain OAuth, in general, is the answer here, but I'd like to nail down a specific implementation.

share|improve this question
    
Have you taken a look at "Remote Access Apps" (help.salesforce.com/help/doc/en/remoteaccess_about.htm), or its successor: "Connected Apps" (wiki.developerforce.com/page/Connected_Apps). In either case you can configure Salesforce as the Authentication Provider (help.salesforce.com/help/doc/en/sso_provider_sfdc.htm). We have not used this for Apex callouts, but have had success with our package subscribers authenticating with a Customer Portal in our LMO (and validating their licences in the authentication process). –  Stephen Willcock Dec 18 '12 at 9:59
    
My actual app uses a Remote Access App, so yes. Looks like difference here is your use case involves the subscriber carrying out an action and I want this to happen without the subscriber having to do anything even once at package install, thus the Session Id route. –  mjgallag Dec 19 '12 at 17:18
add comment

2 Answers

up vote 1 down vote accepted

IMO, this is a false distinction that I see very often. There's really no difference between a user/pass/token and an unrestricted oauth token. A credential is a credential and, if a piece of information allows you to establish your identity (authn) in some way, then it's a credential. In some cases, an oauth token can actually be a more powerful credential than user/pass since they could allow you to do things like bypass IP restrictions. There are certain scenarios where different credentials imply different authorization schemes but I don't think that applies here.

As far as general product architecture, I'd recommend packaging a protected custom setting with your application that serves to hold a credential to the org in which you'd like to manage these entitlements. It could be a oauth token, user/pass, random string, etc. You could use a post-install script to call out to your management org and perform a registration operation to obtain this credential and store it in your protected, managed custom setting.

If it were me, I'd use a random, customer-specific string as the credential and associate that string with an Account record where I store information on that customer. I'd then create a VF page and Apex controller published to a Site so I could accept unauthenticated requests. The controller would pull the customer key out of a HTTP header and look up the appropriate account record using that key.

If you used the shared oauth token or user/pass approach linked to a real user account, you'd essentially be creating a group account than can login to your management org but is shared by all of your customers (even though they shouldn't be able to access the credential in theory).

share|improve this answer
    
I initially considered the Site approach. In fact, I really liked it because I don't have to store SFDC user account credentials (in any form) in my managed package. My concern was that someone could hit my public REST method over and over again. While they wouldn't be able to gather any information, since they wouldn't know the "customer keys", they could use up all my Site/API limits for a 24 hour period and thus essentially carry out a denial of service attack. What are your thoughts on the validity of this concern? –  mjgallag Dec 17 '12 at 19:06
    
How would that be any different from using a REST API? –  Mike Chale Dec 17 '12 at 20:28
    
While I understand the reasoning behind not using Org Ids directly, I'd like to avoid the registration step, in order to keep this as simple as possible, for now at least. Thus, what if I hashed Org Id with a "secret" stored in my managed Apex code? My managed package and LMO would use the same "secret" to covert an Org Id to a hash that would serve as the "customer key". Likely not as secure as using a registration step to create a completely random customer key, but I'm hoping this is a viable compromise. –  mjgallag Dec 17 '12 at 20:31
    
@MikeChale If I expose a REST method on a Site anyone can hit it and eat up my Site/API Limits. If I don't expose it on a Site, only authenticated users can hit it. If some random server hits my public REST method over and over it uses up my limits. If some random server trys to hit my private REST method over and over, or trys to authenticate over and over, it doesn't effect the Site/API limits in my org. In any case, I'm leaning toward the public REST method exposed via Sites (sans registration step) as it avoids the messiness of storing shared SFDC account credentials in my managed package. –  mjgallag Dec 17 '12 at 20:40
add comment

@mjgallag I don't think the install script would create another step for the customer. Post install scripts are run automatically and it should be transparent to the customer. I wouldn't recommend the salted hash with a secret salt since it's not an accepted cryptographic solution and it still comes down to the confidentiality of the code, which is consider a bad strategy in general for a number of reasons.

As far as weathering a denial of service against your Site request limits, I don't know the function or purpose of your application but I'd suggest failing open in the case of the management organization not being available. Highly available designs tend to be expensive and complicated. You could certainly have a list of entitlement verification endpoints (SFDC, EC2, Rackspace, etc) but it's probably not worth it.

Unless allowing users to temporarily perform unlicensed actions will make or break your company, I don't think it's worth the headache to design a highly available system here.

share|improve this answer
    
Great points as always. I meant the registration step would create more complexity for me, poor little solo freelance developer, just trying to finally get to his minimum viable product out the door :) In all seriousness, I'm cool with the registration step, but I'd need to pass the Org Id, or a salted hash of it, in that step, in order to associate with the appropriate license record in the LMO. I can't seem to figure out any good way around that. –  mjgallag Dec 17 '12 at 21:20
1  
If the post install callouts support UserInfo.getSessionId(), you could go that route and query the org ID given a session ID and a valid SOAP server. –  Brian Soby Dec 17 '12 at 21:27
    
Ah ha, you've always got an answer, I'll give that a shot, yet more complexity (who would have guessed :) ), and I'll need a GE/PE API Token for just this one damn API call! I really wish I could avoid all this extra work, but I've got a subscriber action that I've got to pay a 3rd party provider every time it happens, and if I don't want to have to file for bankruptcy due to a run away subscriber org, I've got to put this custom license check into place. –  mjgallag Dec 17 '12 at 21:56
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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