Use both a social network and strong authentication with User Driven Federation

This article is currently a work in progress, March 2018.

We had a recent customer case with the following scenario and requirements:

Users are logging in to a SAML Service Provider (target application).

A) Allow CustomerID username and password to be used for logging in.

B) If the user forgets their username and password, allow Finnish bank TUPAS authentication to be used instead. If the matching social security number is not found, present the user with the chance to register, using a registration workflow from Ubisecure  CustomerID according to their own selection.

C) Allow Facebook to the used for login. If the Facebook account has not been used before, ask the user to link the account to their existing user account by completing the login process with username and password. This is what we call User Driven Federation. If they don't have have an account, they should have the option at this point also to register, using a registration workflow from Ubisecure  CustomerID according to their own selection.  If the Facebook account has been before, the user should just be logged in to their account.

A) is standard login. B) and C) are both possible if done separately, but when combined, the user experience suffered, as by default it is impossible to give specific guidance for each situation. All three options are required on the same login page.

This article describes how to configure this scenario in a more user friendly manner.

The solution to the problem requires some creative configuration as follows:

Configure B) using the standard User Driven Federation configuration and adjust any specific messaging using the user interface customization template called federation.  In the template for the target application, include a Facebook logo, with a link to the authorization_code flow URL for the OAuth2 application (see below). The Facebook logo and link can be added using HTML within the MENU_HELP_LINKS value of the user interface text or more dynamically using javascript extensions.

For C), create an application of type OAuth2, using a unique user interface template, for example federation2. The redirect_uris value should be set to the target application, which is a SAML Service Provider. This OAuth2 application configuration will be used solely as a way to initiate a login process using only Facebook and to redirect the user to the target application after successful login. The authorization code will not be used.


Facebook authentication method configuration:

In order to allow explicit selection, add the word facebook to the OpenID Connect Authentication Context field:

The link to put on the login page will look like this

https://www.example.com/uas/oauth2/authorization?client_id=30ead3c5-86ed-44f4-96e0-6c9710bf1529&response_type=code&redirect_uri=https://www.customer.com/targetservice/&acr_values=facebook

All target applications must be whitelisted in the Stored Metadata section of the application configuration:

{"redirect_uris":["https://www.customer.com/targetservice/"]}

Multiple target services could be listed - different links could be used in different templates as required. Add as many as required.

{"redirect_uris":["https://www.customer.com/targetservice/", "https://www.another.com/targetservice2/"]}

An authorization policy must be created and attached to the application. The authorization policy should be blank.

The permitted methods tab should have both CustomerID password and Facebook enabled. Both are required to be enabled for User Driven Federation to work. The username and password fields will be hidden by using acr_values=facebook in the authorization code request link.

The Allowed To tab should be configured to allow only Facebook users.

Make a second User Driven Federation configuration and attach it to the Facebook authentication method. A sample LDIF file is provided below:

dn: cn=FacebookFederationTable,cn=Services,ou=System,cn=Ubilogin,dc=www,dc=example,dc=com
changetype: add
objectClass: top
objectClass: ubiloginService
cn: FacebookFederationTable
ubiloginClassname: com.ubisecure.customerid.federation.CIDFederationManagerFactory
ubiloginServiceInputParameter: subject
ubiloginTitle: Facebook Federation Table
 
dn: cn=FederationTable,cn=FacebookFederationTable,cn=Services,ou=System,cn=Ubilogin,dc=www,dc=example,dc=com
changetype: add
objectClass: top
objectClass: ubiloginFederationTable
cn: FederationTable
 
dn: cn=federation2,cn=Server,ou=System,cn=Ubilogin,dc=www,dc=example,dc=com
changetype: add
objectClass: top
objectClass: ubiloginLDAPURLUserMappingTable
cn: federation2

dn: cn=9871a6a6-cc57-4133-b9e4-2b3c5b9c90f9,cn=federation2,cn=Server,ou=System,cn=Ubilogin,dc=www,dc=example,dc=com
changetype: add
objectClass: top
objectClass: ubiloginServiceReference
objectClass: ubiloginServiceUserMappingEntry
cn: 9871a6a6-cc57-4133-b9e4-2b3c5b9c90f9
ubiloginServiceDN: cn=FacebookFederationTable,cn=Services,ou=System,cn=Ubilogin,dc=www,dc=example,dc=com
ubiloginServiceInputParameter: subject ${nameID}


# Modify the Facebook method to enable User Driven Federation
dn: cn=oauth.facebook.1,cn=Server,ou=System,cn=Ubilogin,dc=www,dc=example,dc=com
changetype: modify
replace: ubiloginLDAPURLUserMappingTableDN
ubiloginLDAPURLUserMappingTableDN: cn=federation2,cn=Server,ou=System,cn=Ubilogin,dc=www,dc=example,dc=com
-
changetype: modify
replace: ubiloginDirectoryServiceDN
ubiloginDirectoryServiceDN: cn=CustomerID Directory,cn=Services,ou=System,cn=Ubilogin,dc=www,dc=example,dc=com
-
changetype: add
ubiloginConfString: oidc.acr facebook

-
 
# On the authorization policy object, point to the mapping table by adding the following attribute and reference:
dn: INSERT DN TO AUTHORIZATION POLICY,ou=System,cn=Ubilogin,dc=www,dc=example,dc=com
changetype: modify
ubiloginLDAPURLUserMappingTableDN: cn=federation2,cn=Server,ou=System,dc=www,dc=ubidemo,dc=com
-
changeType: add
ubiloginConfString: FederationManager.TemplateName federation2
-

Modify the template above to match your environment and import to the Ubisecure Directory using import.cmd or import.sh