Sitecore - How to get User ID if the user was logged in using external identity provider (Salesforce SSO) - salesforce

I have a little bit of problem with the authentication on Sitecore website. Basically there is a button on the navbar, and when user clicks on the button, it redirects the same user to Salesforce to log in (Implementation of SSO). Basically I am using Salesforce as a identity provider and Sitecore Website as a service provider. Now I have a question? When user is logged, how can I get the ID of that user.
Do users in Sitecore User Manager have the same ID as the users in Salesforce, or I can just get a email to identify the user?
P.S: Sorry if this is a really stupid question, but I am a begineer when it comes to making Sitecore websites and the SAML SSO. Thank you in advance

Stop with the Sitecore and Salesforce for a second, you'll need to cover some basics and click through the login process manually before you automate it.
You probably are using a "connected app" in Salesforce that includes OAuth2 config (consumer key also known as client id; a secret; a list of scopes telling what this app is allowed to do on behalf of this SF user; a list of allowed urls that can login using this consumer key and secret. Etc.) It might even have something about Canvas Apps at bottom of the page.
Next would be - who's logging in. A core Salesforce user or do you have Partner Community, Customer Community (recently rebranded to "Digital Experiences").
Open incognito window and go to https://openidconnect.herokuapp.com/
For login host leave as is if you have production user or test.salesforce.com if you go from sandbox (you can also use branded urls, mycompany--dev.my.salesforce.com etc). If you have a community user you'll have to change the url to whatever is the community base url, like https://dev-mycompany.cs123.force.com/mycommunity
Don't change anything else, click next, next, next. This will take you through OAuth2 "web server flow" (one of many ways to log in). You type the username/password to SF screen and go back to that herokuapp with "authorisation code". The app has few minutes to swap that code for actual final "access token" and couple other pieces of info. Final step in this wizard calls OpenId "userinfo" - returning some info about the user that logged in. That's where you could pull the email if needed (and if there are extra fields you'd like SF to return in this process that's configurable too)
Close that browser window. Check the "connected app" in SF. Open new incognito window, do same thing but this time put your url, consumer key and secret (you might have to edit the app in SF first to allow callbacks to https://openidconnect.herokuapp.com/callback).
So now you should have rough idea about whole login process. Your sitecore app probably does same thing, receives authorisation code and exchanges it for final token. At that point you have valid SF session ID you could use to call that "userinfo", run queries (if the app allowes API access, check the "scopes") etc.
I doubt the Sitecore developer created it all by hand, you probably have some Spring stuff like spring.security.oauth2.client... My Java days are long gone but if you get better at manual click-click-click through the flow you should be able to follow existing code?
It's a big topic and there are other ways to do it (other OAuth flows, sending info about the current user when you have external page embedded in SF as iframe, you'd need to read about "canvas apps")... but that's best guess based on info you provided. You might want to check some trailhead courses too like https://trailhead.salesforce.com/content/learn/projects/build-a-connected-app-for-api-integration/implement-the-oauth-20-web-server-authentication-flow
https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/intro_oauth_and_connected_apps.htm
https://developer.salesforce.com/docs/atlas.en-us.api_streaming.meta/api_streaming/code_sample_auth_oauth.htm (Java but very hand-crafted raw HTTP, probably that Spring security is better)

Related

How to access multiple salesforce orgs with same connected app

I am trying to access the multiple communities in multiple salesforce sites with same connected-app but could not.
For example: I have created the two salesforce sites A and B. And created connected-app in A. To access rest API of A, i could authenticate with connected-app in A, But how to connect with B with using the same client_secret and client_id by differs in user_name and password?
Or is there any way to connect with REST API with username and password as creds?
Example: There is community_A1, community_A2 in Site A and community_B1 , community_B2 in Site B.
I need to access communities in both the Sites
This should work out of the box, what errors you're getting?
You can have 1 set of consumer key and secret and (if admin in target org didn't block it) you could use this to login to any SF in the world, sandbox or production, core SF or community.
Imagine being a developer of mobile app that pulls data from salesforce. You'd want to have just 1 pair of keys, not install separate key for every org people might install your app...
All org-specific stuff you need is username, password and login url. For community the login url will look like https://sandboxName-MyDomain.cs123.force.com/communityName
Once you have that, you can inspect all the OAuth2 stuff at https://sandboxName-MyDomain.cs123.force.com/communityName/.well-known/openid-configuration
Have you played with https://openidconnect.herokuapp.com/ ?
Paste your community url, for now keep the client and secret as is, click next. Login to community and keep clicking next. It should work fine and at the end - give you access_token / session id.
Now close this browser completely / open new incognito window and do it again. This time give your login url but also client and secret. Next, Next... Check the user's login history, it should mention your connected app now.
Now close this and do it last time, with the other community's login url and another user's credentials but still with your client and secret.
is there any way to connect with REST API with username and password
as creds?
Not for community. Internal users can get access in one go with https://help.salesforce.com/s/articleView?id=sf.remoteaccess_oauth_username_password_flow.htm&type=5 but community/experience users need this interactive login, there has to be a human consent / password typing step. And anyway it's not very secure flow. "Experience Cloud sites don’t support the OAuth 2.0 username-password flow."
In a pinch you could try the SOAP API's login method but from what I remember you may need to pass the community's Id in the message then
Connected-app is global metadata in salesforce. Once we create a connected-app in one org, then can access any salesforce site with the same client_id,client_secret, unless the admin has blocked the access.
I needed to add the custom profile into the community members to allow the access to the community via API (Community workspace -> administration -> members -> profiles.)

Salesforce Server-to-Server integration without any user involved

I am working on a integration with Salesforce using REST APIs and, as part of the project, I need to send updates to Salesforce and these updates are not user triggered, they are system triggered.
Because of that, what I expect to see on Salesforce Field History is not a user name but the name of our Connected App (the app that made the update).
What I see today is the user name because the way the integration was made initially using OAuth Authorization Code flow.
To change that part of the project, I followed the link (OAuth 2.0 JWT Bearer Flow for Server-to-Server Integration): https://help.salesforce.com/articleView?id=sf.remoteaccess_oauth_flows.htm&type=5
Making that, I was expeting to generate a token for a System, not for a User, but that's not what happened: when I used the token generate from the JWT Bearer Flow and ran the update, the Field History still shows the user name.
What could I do then?
Which are the options in Salesforce to achieve the behavior I'm expecting?
The most important, in my opinion, is to have a Token for our system, not for a user.
Thanks!
Everybody is an user in Salesforce. Even if you access unauthenticated pages (some contact us form? case or lead capture) - it gets tracked under special Guest User.
It sounds stupid but gives you unified interface to control permissions (Profiles/Permission sets). You want guests to access only FAQ articles and make cases? Sure thing, do it in profile, don't get paranoid about people trying to guess right URLs. You think an app was hacked? You can terminate the session just like any other "user". Want to allow login only in certain hours and from certain IP? Sure.
An app connecting with JWT will still need username (main difference being it's "just" certificate for signing the request instead of password).
Your best bet is to create dedicated "Mr System", "SystemX integration" account. It sounds like waste of license but in the long run saves you questions "why did you edit my account at 1 am" and you could even use it as backup account if you use SSO and it ever fails...

Salesforce: How to automate report extraction as JSON/CSV

I am new to Salesforce, but am an experienced developer. I am provided a link to a Salesforce report, which mostly has the right filters (query). I would like to use an REST API to pull that information as CSV or JSON so that I can do further processing on it.
Here are my questions:
Do I need special permissions to make API calls? What are they?
Do I need to create an "app" with client-key & secret? Does my admin need to grant me permission for this too?
There are a lot of REST APIs from Salesforce, which one do I need to get the info from the report? Analytics?
How do I authenticate in code?
You'd have to work with the System Administrator on the security pieces. Anybody who knows how the company works, can all users see everything, is there Single Sign-On in place, how likely is the report to change...
You will need an user account to pull the data. You need to decide if it'll be some "system account" (you know username and password and have them stored in your app) or can it run for any user in this org. It might not matter much but reports are "fun". If there will be data visibility issues 6 months from now, you'll be asked to make sure the report shows only French data to French users etc... you can make it in report filters or have multiple reports - or you can just use current users access and then it's the sysadmin that has to set the sharing rules right. (would you ever think about packaging what you did and reusing in another SF instance? Making a mobile app out of it? Things like that, they may sound stupid now but will help you decide on best path)
The user (whether it'll be system account or human) needs Profile permissions like "API Enabled" + whatever else you'd need normally ("Run Reports" etc). If you're leaning towards doing it with system user - you might want to look at Password Policies and maybe set password to Never Expires. Now this is bit dangerous so there would be other things you might want to read up about: "API only user" (can't login to website), maybe even locking down the account so it can login only from certain IP ranges or at certain times when the job's supposed to be scheduled...
Connected App and OAUth2 stuff - it's a good idea to create one, yes. Technically you don't have to, you could use SOAP API to call login, get session id... But it's bit weak, OAuth2 would give you more control over security. If you have sandboxes - there's little-known trick. You can make connected app in production (or even totally unrelated Developer Edition) and use client id & secret from it to login to sandboxes. If you create app in sandbox and you refresh it - keys stop working.
(back to security piece - in connected app you can let any user allow/deny access or sysadmin would allow only say these 3 users to connect, "pre-authorize". Could be handy)
Login - there are few REST API ways to login. Depends on your decision. if you have 1 dedicated user you'll probably go with "web server flow". I've added example https://stackoverflow.com/a/56034159/313628 if you don't have a ready SF connection library in your programming language.
If you'll let users login with their own credentials there will be typical OAuth "dance" of going to the target page (Google login, LinkedIn, Twitter...) and back to your app on success. This even works if client has Single Sign-On enabled. Or you could let people type in their username and pass into your app but that's not a great solution.
Pull the actual report already
Once you have session id. Official way would be to use Reporting API, for example https://developer.salesforce.com/docs/atlas.en-us.api_analytics.meta/api_analytics/sforce_analytics_rest_api_get_reportdata.htm
A quick & dirty and officially not supported thing is to mimic what happens when user clicks the report export in UI. Craft a GET request with right cookie and you're golden. See https://stackoverflow.com/a/57745683/313628. No idea if this will work if you went with dedicated account and "API access only" permission.

IdentityServer4: allow login only for specific user/client combinations

I want to use IdentityServer4 as a common login for my own web applications.
Not all users are free to use all apps and obviously I could make all apps have users be rejected that aren't allowed to access them.
It seems a little more elegant to have a common "this app isn't activated for you" page centralized in the identity server though. That way, I need to implement that page only once. The identity server would have to have knowledge about which user may access which client, but that's reasonable in my scenario: they are all my own apps anyway.
I'm not sure what the right place is to hook the test in. It can't be the login page as the user may already be logged in to the identity server from a client he does have access to.
I wouldn't go for this approach, but I do not know the design of your apps.
I think that the url may confuse the user. Since it is the url of the IdentityServer where they see the "this app isn't activated for you" message. What does that mean to the user and where to go from there?
Besides, IdentityServer is meant to authenticate users, not to authorize users. So it doesn't seem right to move this kind of logic to IdentityServer. It also sounds like extra work.
Keep it simple. Keep authorization close to the resource and create one page with the message. Copy that to all your apps and css does the rest.
And use the default behaviour. In case an anonymous user hits a secured method, the user will automatically be rerouted to the login page. In case an authenticated user hits a method where it doesn't have access, it reroutes to the default (apps) Account/Denied page.
You can override the path in you startup configuration:
.AddCookie("Cookies", options =>
{
options.AccessDeniedPath = "/accountdenied";
})
You can show the "this app isn't activated for you" page, or you can go from there and redirect with code to the IdentityServer page. With the possibility to add additional information to customize the page.
Perhaps you can enter the page of IdentityServer instead, if that fits your design better. I haven't tried it, so I do not know if that's possible.
But in any case I would keep the authorization logic in the app.

Signup for email accounts from GAE app

I am faced with a rather strange request and there isn't much material online tackling that.
I am building a web app on GAE ... front end, back end, datastore, blob store, user accounts, the whole nine yards ...
Part of the requirements is to have a user communication system, (users sending messages to each other, just like Facebook) as user emails are not to be shared among other users, and the web app shall only send emails to the user sign up email strictly for security and administration purposes, and wont flood their inbox with notifications like some websites do.
I have narrowed narrowed it down to 4 options
Option 1:
Reinvent the wheel - Build this whole system form scratch on the Datastore and Blob store. However, not only is it expensive, but also I am not gonna go through all of that (just saying honestly)
Option 2:
Build a bouncing system ... User A sends message to app ... app bounces email to User B. Not very Elegant, impossible to create threads and conversations, eats up app Mail Quota used for Marketing and what not.
Option 3:
Host My own Email server onsite. Patch an API servlet and run the whole show through API. Very valid, except that the client doesn't want anything on site, and I wont be around to maintain it for him.
Option 4:(Best option if someone helps out)
Implement option 3 on a 3rd party email provider. Which brings us to the question, is there any respectable email provider that allows account sign up through API ?? I need to create a shadow email account on a 3rd party server(that the user will never know it exists) every time someone makes an account on my app. Then store all emails and their generated passwords in the Datastore, and when user logs in my web app, web app logs in 3rd party server, retrieves messages and serves it. When he wants to send a message, web app gets the message, sends an email using API as well. If someone knows how to do that on Gmail, I would be eternally grateful (but I highly doubt google allows that)
Note
I can implement the whole setup on xmpp/Jabber servers as well but these free servers keep changing all the time and they change their configurations ... bottom line they are not very reliable.
Thanks a lot guys !! I really appreciate any feed back and if you have any other suggestions please don't hesitate !! This is by no means a solid plan yet.

Resources