Showing posts tagged with:

Security

Salesforce Manager Groups

A fit-for-purpose sharing architecture is one of the fundamental elements that underpin a secure and performant Salesforce implementation. The sharing architecture defines the record-level visibility model and should be subject to periodic review and refinement to reflect shifting organisational factors. The most efficient sharing models make full use of implicit sharing via the Role Hierarchy, with minimal use of explicit techniques such as Sharing Rules. An implicit model is reliant on a well conceived Role Hierarchy that reflects data access across the organisation, and is therefore not necessarily aligned directly to the organisational structure. This is hard to achieve and requires an approach of continual adjustment throughout an implementation project and beyond. The benefits of this approach are manyfold; control, reporting, maintainability and performance being just examples. In regard to control, implicit access provides the record-owner level of access, which can’t be achieved via explicit means. With reporting, the dynamic filters “My Team’s Accounts” etc. are based on the Role Hierarchy, i.e. users in roles below the current users’ role etc. in addition with some reports the Role Hierarchy can be used to filter the output at runtime. In regard to maintainability, the proliferation of sharing rules often introduced to compensate for a substandard Role Hierarchy design is avoided. Finally, in the performance case, although sharing data (AccountShare etc.) is persisted at the time of configuration, and not calculated fully at the time of record access, there is still a performance consideration with complex sharing models. So in short, a sharing model that is predominantly implicit is better than an explicit model. Irrespective of whichever model is implemented, a comprehensive understanding of the explicit techniques and their primary use cases is important to ensure the sharing model is appropriately secure and maintainable.

For the first time in a number of releases, the Spring ’15 release introduces a new sharing model feature “Manager Groups”. This feature extends the capability of explicit sharing techniques (Manual Share, Sharing Rule and Apex Managed Sharing) enabling direct use of the management hierarchy, as defined by the Manager field on the user record. Manager Groups are system defined, per-user, and can be utilised in the same way Public Groups are used in the same contexts. For each user 2 Manager Groups are provided; “Managers Group” – immediate managers and their manager and so on (up the management hierarchy) and “Manager Subordinates Group” – the user’s direct reports and their reports and so on (down the management hierarchy). Unlike Role Hierarchy based sharing, Manager Groups share directly to each user in the hierarchy chain, not all users with the parent role.

Note, the Manager Groups feature was initially introduced in the Winter ’14 release and made available upon request. Spring ’15 makes the feature automatically available in all orgs.

Prior to the introduction of Manager Groups, sharing based on the management hierarchy relied upon the Role Hierarchy reflecting the management hierarchy, or elaborate explicit means. The Manager Groups feature now provides an efficient means to share data up and down the management hierarchy, leaving the Role Hierarchy to strongly model the data access requirements for the organisation.

Enable via Sharing Settings page

Manager Group Sharing - Settings

Manual Share

Manager Group Sharing - Manual Share

Sharing Rule Definition

Manager Group Sharing - Sharing Rule

References:
Sharing Records with Manager Groups
A Guide to Sharing Architecture
Designing Record Access for Enterprise Scale
Record-Level Access: Under the Hood

Salesforce Activity Sharing

This brief post serves to clarify the sharing model related to Activities, i.e. Task and Event. For most implementations a public sharing model for Activity is highly appropriate and a necessary element of the CRM process. In some cases however a private model is required, perhaps where strict visibility rules must be applied in respect to Account and Contact, or where the activity itself is of a confidential nature. In the former example details of the Contact (Name, Title, Account Name) are revealed on the Activity record to assigned users (and those above them in the role hierarchy) who don’t necessarily have record visibility to that Contact or Account. This can be a problem. In the latter example, the interpretation of private OWD for Activity relates to editing of records, not visibility of records (as is the case for other objects) meaning there’s no mechanism to restrict access selectively to Activity records related to a given record. In mitigation, field level security (FLS) can be applied to hide fields from certain users, this approach can be effective but is not ideal. As such the implementation of a fully private sharing model for Activity can be difficult to achieve.

Blog Sketches

Activity Org-wide Default Implications
— Private : Read access to the [Related To] record provides read access to the Activity. Only the Assigned User and users above them in the role hierarchy can edit.

— Controlled by Parent : Read access to the [Related To] record provides read access to the Activity. Edit access is possible for the Assigned User and users above them in the role hierarchy or requires edit access to the [Related To] and [Who Id] records.

In considering the OWD settings above, the rules below must also be understood.

1. Activity Visibility. If the Activity is related to a Contact, then View access is required to the Contact, with the exception of the Assigned User (and role hierarchy) who can view the Activity regardless of Contact access. Private contacts can be problematic in this context.

2. Activity Edit. If the Activity is related to a Contact, then Edit access is required to the Contact, with the exception of the Assigned User (and role hierarchy) who can edit the Activity regardless of Contact access.

References
Help and Training – Access to Activities and Calendars
Idea – Support for fully private (no read or write) activity sharing model

Salesforce OpenID Connect

In addition to the proprietary Authentication Provider types (Facebook, Janrain, Salesforce) Winter ’14 (v29.0) added support for the OpenID Connect protocol, enabling off-platform authentication via any compatible OpenID Provider (Google, PayPal, Amazon and others). This post provides a basic implementation overview.

OpenID Connect what is it?
OpenID Connect is a lightweight authentication (identity verification) protocol built on top of modern web standards (OAuth 2.0, REST and JSON). OpenID Connect supersedes OpenID 2.0 and amongst other goals is intended to promote interoperability, be accessible to developers and to provide greater support for mobile use cases.

The OpenID Connect standard was recently ratified by members of the OpenID foundation and announced publicly at the Mobile World Congress in Barcelona on 26th February 2014. The standard is supported by Google, Microsoft, Salesforce, AOL, Ping and others.

The protocol works on the principal of an “Authorization Server” or OpenID Provider (OP) (e.g. Google), authenticating users on behalf of a “Client” or Relying Party (RP) (e.g. Salesforce). With the current implementation Salesforce can be configured as a RP but not an OP. In this context an Authentication Provider is configured in Salesforce with the type set to OpenID Connect. Note OP is also referred to as IDP, confusingly we have 3 seemingly interchangeable terms – however the OP term is the one defined in the standard.

Please refer to the excellent OpenID website for more details in regard to specifications, implementations, useful FAQs etc..

Identity Use Cases
In simple terms, users can single sign-on (SSO) into Salesforce using external web application credentials. A Salesforce user record can be created just-in-time on the first authentication event, subsequent events for the user map to this user record. Note, usefully it’s also possible to map existing users via the [Existing User Linking URL].

A key use case here is B2C portals and communities, however internal users and partners can also use this authentication approach. For internal users SSO via a Google Account could make sense where an enterprise has adopted Google Apps for Business.

What’s important to understand is that Salesforce supports external Authentication Providers for all user types (with the exception of Chatter External) with SAML, OAuth and OpenID Connect protocol support. This provides a high degree of flexibility in the terms of how identity management is implemented.

Implementation Steps
The Salesforce help providers a detailed series of steps to follow. The following high-level example shows a basic implementation of a Google Accounts Authentication Provider.

1. Register an OpenID Connect Application.
As per Salesforce Connected Apps, within your Google account an application is required, within which OAuth is configured. Applications are created via the Google developers console. The Redirect URI won’t be known until the Authentication Provider is configured in Salesforce.

7. Google Developers Console

2. Create an Authentication Provider.
Consumer Key = Client ID
Consumer Secret = Client secret
Scope = profile email openid

8. Salesforce Auth Provider Detail Page

3. Update OpenID Connect Application.
Copy the Salesforce [Callback URL] to the Google [Redirect URI] field and save.

4. Add Authentication Provider to Login Page (Standard App or Community).
This step requires a My Domain where the internal app login page is customised.

9. Salesforce Login Page Customisation

5. Configure a Registration Handler class.
Within the Authentication Provider configuration a Registration Handler class can be specified, this class implements the Auth.RegistrationHandler interface and is invoked to create new users or map to existing users in response to authentication events.

[code language=”java”]

global class GoogleAccountsRegistrationHandler implements Auth.RegistrationHandler{
global Boolean canCreateUser(Auth.UserData data) {
//Check whether we want to allow creation of a user?
return true;
}

global User createUser(Id portalId, Auth.UserData data){
if(!canCreateUser(data)) {
//Returning null or throwing an exception fails the SSO flow
return null;
}
if(data.attributeMap.containsKey(‘sfdc_networkid’)) {
//We have a community id, so create a user with community access.
//.. create community user.
} else {
//.. create standard user.
return u;
}
}

global void updateUser(Id userId, Id portalId, Auth.UserData data){
User u = new User(id=userId);
//.. update fields if required.
update(u);
}
}
[/code]

Testing
1. Initialisation
The [Test-Only Initialization URL] provided on the Authentication Provider detail page can be pasted into a browser address bar and used to examine the raw output provided back from the Authorization Server.

1. Test Initialisation Output

2. Authentication
The following screenshots show the basic authentication flow. Note, as with SAML based SSO, errors are appended to the URL querystring.

Customised login page showing the Google Account Authentication Provider.

2. Login Page With Auth Providers

Clicking the button redirects the browser to the Google Service Login page to authenticate (unless a Google Accounts session exists).

3. Google Service Login Page

For new users the user consent page is displayed. This page can be customised via the Google Developer console.

10. User Consent page

Authentication errors are appended to the URL, as-per SAML authentication errors.

4. Error Page 1

5. Error Page 2

Finally, a Salesforce session is established. New users can be provisioned automatically, script within the Registration Handler class controls the configuration of such User records.

6. Auto-provisioned User Detail Page

Implementation Notes
1. Google Developer Console. Remember to turn ON – Google+ API access. This is required.

2. The auto-created Registration Handler class template must be modified as the default code will fail in many cases.
canCreateUser is false by default – in most cases this must be changed to true.

The Combination of values below don’t work if the user isn’t configured with US locale.
u.languagelocalekey = UserInfo.getLocale();
u.localesidkey = UserInfo.getLocale();
u.emailEncodingKey = ‘UTF-8’;
u.timeZoneSidKey = ‘America/Los_Angeles’;

3. Activation code entry appears to fail within an Internal Server error, but the code has been successful so subsequent attempts will succeed. This may be specific to my context.

4. As a best practice map the user Id from the OpenID Provider (Google Account Id in the example) into a custom field on the User record. This provides a robust mapping between the 2 system identifiers that can be used by the Registration Handler script.

5. Access can be revoked via the Third Party Account Link related list on the User detail page.

6. Make the OpenID Connect Application name meaningful to the end-users, the Google user consent page will display this in a “[AppName] is requesting access” format, anything weird or meaningless may cause concern.

Protocol Flow
Please treat the diagram below as indicative only, I put this together from a combination of browser profiling and assumptions made on the basis of reading the OpenID Connect specification.

As always, corrections would be appreciated.

OpenID Connect - SF Process Flow

Final Thoughts
OpenID Connect support is a highly useful extension to the Authentication Provider platform capability. For B2C portals and communities it makes sense to offer as many sign-in-via options as possible (Facebook, Google etc.) removing as much friction to user adoption as possible. As a personal opinion, over time I’m becoming less tolerant to having to register a new user account on each and every authenticated web site I interact with, particularly where I view the interaction as transient. Some users may have concerns around data security, i.e. by signing-in with a Google account are they implicitly giving Google access to the data held in the portal? In the majority case however, users will appreciate the improved user experience. For internal users OpenID Connect makes single sign-on via one or more of a multitude of current and future web platforms incredibly straightforward to implement. In the Salesforce context the key challenge will ultimately relate to reconciliation and rationalisation of identities (i.e. User records).

References
http://openid.net/connect/
http://openid.net/developers/specs/
https://developers.google.com/accounts/docs/OAuth2Login
https://console.developers.google.com/project

Salesforce Identity Connect

Over the recent years I’ve spent focused on the Salesforce architecture domain I’ve designed and implemented federated single sign-on (SSO) schemes many times (and the proprietary Delegated Authentication on rare occasions). Whilst each implementation has its nuances in terms of specific access use cases (mobile, composite app, public internet versus corporate network only etc.) and infrastructure deployment topology, there is typically a high degree of commonality. For instance, most corporate environments utilise Active Directory as the primary enterprise identity store, this is inarguable. Equally common in such environments, at least in my experience, is the absence of Active Directory Federation Services (ADFS), or any federated identity service (Ping Identity, Okta etc.). As such the introduction of SSO for Salesforce typically means introducing the infrastructure to support federated SSO as a generic service. Notable exceptions to this are corporates that have transitioned to the Office365 cloud productivity suite, where federated SSO is highly desirable for the same good reasons as those for Salesforce SSO, namely security, support and end-user experience.

Following the idea that Active Directory is pervasive in today’s corporate infrastructure environments and that Salesforce SSO implementations typically conform to a set of patterns and related technology solutions, implementing SSO becomes a question of mapping a specific set of identity management requirements appropriately.

Example patterns (illustrative and not exhaustive)

SAML Service Provider initiated flow with optional automated user provisioning.
Solution Option – ADFS (possible with AD groups and conditional custom claims rules) with SAML based JIT user provisioning.
Rationale – Simple, cost-effective solution using standardised technology. If the IT department supports AD, ADFS shouldn’t cause any alarm.

SAML Service Provider initiated flow with bi-directional identity synchronisation.
Solution Options – ADFS with middleware-based data synchronisation between Salesforce User records and AD User Principals. Or, 3rd party identity management service offering user synchronisation capability. For a simple one app, point solution Okta Cloud Connect is a free service to be evaluated alongside equivalent competitor offerings.
Rationale – ADFS has no native identity synchronisation capability. Users can be provisioned into Salesforce, and updates applied to certain fields, via SAML JIT provisioning at the time of access, however there are no background updates and perhaps most crucially there is not automated de-activation of users.

SAML Identity Provider initiated flow with bi-directional identity synchronisation.
Solution Option – 3rd party identity management service.
Rationale – ADFS offers no native user-facing IdP capability, 3rd party services offer great flexibility in this area. Salesforce itself can be used as an IdP – a subject beyond the scope of this post.

As the example patterns show, there are a number of factors to consider and a multitude of enabling technologies, each with different levels of capability (at a reflective price point). Given the complexity of a federated SSO solution, and accepting that an enterprise-wide solution should be considered over a point solution, it is key to understand the solution options available and to consider some degree of future proofing.

A relatively recent arrival in the market is Salesforce Identity Connect (October 2013), an add-on component to Salesforce Identity, providing connection to on-premise identity directories, namely Active Directory. The rest of this post outlines the result of a high-level investigation into the capabilities of Salesforce Identity connect.

Salesforce Identity Connect
Salesforce Identity Connect, hereafter referred to as SIC, is built on the ForgeRock Bridge Service Provider Edition (SPE) technology and falls into the category of 3rd identity service.

What is it?
Informal notes in no order.

On-premise identity service with a browser-based admin UI.
Supports Windows, OSX and Linux hosts.
Can be installed on Windows as a service.
Install, configure, run service. Quick to get up and running.
No ADFS proxy equivalent.
An org must be activated for Salesforce identity, this adds a download link to the setup menu and feature licenses.
One SIC instance can support multiple orgs (with different configurations). Sandboxes are supported.
Setup steps; create connections (SF and AD, define mappings, set schedule, configure SSO)
No local storage of users and passwords, user associations are held in a local MySQL db.
Connects to a SF org via OAuth 2.0
Multiple direct AD Domain Controller connections are not supported, instead a connection should be made to the Global Catalogue where multiple domains must be spanned. Note this approach requires manual modification of the AD schema.
User licenses are managed via Permission Set Licensing, not feature licensing.
Org must have Multiple SAML Configurations enabled.

What does it do?

User Authentication – Federated user authentication is supported via SAML 2.0 Service Provider Initiated and Identity Provider Initiated flows. SPI is the common case, where users access the SF My Domain and are redirected to the IdP (SIC, Identity Connect) for either seamless integrated authentication (IWA) or prompted AD login. For IWA to work there are a number of complex Kerberos authentication related setup steps to be applied to the SIC host, this can be a challenge as technical expertise in this subject area is limited. There are also end-user browser configuration changes to be applied, for IE users a GPO would cover this, for Firefox a manual configuration would be necessary. Not ideal.

User Synchronisation – Automated background synchronisation, not JIT. Mapping can be attribute-based (AD User attribute to Salesforce User field), AD Group membership to User Profile or AD Group membership to Permission Set. In the attribute case, direct mappings, transformations via JavaScript or default static values can be applied. Where transformations are applied ternary expressions are a useful convention where only populated field values are transformed to provide the target value. In the Group to Profile case, a list of AD groups are mapped to specific profiles, such mappings are defined with a precedence order such that the result is always a single profile, regardless of how many groups a user is a member of. A default profile must be defined as a catch-all. Tracking of users provisioned into Salesforce occurs via Permission Set Licenses for the Identity Connect Permission Set. User associations established by the SIC Reconciliation Report can be manually edited via the web interface. The applied association rules can also be modified where necessary. Synchronisation can be configured to run in Live Update or Scheduled Update mode. The former being more timely, but more prone to inconsistency the latter being more comprehensive approach with the typical periodic scheduling frequencies. It would be nice to have the option to combine live updates with a scheduled daily synchronisation – this doesn’t appear to be possible.

Licensing?
Salesforce Identity Connect is licensed as an add-on to Salesforce Identity at £1 per-user, per-month regardless of Edition. Current pricing can be found via this link.

Conclusions
Salesforce Identity Connect provides a capable user authentication and synchronisation service. Good points being the ease of configuration of the Salesforce side of things plus the multiple org support, the attribute and group mapping functionality is also very nice. The two downsides being the cost, although it’s an expensive area of technology, and the complexity of configuring Integrated Windows Authentication (IWA). The SSO aspect to the service is only meaningful if the SSO is seamless. Coming back to the cost, ADFS is free-of-charge but provides no user synchronisation (other than via SAML JIT). I believe many people will take this route regardless, simply to avoid any cost whatsoever, although £1 per user/month does represent a significant outlay for larger installs and could be hard to justify for performance edition customers particularly. In addition to the run cost there is also the technical complexity of establishing IWA to consider; many IT departments will look nervously at the long list of Kerberos configuration tasks and may resist the approach in terms of the effort, expertise and deployment cost involved.

To be compelling services such as SIC need to be simple and reasonably non-technical to install and run. SIC achieves this nicely for the run aspect, for the install aspect there’s some room for improvement. For many organisations the installation experience will not be an issue, the focus will be on the end-user experience and the administrative functionality, in these areas Salesforce Identity Connect looks a solid offering.

Links
Really good, short walk through video on YouTube

Implementation Guide PDF

Two-Factor Authentication

Winter ’14 introduces two-factor authentication (2FA) for both User Interface and API logins, a long-awaited security feature enabled through User Profile, or Permission Set. The relevant permissions are:

Two-Factor Authentication for User Interface Logins
Two-Factor Authentication for API Logins

The second factor in question being a time-based token generated by a Salesforce supplied, device specific authenticator app (something similar to the RSA SecurID soft-token mobile app I would expect).

User Interface Login

For User Interface logins the authentication process is shown in the screenshot below. A Salesforce generated code is entered (or scanned via QR Code) into the authenticator app which generates the 6-digit time-based token to authenticate with. At the time of writing the authenticator app download link redirects to salesforce.com/mobile path, so the end-to-end process can’t be tested as yet.

auth_time_based_token_entry

API Login

Two-factor authentication for User Interface logins is a pre-requisite for API logins. In this context the time-based token replaces the standard security token in the API login call.

The time-based token is generated via the mobile authenticator app and added to a field on the User record, as shown below.

user_time_vased_token_input

Identity Confirmation
Time-based tokens can also be used during login verification to activate a computer/device.

I’ll update this post once the authenticator apps become available and the end to end process can be tested. I need to do some investigation also into the specifics of the persisted tokens (how long-lived are they etc.?).

Update 2013-10-23
I notice that the authenticator app information is at the bottom of the salesforce.com/mobile page. Instead of providing a proprietary approach the commonly used Google Authenticator service and related apps are used. iOS screenshot below.

photo

For more information on Google Authenticator refer to here and here.

Multi-Provider Single Sign-On

The Summer ’13 release brought an interesting new feature in the area of identity management – Multi-Provider Single Sign-On. The general principle being (to my initial reading of the release notes) that a single Salesforce org can perform federated authentication to multiple identity providers. Useful indeed where SSO is desirable but the Salesforce implementation spans multiple IT environments within a single enterprise. For example a subset of the user base may have their identities managed by Active Directory whilst the remainder are Google Apps users and have no AD user principal. Prior to Summer ’13 an org could only be configured as a service provider in relation to a single identity provider (IdP), therefore in the example the Salesforce SSO settings could be configured to point to an ADFS endpoint, enabling authentication by AD but what about the Google Apps users?

So, Summer ’13 seemingly addressed this limitation enabling multiple service provider-to-identity provider relationships to be configured. All this made great sense and appeared to improve the flexibility of a native Salesforce solution. In reality this issue has historically been resolved externally to Salesforce using tools such as Ping, Okta, Janrain etc. which additionally provide extension functionality such as multi-factor authentication, finer grained access control, device access policies, user data replication etc..

The main question I’ve had with Multi-Provider Single Sign-on, since the release notes were published earlier this year, is how the authentication interaction would inform the Salesforce org which IdP to use. Would this be a querystring parameter on the My Domain, additional sub-domain or an additional My Domain perhaps? Note, the SSO process is initially anonymous, accessing a My Domain (e.g. force365blog.my.salesforce.com) allows Salesforce to check for an active SSO configuration and initiate the SSO sequence with the configured IdP. Unfortunately, it would appear that the answer to this question is straightforward, the Multi-Provider SSO functionality is limited to the new Communities functionality. In this context each active SSO configuration can be optionally enabled within a Community, the result of this being an additional button appearing on the Community login page as below.

Communities Login

It therefore becomes possible for Communities users to authenticate against multiple identity providers, internal app users remain limited to a single provider, selected from the active SSO configurations using the Authentication Service field on the My Domain page. Hopefully a future release will extend this functionality to internal app users. In the meantime the SSO documentation needs to clearly define the context of this functionality, i.e. Communities only. If I’ve missed something here, I’d appreciate a correction..

Winter ’14 Update (thanks to Leon de Beer)
With Winter ’14 it is now possible to enable multiple Authentication Services for a My Domain via Login Page branding. In doing so Service Provider Initiated SSO (SPI) no longer functions in a seamless manner, instead an Authentication Service selection page is displayed. If the “Login Page” Authentication Serivice is enabled then the login page is shown with buttons for each additional enabled service, if not then just the buttons are displayed on an otherwise empty page. So Winter ’14 opens up Multi-Provider SSO to internal users, however I don’t currently see a way to drive the automated selection of a specific Authentication Service such that SPI SSO can work in the case where multiple services are enabled.

Salesforce SSO with ADFS 2.0

In this post I’ll share some recent practical experiences implementing Federated SSO between Salesforce and Active Directory Federation Services 2.0 (ADFS 2.0 for brevity). For detailed configuration and theoretical information on this subject please refer to the excellent resources below.

http://blog.rhysgoodwin.com/cloud/salesforce-sso-with-adfs-2-0-everything-you-need-to-know/
http://wiki.developerforce.com/page/Single_Sign-On_with_Force.com_and_Microsoft_Active_Directory_Federation_Services

To set the scene – the “deployment view” schematic below shows the building blocks of a complex implementation covering most if not all possible access scenarios including portals, public web access, mobile user agents etc.

SSO ADFS

Deployment Considerations

– Salesforce
Two points to make here, firstly to emphasise the fact that all communication is routed through the browser running on the local machine (SAML 2.0 Browser Post Profile), there is no direct communication between Salesforce and ADFS proxy etc.. The second point being the importance of the introduction of a My Domain to the org, this is required for service provider initiated SSO and is necessary for mobile apps, Chatter desktop, Salesforce for Outlook and deep-links to function correctly with SSO.

– ADFS 2.0 Deployment Topology
Ideally, the ADFS configuration database should be deployed on a fault-tolerant, load-balanced SQL Server cluster – avoid the Windows internal database if you’re looking at a high-availability design. This is particularly advisable if your organisation has this SQL Server infrastructure in place. The ADFS 2.0 server role can also be deployed in a Federation Server Farm configuration, with active servers load balanced on a single virtual IP and connected to the shared configuration database. There is huge flexibility here in terms of redundancy and load-balancing configurations. The ADFS servers and configuration database host should be deployed within the corporate network, not the DMZ.

In a multi-org deployment, to workaround the unique service provider certificate limitation preventing more than one Salesforce org as a service provider in ADFS follow the instructions here.

http://help.salesforce.com/apex/HTViewSolution?id=000163471&language=en_US

– ADFS Proxy
There are other options in terms of routing inbound traffic through the DMZ, however ADFS proxy is a popular, free and secure option. A farm configuration should be deployed, with multiple (at least 2) load balanced servers behind a virrtual IP.

– Public DNS
In SAML terms a Salesforce org can be Service Provider to one (and only one) Identity Provider. In defining the single set of settings, the Identity Provider login URL must be entered. This url has to be accessible from the local machine of all prospective users, those who are connected to the corporate network and potentially those who aren’t. In order to support external users the Identity Provider host name must be resolvable by the public DNS to a secure server presenting a certificate signed by a root CA. An internal CA signed certificate is acceptable if there are no external access scenarios to consider and all SSO attempts will be made by users connected to the corporate network via cable or VPN.

– Internal DNS
Internal users must resolve the ADFS url (Identity Provider login URL) directly to the internal ADFS server host, whilst external users will resolve via public DNS registry. The internal override is key, this is necessary to ensure that Windows Integrated Authentication takes place, plus avoids an expensive routing via the public internet. Ideally this can be achieved simply via the internal DNS. In cases where internal users connect externally from the same machine (outside of a VPN connection), a localhost file entry would be problematic.

– ADFS Claim Rules (Transform)
Defined rules can (and should) be exported to a file, as a backup and convenience when recreating Relying Party Trusts within ADFS). The link below provides the Powershell instructions for this.

http://social.technet.microsoft.com/wiki/contents/articles/4869.aspx

Example rules below. Where possible use the claim rule templates (attribute population from AD, comditional static attribute population based on security group membership etc. the claim rule language is seemingly undocumented.

[sourcecode language=”text”]
@RuleTemplate = "LdapClaims"
@RuleName = "Send UPN as Name ID"
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
=> issue(store = "Active Directory", types = ("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"), query = ";userPrincipalName;{0}", param = c.Value);

@RuleTemplate = "LdapClaims"
@RuleName = "Send Email Addresses as User.Email"
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
=> issue(store = "Active Directory", types = ("User.Email"), query = ";mail;{0}", param = c.Value);

@RuleTemplate = "LdapClaims"
@RuleName = "Send Surname as User.LastName"
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
=> issue(store = "Active Directory", types = ("User.LastName"), query = ";sn;{0}", param = c.Value);

@RuleTemplate = "LdapClaims"
@RuleName = "Send UPN as User.Username"
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
=> issue(store = "Active Directory", types = ("User.username"), query = ";userPrincipalName;{0}", param = c.Value);

@RuleTemplate = "EmitGroupClaims"
@RuleName = "Send User.ProfileId for Salesforce Standard Users"
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid", Value == "S-1-5-21-1591777566-3669593721-1616705233-599", Issuer == "AD AUTHORITY"]
=> issue(Type = "User.ProfileId", Value = "00fE0000000ryDa", Issuer = c.Issuer, OriginalIssuer = c.OriginalIssuer, ValueType = c.ValueType);

@RuleTemplate = "EmitGroupClaims"
@RuleName = "Send User.ProfileId for Salesforce Chatter Users"
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid", Value == "S-1-5-21-1591777566-3669593721-1616705233-1999", Issuer == "AD AUTHORITY"]
=> issue(Type = "User.ProfileId", Value = "00fE0000000EeCs", Issuer = c.Issuer, OriginalIssuer = c.OriginalIssuer, ValueType = c.ValueType);

@RuleTemplate = "EmitGroupClaims"
@RuleName = "Send 809 as User.Department"
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid", Value == "S-1-5-21-1591777566-3669593721-1616705299-9115", Issuer == "AD AUTHORITY"]
=> issue(Type = "User.Department", Value = "809", Issuer = c.Issuer, OriginalIssuer = c.OriginalIssuer, ValueType = c.ValueType);

@RuleTemplate = "LdapClaims"
@RuleName = "Send co as User.Country"
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
=> issue(store = "Active Directory", types = ("User.Country"), query = ";co;{0}", param = c.Value);
[/sourcecode]

– ADFS Claim Rules (Authorisation)
Particularly in just-in-time (JIT) user provisioning scenarios having control over who can access Salesforce via ADFS SSO can be important. In such cases one approach can be to create an AD securtity group [Salesforce Users] and add all valid AD principles. An authorisation claim rule can be added (after removing the permit all default) to restrict access to the just the group members. Note with service provider initiated SSO, i.e. the user hits the my domain first, for non-privileged users the end result will be the display of the SAML login error page, this may not be the ideal experience. For identity provider initiated SSO, i.e. the user hits ADFS first, then an ADFS error page is displayed.

– JIT provisioning
Salesforce mandates that users provisioned via a SAML assertion must have an initial user profile Id specified in an attribute within the assertion. One approach to this requirement is to use Active Directory security groups to group subsets of the user population where the initial user profile assignment is common, i.e. [Salesforce Standard Users], [Salesforce Chatter Users] etc. A best practice with this approach is to keep the assigned profile as restricted as is feasible until an Administrator can refine the assignment with more intelligence. It would be feasible to use a custom attribute store, complex custom claim rules etc. to achieve a smarter initial profile assignment however I’ve yet to experiment too much with either.

As neither Active Directory or ADFS has any knowledge whether the user has been provisioned or not in Salesforce, it must send user-provisioning related attributes in all cases. There is an issue with this in respect to user profile. For example, user is a member of the [Salesforce Standard Users] group and is initially created with a standard user profile, subsequently another user updates the profile to system administrator – so far so good – however the next time the user accessess Salesforce via SSO, the user profile id in the SAML assertion is used to update the user back to the standard user profile – far from ideal. One approach to avoiding this is to add an Apex Trigger to the User object whch suppresses the attempted profile update, example below.

[sourcecode language=”java”]
private void processSSOUpdate(User[] updatedRecords, Map<Id, User> oldMap){
/*
ADFS has no knowledge of whether a user exists in Salesforce or not and as such must send the user profile id in all cases.
The user profile must only be used in the insert case, this trigger prevents reset of user profile changes made in Salesforce.

Note.The SSO process invokes an update on the User record on every login.
*/
if (UserInfo.getName()==’Automated Process’ || (Test.isRunningTest() && UserTestHelper.isSSOTest)){
for (User u : updatedRecords){
if(u.ProfileId!=oldMap.get(u.Id).ProfileId){
u.ProfileId=oldMap.get(u.Id).ProfileId; //& override any attempt to reset the user profile.
}
}
}
}
[/sourcecode]

Apex Trigger script can also be used to add default Chatter group membership, translate locale settings etc.

– JIT de-provisioning
In cases where SSO is enforced via login policy, deactivating the AD account prevents access to Salesforce. However in a mixed-mode scheme where users can also login using Salesforce authentication, the leavers process must involve manual deactivation of the Salesforce user. Alternatively, an integration tool could be used to query the Active Directory via an LDAP connector and apply User record deactivations to Salesforce. It may be the case that the automated logic must be two-phased, first attempt deactivation if this fails (active assignment rules associated with the user etc..) then update the user to a No Access user profile, with login hours set in a way to lock-out access.

– Browser Compatibility (seamless SSO authentication)
Browser compatibility with Windows Integration Authentication is mixed:

Firefox – not ok (requires this configuration change: http://markmonica.com/2007/11/20/firefox-and-integrated-windows-authentication/)
Chrome – ok
IE – requires the ADFS host to be added to the Trusted Site Zone. This can be achieved via System Management Tools and pushed out across the enterprise.

– Portals
Although the Single Sign-on Implementation Guide states otherwise, I have noticed that service-provider initiated SSO does work for portals users, i.e. portal user hits the my domain, is redirected to ADFS to log in and then is returned to portal in an authenticated state via the site url. This may be an anomaly.

– Login Policy
It is possible to enforce SSO at the org level, seemingly preventing standard Salesforce authentication to take place. A very good thing where appropriate, in security terms. I have noticed that you can still log in with Salesforce credentials using links as below.

https://force365.my.salesforce.com/login.jsp?un=myuser%40force365.com&pw=mypassword

– Chatter Emails
If a My Domain is introduced to the Salesforce org to support service-provider initiated SSO, it should be noted that links embedded within automated email messages will incorporate the my domain. This could be a real problem where Customers are collaborating in Chatter Customer Groups – clicking on the links (in a pre-authenticated state) will take the customer (or partner) to the identity provider login page.

Update – Troubleshooting
1) CRL check issue. If your ADFS server can’t connect to the internet you may get errors (check the event log) relating to Certificate Revocation List checks failing. To address this open Powershell (as Administrator), then use the commands below.
[sourcecode language=”powershell”]
Add-PSSnapin Microsoft.Adfs.PowerShell
Set-ADFSRelyingPartyTrust -TargetName "YourRelyingPartyDisplayName" -SigningCertificateRevocationCheck None
[/sourcecode]

2) Error MSIS7004. Make sure the ADFS service account (Network Service by default) has permissions to the ADFS certificate (right-click certificate in the certificates MMC snapin, find Manage Private Keys option, check permissions).

Update 2 – Sandbox suffixes in Claim Rules
The second Claim Rule below shows how you can handle sandbox suffixes for usernames where you’re not using a dedicated test AD.

@RuleTemplate = “LdapClaims”
@RuleName = “Send Email addresses as Email”
c:[Type == “http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname&#8221;, Issuer == “AD AUTHORITY”]
=> issue(store = “Active Directory”, types = (“User.Email”), query = “;mail;{0}”, param = c.Value);

@RuleName = “Send Email address with suffix as User.Username”
c:[Type == “User.Email”]
=> issue(Type = “User.Username”, Value = c.Value + “.test”);

Partner Portal Record Access

Finally, this post concludes a series exploring record access considerations with the different portal user license types. This post covers the Partner Portal type.

By way of reminder, the decision tree below should be used when making the high-level decision on the appropriate license type for the different user populations within your portal.

Partner Portal
The Salesforce partner portal supports partner relationship management (PRM) scenarios such as Opportunity collaboration, Lead sharing etc. Enabling businesses to manage channel activities within Salesforce in parallel to their direct sales. As with all external user access scenarios it is imperative that the visibility model provides partners with relevant data access, but no more. Partner portal users have the Gold Partner user license type – it is my understanding that the Silver and Bronze license types are no longer available.

CRUD permissions :
Create on Account, Asset, Cases, Contacts, Custom Objects, Idea, Lead, Opp – basically all the SFA standard objects.
Read on most standard objects
Update – as create, excluding Idea

Default record access :
Partner portal users are placed in the role hierarchy as below, as descendant roles of the Account Owner’s role.

So for each account where a Partner Portal user is activated (Acme in the case above), a set of 3 roles is created under whichever role the account owner has allocated. Executive users can view manager owned records and so on. The number of roles created can be set between 1tans 3, giving control over partner user sharing granularity versus proliferation of user roles (and consequential impact on performance).

Sharing options :
Role-based and criteria-based (CBS) sharing rules, manual sharing, Apex Sharing, Apex Managed Sharing.
Account and Sales teams.
Can have the “Super User” permission – this provides access to data owned by users within the same role or below in the portal account hierarchy, limited to Cases, Leads, Custom Objects and Opportunities

Other considerations :
Introducing a partner portal requires a full analysis of the sharing model implemented within a Salesforce org. Public sharing means public to partners also. This principle equally applies to report and document folders. Listviews with names which reveal something you don’t wish your partners to see should also be secured.

Note. This page on the Salesforce help site provides an excellent reference for further information.