While I am still trying to figure if this is a Salesforce bug or an issue with the documentation itself, or if I am missing something here, thought of getting some opinion here as well, if anyone has experienced this scenario and possible resolutions.
Use Case: Allow JIT provisioning (User Provisioning Type selected as Standard on the SSO settings setup page)/SSO for Community Users using SAML
The SAML assertion for both scenarios (JIT provisioning/SSO) consists of these attributes:
<saml:Attribute Name="User.FederationIdentifier" />
<saml:Attribute Name="User.FirstName" />
<saml:Attribute Name="Account.AccountNumber" />
<saml:Attribute Name="Account.Name" />
<saml:Attribute Name="Contact.Email" />
<saml:Attribute Name="Contact.LastName" />
Scenario 1 (JIT)
- Account exists in system
- Contact does not exist in system
- User does not exist in system
This scenario works fine based on the documentation. A Contact record is created, a User record is created and the User is logged in to the Community. Excerpt below from the documentation.
Salesforce attempts to match the Federation ID in the subject of the SAML assertion (or in an attribute element, depending upon how the SAML Identity Location is defined in the SAML Single Sign-On Settings) to the User.FederationIdentifier field of an existing user record.
If a user with a matching user record isn't found, then Salesforce searches the contacts for a match based on the Contact ID (User.Contact) or email (Contact.Email). Contact.Email and Contact.LastName are both required properties when User.Contact is not specified, but matching is only based on Contact.Email when both properties exist.
If a matching contact record isn't found, then Salesforce searches the accounts for a match based on the Contact.Account or Account.AccountNumber specified in the SAML assertion. Account.AccountNumber and Account.Name are both required properties when Contact.Account is not specified, but matching is only based on Account.AccountNumber when both properties exist. If a matching account record is found, Salesforce inserts a new user record and updates the account records based the attributes provided in the SAML assertion.
Scenario 2 (SSO:Problem)
- Account exists in system
- Contact exists in system - the same Contact as created in Scenario 1
- User exists in system - the same User as created in Scenario 1
- Contact's email is updated in system
- User's email is not updated as Contact's updated email as in above step
This is where the problem is! The documentation mentions as below (even though not clearly specifies what is updated, until you refer to the help article, quoted just after this):
If a matching user record is found, Salesforce uses the attributes in the SAML assertion to update the specified fields.
Then from this help article it clarifies what gets updated:
User record exists: Contact fields (eg LastName, Email) and User fields (eg Email, LastName, etc) are updated.
In this scenario, based on the documentation, a User record should have been found based on the Federation ID, and then Contact attributes should have been updated (even though this too does not seem to be the right, because a Contact email update during JIT/SSO is not a right thing to do if it was done for Business specific reasons). However it ends up throwing an error as "INVALID_CONTACT (23)".
It looks like the process is trying to still lookup a match on Contact even if the User would have been found using the Federation Id. My understanding is that as soon as the User was found, it should login, and update any Contact related attributes which is linked to the Community User record. But as said, this does not seem to be the case.
Now, if I remove the Contact related fields from the assertion, this works fine, i.e., the User is able to login successfully.
The issue here is that, we cannot (and don't want to) control the SAML assertion as the purpose here is JIT provisioning and that the assertion will always have a specified SAML attributes to be sent to Salesforce to support JIT.
While there are options to handle this by writing custom JIT handler, but wanted to get some thoughts here, if anyone has encountered this scenario and if had any solution to address this?