22

Background

If you're building an app, that involves

  1. Doing some very basic actions on behalf of non-Salesforce users, i.e. creating a Quote
  2. Is hosted externally (in other words, not APEX, but rather PHP, or Node.JS Heroku app)
  3. Requires some basic authentication for the non-Salesforce users (username and credentials stored in salesforce)
  4. Doesn't violate Salesforce Terms of Service

What's the quickest route to build that app, and what best practices should be employed to develop fast and securely?

Inspiration

After reading this question and running into this sort of app architecture several times myself, felt like this would be great to get the voice of the community on.

  • Commenting because I may be way off base, but using one of the OS CMSes that have decent integration modules would get this sort of job done quickly, right? eg, Drupal + its Salesforce Suite or Plone & its integration tools. There's no TOS violation in integrating with a remote system that authenticates, just in directly authenticating SF users, or (I believe) in creating a user-like-object with your own platform-based authentication flow. – Thomas Taylor Nov 4 '13 at 5:10
  • Ralph, Is the gist of what you're asking that responders appear to be missing, "How would I package something like this to distribute it via the App Exchange?" and "How would SF qualify something like this when distributed as an App via the App Exchange?". Am I on target? – crmprogdev Nov 9 '13 at 15:15
  • It might help to peek at the linked question which gives an example scenario. This is purely a thought experiment on what the quickest route to create some basic authentication for non-salesforce users for an app that uses data from the platform. – Ralph Callaway Nov 10 '13 at 21:17
7
+100

The key to solving this problem lies in two parts:

  1. Having a dedicated SF User to handle all requests from your 3rd Party to SFDC
  2. Creating your own User DB + Code to that verifies your 3rd Party user credentials. Once verified, they will then have access to the SF User. The extra code you'll have to write is to manage what kind of processes you want to expose to/from SFDC.

(Essentially, I am saying to write code that creates and manages your own SessionId -- roll your own "oAuth" (it's not that hard and quite empowering))

I wrote a watered-down version of what you are looking for (but it's managed on SF). What I did was create a Custom Object called Portal__c that stores Site information as well as User and Session information (in different Record Types).

Then, I wrote a class called Portal that manages all of my user activity in its static methods. On top of that, as an instance, Portal acts as a pseudo-controller that gathers Portal, User, and Session information from a Cookie I create when a user logs in. (This way, my Site doesn't use URL Parameters to determine which User is logged in -- the UserId and SessionId are "hidden" in the Cookie.)

After the backend work was completed, I could then build my VF Pages. This is where I decide what parts of the SFDC I want to expose to my 3rd Party (my Site Users). I wrote the Portal code so it's a breeze to login, register, gather User/Session/Portal data, and verify the Session in my VF controllers. (I also added methods like

public static pageReference Portal.getPortalPage(Portal.Page myEnum){...}

to stream-line page Navigation in my Site [as well as limit which Site pages are accessible]. Also, I created a basic Session History tracking mechanism. The sky's the limit!)

Note that my creation follows the schema of my solution:

  1. My dedicated SF User is a "Site User" that SF automatically creates for site users
  2. The real meat & potatos -- creating Portal__c to manage Portal/User/Session data and creating the Portal class were the key to my problem, and this is where the real work takes place. As my example shows, it can be done completely in SF, and it is not difficult to abstract this to a different platform

I elaborate in more detail here:

SSO of a force.com site with another force.com site in same org

12

Don't take this as gospel, but if your users 'own' data in Salesforce then they need licences. If however, your users can submit quotes but don't need to own the data as such, then you can use an integration user, i.e. one user you setup and use in the connecting application which submits requests on behalf of all users.

I've created this exact setup using Node.js on Heroku, using nForce to manage the connection to the salesforce org. You simply create a connected app in Salesforce and put the app details into an config JSON object that nForce uses. You can use the username/password flow which means you just have the username, password and token stored in the Heroku code itself. For the end-user authentication you could roll your own or use something like Twitter/FB authentication managed by the Heroku app.

  • Excellent point @lacey, but the question is really about how to architect the solution, not is it possible. Any tips for how to architect this sort of solution? – Ralph Callaway Nov 4 '13 at 15:47
  • Ps - take a look at the inspiration question for an example use case. – Ralph Callaway Nov 4 '13 at 18:16
  • you've got the closest effort on this question, no interest in taking another stab at this with the bounty? Just looking for some more details on your second paragraph. – Ralph Callaway Nov 11 '13 at 16:26
  • @Ralph I meant to circle back to this but never got around to it! For the record, if you want to authenticate external users who don't have Salesforce licences, Auth0 is a great service. – Matt Lacey Feb 18 '14 at 3:34
  • Great to know, will definitely check out Auth0 – Ralph Callaway Feb 18 '14 at 18:53
3

Users that use the system need to have a license. Custom authentication schemes are against the rules. However, it's very easy to be in compliance, although it will probably cost you a little bit in terms of service fees. Consider a Chatter Plus (or Chatter Only) license type-- they're intended for light user access and are inexpensive.

You can also review the other types of licenses available in Help & Training-- one of those might be more suitable for what you're trying to do (e.g. Partner Portal licenses, which come in packs of 5 for about $1500/year, or $25/user/month, last I heard). Licenses can start as low as $5/user/month or less, depending on the exact features you need. Most licenses include optional API access at no additional cost (API is an all-or-none feature, not per license).

It sounds like you simply need some Chatter Only licenses. Of course, since you want your code to be external, you'll probably be using Salesforce Identity to have the users log in through OAuth; this is deadly simple to implement in modern languages such as PHP. Heroku can be a no-brainer if your development skill set lies in Java or Ruby, since the templates for the page are git-cloned when you start a new app, literally leaving you with nothing to do but build logic and UI, with all the basic dependencies built-in and resolved ahead of time. Of course, with REST, it'd be pretty easy to do this all in normal PHP if you have your own server available.

  • Excellent suggestion, but for the sake of this question can we assume that we are creating a custom user like object? – Ralph Callaway Nov 4 '13 at 18:16
  • Ps - take a look at the inspiration question for an example use case. – Ralph Callaway Nov 4 '13 at 18:22
  • no interest in taking a second stab at this one for the bounty? – Ralph Callaway Nov 11 '13 at 16:27
3

Ok, so not only can you utilize a oAuth2 / chatter license authentication system to authenticate users on your site to SF and provide your application with a session limited access token to data scoped to the user that just logged in, you can also do the following:

Utilize an api (only) account that maintains a constant connection between your application and your Salesforce org. This is accomplished by using a server-side oAuth flow and will establish a set of credentials your application can utilize to query SF. Once you have established this connection your workflow would look like this:

End user visits website and enters credentials Your application accepts the credentials from the user, and submits a query to salesforce using your previously established connection. It's important to note that you should probably construct this query to match on username AND password (hashed accordingly ... because you are hashing AND salting passwords, Right?) 0 rows = invalid password. 1 row = valid password, 2+ rows = you're doing hashing wrong.

At this point, you've now established that the end user is, (or is not) in possession of a valid username and password which, if you've done the query right will also give you the Id of the object you were querying. I'm assuming that you'll want that Id to do other kinds of work.

All that said -- THIS IS THE WRONG WAY TO DO IT, PLEASE DON'T DO THAT. --

Let me say that again. -- DO NOT DO IT THE WAY DESCRIBED ABOVE --

To do so is to leverage almost NONE of the platform's rich and vibrant feature set, it's security and permissions features and is incredibly limiting, and prone to data-f'd-up-ness.

If you are building an application where users will be allowed to login and then access Salesforce data, let salesforce be the manager of Identity and Authentication and piggy back your application on it. In the inspiration question, the user should oauth each user to SF, and accept the salesforce asserted identity id as a FK lookup to the local user table. Ie: SF user abc1234567890defgh returned as part of the oAuth hash is matched to local user 'Awesome User'. That oAuth access token should be used for that users' data access.

Yes, this requires a change in thinking and architecture, but is safer from both a security and data sanity aspect.

1

Ralph,

I think the easiest/best way to do this authentication bit, would be to rely on the oAuth Authentication services provided by salesforce. I can only speak in depth to the Ruby side of things but I am sure there are node and php analogs.

Rails has an add-on gem called "Devise" and another called "OmniAuth" you can use OmniAuth by itself -- there's a OmniAuth-Salesforce provider pre made in fact -- or you can couple it with devise for a pre-build set of routes etc.

If you go this route, you'll need to create a "connected app" in your org, with oAuth info. These two keys (consumer key, secret key) will be needed by your external portal to start the oAuth flow.

Once you've completed the oAuth flow against Salesforce with an authenticated user (even chatter free) you'll get back the refresh, and access tokens as well as the user GUID (18 character id) that you can use to query against your external db model on a 1:1 lookup to match SFDC user to Local user.

If you have questions I can probably stand up an example rails app pretty quickly using OmniAuth to salesforce.

Additionally, if you chose to go down the enlightened ruby path, I can help you get setup with RestForce, a ruby Gem that provides brilliant sObject api access.

  • totally on board, but I think that's an answer to the different question. The users that are being autheticated won't have SFDC licenses are username, so using Salesforce OAuth isn't an option. – Ralph Callaway Nov 4 '13 at 18:15
  • Ps - take a look at the inspiration question for an example use case – Ralph Callaway Nov 4 '13 at 18:23
  • no interest in taking a second stab for the bounty? – Ralph Callaway Nov 11 '13 at 16:27
  • Ralph, I believe rolling your own authentication without utilizing licenses of some kind on the salesforce side is against the TOS. (IANAL!) – Kevin P Nov 11 '13 at 17:24
  • Ralph, All of that said, two comments. 1: the example use case question is a hot mess, and perhaps not the best example to give. Additionally, see my second answer for what I think your looking for. – Kevin P Nov 11 '13 at 17:25
0

Use JWT Bearer Token Flow to authenticate the remote host into Salesforce as a community user.

http://doingpoorly.blogspot.com/2014/11/jwt-bearer-token-flow-can-be-used-for.html

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.