Working with Identity Providers

Configuring SAML JIT Provisioning

SAML Just-In-Time (JIT) Provisioning automates user account creation when the user first tries to perform SSO and the user doesn't yet exist in Oracle Identity Cloud Service. In addition to automatic user creation, SAML JIT Provisioning allows granting and revoking group memberships as part of provisioning. SAML JIT Provisioning can be configured to update provisioned users so the users' attributes in the Service Provider (SP) store can be kept in sync with the Identity Provider (IDP) user store attributes.

Note:

SAML JIT Provisioning is disabled by default and must be enabled by Oracle. To enable SAML JIT Provisioning, file a Service Request with My Oracle Support.

When configuring SAML JIT Provisioning, you define how the user data sent by your SAML IDP will be used to create and/or update users in your Identity Cloud Service stripe. First, you create and configure a SAML IDP for federated SSO, and then you enable and configure the SAML JIT Provisioning options for that IDP.

SAML JIT Provisioning can be configured only via the /admin/v1/IdentityProviders REST API endpoint.

The following table describes the IDP configuration attributes relevant to SAML JIT Provisioning.
IdentityProvider Property Description JSON Example
jitUserProvEnabled

Boolean property to enable/disable the SAML JIT Provisioning feature for this IDP.

If this property is true at least one of jitUserProvCreateUserEnabled or jitUserProvAttributeUpdateEnabled also must be true.
"jitUserProvEnabled": true,
jitUserProvCreateUserEnabled

Boolean property indicating whether a user should be created, based on the incoming assertion, if the user does not yet exist.

"jitUserProvCreateUserEnabled": true,
jitUserProvAttributeUpdateEnabled

Boolean property indicating whether the user's attributes should be updated, based on the incoming assertion, if the user already exists.

"jitUserProvAttributeUpdateEnabled": true,
jitUserProvAttributes

This is a reference to a MappedAttributes object, which defines the mapping of the IDP SAML assertion attribute values to Identity Cloud Service user attributes, for both dynamic user creation and user attribute updates. (Set at creation of the IdentityProvider, do not update this reference.)

See below for details of the jitUserProvAttributes usage of the MappedAttributes resource.

 
jitUserProvGroupAssertionAttributeEnabled

Boolean property indicating whether group memberships should be assigned to the user based on a list of group names received from the IDP in a SAML attribute.

If this property is true, then the property jitUserProvGroupSAMLAttributeName must be set.

"jitUserProvGroupAssertionAttributeEnabled": true,
jitUserProvGroupSAMLAttributeName

The name of the SAML assertion attribute that will contain groups to be assigned to the user, if the property jitUserProvGroupAssertionAttributeEnabled is true.

The assertion attribute can comprise either:
  • a single AttributeValue element, containing a comma-separated list of group names; or
  • multiple AttributeValue elements, each with a single group name.
"jitUserProvGroupSAMLAttributeName": "FederatedGroups",
jitUserProvGroupStaticListEnabled

Boolean property indicating whether group memberships should be assigned to the user based on a static list of group names.

If this property is true, then the property jitUserProvAssignedGroups must be set.

"jitUserProvGroupStaticListEnabled": true,
jitUserProvAssignedGroups

Array of groups to be assigned to the user, in addition to any values received in the SAML assertion, if the property jitUserProvGroupStaticListEnabled is true.

Note: The values set in this array are group IDs (not group names).

"jitUserProvAssignedGroups": 
[
{"value": "21f273857a304684a8f7e353e452a2e1"},
{"value": "1962687f74b84121b69c5560769e8b06"}
],
jitUserProvGroupAssignmentMethod

String property that controls how group memberships will be assigned to the Identity Cloud Service user. The value must be one of:

  • Overwrite - Replace all the user's group memberships with the ones received in the SAML assertion and/or statically configured here.
  • Merge - Add to the user's existing group memberships the ones received in the SAML assertion and/or statically configured here.
"jitUserProvGroupAssignmentMethod": "Merge",

Configuring the jitUserProvAttributes Mapping

Once the IdentityProvider has been created, and the SAML JIT Provisioning attributes configured as needed, the jitUserProvAttributes resource must be updated to add your inbound attribute mappings. The MappedAttributes resource, referenced by jitUserProvAttributes, is automatically created and deleted with the IdentityProvider resource, and this property is marked immutable. The SAML JIT Provisioning attribute mappings are configured by updating the existing MappedAttributes object, not by replacing it.

The following table describes the MappedAttributes properties used by SAML JIT Provisioning.
MappedAttributes Property Description JSON Examples
attributeMappings
The list of mappings between the SAML assertion attributes and the Identity Cloud Service user attributes. Each mapping consists of:
  • idcsAttributeName - An expression defining the path to the user attribute that should be assigned an incoming value. Expressions follow the SCIM syntax, as used by the Identity Cloud Service User Sync feature. The expression given for this attribute is validated against the User schema.
  • managedObjectAttributeName - A policy expression defining the value to be mapped into the user attribute. This can have values such as $(assertion.firstname) to refer to an assertion attribute called "firstname", or it can be a static string literal, or a function.

Note: SAML assertion attribute names are case-sensitive.

"attributeMappings":[
{
"idcsAttributeName": "userName",
"managedObjectAttributeName": "$(assertion.mail)"
},
{
"idcsAttributeName": "name.givenName",
"managedObjectAttributeName": "$(assertion.firstname)"
},
{
"idcsAttributeName": "name.familyName", 
"managedObjectAttributeName": "$(assertion.lastname)" 
}, 
{ 
"idcsAttributeName": "emails[primary eq true and type eq \"work\"].value", 
"managedObjectAttributeName": "$(assertion.mail)" 
}, 
{ 
 "idcsAttributeName": "urn:ietf:params:scim:schemas:oracle:idcs:extension:user:User:isFederatedUser", 
"managedObjectAttributeName": "#toBoolean(\"true\")"
}, 
{
"idcsAttributeName":
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:Organization",
"managedObjectAttributeName": "ACME Corporation"}, 
{ 
"idcsAttributeName": "externalId", 
"managedObjectAttributeName":
"#concat(\"ACME/\",$(assertion.fed.nameidvalue))" 
}
],
refResourceType

The name of the resource that is using/has a reference to this mapped attribute (always IdentityProvider in case of SAML JIT Provisioning, do not update).

"refResourceType": "IdentityProvider",
idcsResourceType

The type of the Identity Cloud Service resource to which we are mapping (always User in the case of SAML JIT Provisioning, do not update).

"idcsResourceType": "User",
direction

Direction of the mapping, with respect to the Identity Cloud Service resource in question (always inbound in the case of SAML JIT Provisioning, do not update).

"direction": "inbound",
refResourceID

The ID of the IdentityProvider resource that has a reference to this MappedAttribute resource (set at creation, do not update).

"refResourceID": "<IDP Resource ID>",

To update the attribute mappings, first you must identify the correct MappedAttributes resource for your IDP. This can be done by retrieving the IdentityProvider resource, and looking at the $ref attribute of the jitUserProvAttributes property.

For example, you might have a MappedAttributes resource such as https://tenant-base-url/admin/v1/MappedAttributes/6533d475754845a8b0e971c48b87edda, which you would then PATCH to update its attributeMappings property.

Sample PATCH payload for MappedAttributes


{
 "schemas": [
     "urn:ietf:params:scim:api:messages:2.0:PatchOp"
 ],    "Operations": [
     {
         "op": "replace",
         "path": "attributeMappings",
         "value": [
             {
                 "managedObjectAttributeName": "$(assertion.mail)",
                 "idcsAttributeName": "userName"
             },
             {
                 "managedObjectAttributeName": "$(assertion.firstname)",
                 "idcsAttributeName": "name.givenName"
             },
             {
                 "managedObjectAttributeName": "$(assertion.lastname)",
                 "idcsAttributeName": "name.familyName"
             },
             {
                 "managedObjectAttributeName": "$(assertion.mail)",
                 "idcsAttributeName": "emails[primary eq true and type eq \"work\"].value"
             }
         ]
     }
 ]
}

SAML JIT Provisioning Attribute Mapping Usage and Runtime Behavior

If values for userName, name.givenName and name.familyName are not present, there is an error at runtime, since those attributes are marked required in the User schema. The same is true for primary email address, unless the tenant has been configured to make that optional.

At runtime, if any assertion attribute value cannot be converted to a data type that can be assigned to the user attribute to which its mapped, there will be an error and SSO will fail.

If multiple attribute mappings are configured targeting the same Identity Cloud Service user attribute, they are evaluated and executed in position order, and only the last mapping's result is retained.

An incoming assertion attribute that contains no values will result in the removal of the value from the corresponding mapped Identity Cloud Service user attribute, if jitUserProvAttributeUpdateEnabled is true.

The SAML assertion attributes Issuer and Subject NameID are supported, even though they don't appear in the AttributeStatement. They can be mapped using these reserved expressions:
  • ${assertion.fed.issuerid)
  • $(assertion.fed.nameidvalue)
Some Identity Cloud Service user/account schema attributes are not allowed for use in SAML JIT Provisioning:
  • Sensitive attributes - i.e., attributes marked "idcsSensitive: hash" or "idcsSensitive: encrypt" in the schema
  • Attributes that are marked "idcsInternal: true" in the schema
  • Attributes that are readOnly
  • All attributes that User Sync disallows

When a user is created via SAML JIT Provisioning, the following attributes will be set. These attributes aren't configurable:

  • bypassNotification : true - For example, an account activation email will not be sent to the newly-created user.
  • syncedFromApp - A reference to the Identity Provider resource corresponding to the issuer of the inbound SAML assertion.

Frequently Asked Questions

Q: Is it mandatory for groups to be present in Identity Cloud Service to update group membership during SAML JIT Provisioning?

A: Yes. Groups needs to be synced or created manually in Identity Cloud Service before group membership is updated. SAML JIT Provisioning will not create groups on the fly.

Q: Can I map a literal in attribute mapping? For example, I want to map isFederatedUser = true during user creation?

A: Yes.

Q: Do we support multi-value attributes in attribute mapping? If yes, do we patch the payload or do an override?

A: Yes. All values of the Identity Cloud Service user attribute are replaced with the net result of the SAML JIT Provisioning attribute mapping.

Q: If a user is removed from a group in the IDP, how do we handle it? What if that group is manually assigned in Identity Cloud Service? Can we configure replace versus patch behavior?

A: Group assignment via SAML JIT Provisioning update can be configured to have either Merge or Overwrite behavior, for the user's group assignments overall. For example, if update is configured for Overwrite, any manual group assignments that do not appear in the IDP assertion, will be removed.

Q: Can we configure SAML JIT Provisioning to occur only during user creation, but not to update the user later?

A: Yes. If jitUserProvCreateUserEnabled is true and jitUserProvAttributeUpdateEnabled is false, SAML JIT Provisioning will create users if they are missing, but will not update them on subsequent logins.

Custom Social Identity Providers

This use case discusses how to get Oracle Identity Cloud Service to authenticate using a custom Social Identity Provider (IdP) type.

You can set up the metadata for a custom social identity provider using the examples below.

The metadata must be posted to /admin/v1/SocialIdentityProviderMetadata.
  • to add a global level provider, invoke the <tenant-base-url>/admin/v1/SocialIdentityProviderMetadata endpoint.
  • To add a tenant level provider, invoke the <idcs-oracle-url>/admin/v1/SocialIdentityProviderMetadata endpoint.

Note:

If custom social identity providers with same name have been defined using SocialIdentityProviderMetadata at both global and tenant level, the custom social identity provider defined at the tenant level takes precedence.
Once the metadata has been loaded, you can create the new identity provider:
  • By choosing it from the console. Choose Security, then Identity Providers, then Add Social IDP and choose the new identity provider.
  • From the /admin/v1/SocialIdentityProviders REST API.

The new custom social identity provider is available as one of the Social Identity Provider Types.

Login Use Cases

These login use cases show how to change the AuthorizePhase, loginScopes, tokenPhase, and userInfoPhase depending on the provider.

In these samples, Expressions( starting with $) refer to the parameter values that are not constant:

  • $socialIdentityProvider represents the corresponding SocialIdentityProvider resource. For example, $socialIdentityProvider.consumerKey refers to the client secret configured in the tenant specific social identity provider profile.
  • ${state} is the state generated by the Identity Cloud Service runtime while sending the Authorize request to the social idp.
  • ${redirectUri} is the tenant specific callback URL generated by the Identity Cloud Service runtime.
  • ${scope} refers to:
    • In login use-case, the scope string specified as value of the loginScopes attribute.
    • In provisioning use-case, the scope string specified as value of the provisioningScopes attribute.

  • ${clientCredentials} is the standard base-64 encoded representation of client id and client secret as required in the authorization header for Basic authentication scheme.
  • ${authorizationCode} refers to the authorization code received with callback from the social idp.

In the following sections, there is sample metadata for the login use case, followed by two examples. Then the sample metadata for the provisioning use case.

Sample Metadata for Login use case

{
	"type": "SampleProviderForLogin",
	"status": "enabled",
	"idAttribute": "email",
	"capabilities": [
		"login"
	],
	"authorizePhase": {
		"loginScopes": "<scope string>",
		"url": "<Authorization endpoint>"
	},
	"authorizePhaseParameters": [
		{
			"value": "${socialIdentityProvider.consumerKey}",
			"name": "client_id"
		},
		{
			"value": "code",
			"name": "response_type"
		},
		{
			"value": "${scope}",
			"name": "scope"
		},
		{
			"value": "${state}",
			"name": "state"
		},
		{
			"value": "${redirectUri}",
			"name": "redirect_uri"
		}
	],
	"tokenPhase": {
		"url": "<Token endpoint>",
		"method": "<HTTP method for Token endpoint - get/post>"
	},
	"tokenPhaseHeaders": [
		{
			"value": "application/json",
			"name": "Accept"
		},
		{
			"value": "Basic ${clientCredentials}",
			"name": "Authorization"
		}
	],
	"tokenPhaseParameters": [
		{
			"value": "${socialIdentityProvider.consumerKey}",
			"name": "client_id"
		},
		{
			"value": "${socialIdentityProvider.consumerSecret}",
			"name": "client_secret"
		},
		{
			"value": "${redirectUri}",
			"name": "redirect_uri"
		},
		{
			"value": "${authorizationCode}",
			"name": "code"
		},
		{
			"value": "authorization_code",
			"name": "grant_type"
		}
	],
	"userInfoPhase": {
		"url": "<UserInfo endpoint>",
		"method": "<HTTP method for UserInfo endpoint - get/post>"
	},
	"userInfoPhaseHeaders": [
		{
			"value": "*/*",
			"name": "Accept"
		},
		{
			"value": "token ${accessToken}",
			"name": "Authorization"
		}
	],
	"userInfoPhaseParameters": [
		{
			"name": "access_token",
			"value": "${accessToken}"
		}
	],
	"userInfoAttributeMappings": [
		{
			"idpAttribute": "firstname",
			"idcsAttribute": "given_name"
		},
		{
			"idpAttribute": "lastname",
			"idcsAttribute": "family_name"
		},
		{
			"idpAttribute": "email.primary",
			"idcsAttribute": "email"
		}
	],
	"iconUrl": "<icon url>",
	"schemas": [
		"urn:ietf:params:scim:schemas:oracle:idcs:SocialIdentityProviderMetadata"
	]
}

Example: GitHub

{
	"type": "GitHub",
	"status": "enabled",
	"idAttribute": "email",
	"capabilities": [
		"login"
	],
	"authorizePhase": {
		"loginScopes": "user user:email",
		"url": "http://github.com/login/oauth/authorize"
	},
	"authorizePhaseParameters": [
		{
			"value": "${socialIdentityProvider.consumerKey}",
			"name": "client_id"
		},
		{
			"value": "code",
			"name": "response_type"
		},
		{
			"value": "${scope}",
			"name": "scope"
		},
		{
			"value": "${state}",
			"name": "state"
		},
		{
			"value": "${redirectUri}",
			"name": "redirect_uri"
		}
	],
	"tokenPhase": {
		"url": "https://github.com/login/oauth/access_token",
		"method": "post"
	},
	"tokenPhaseHeaders": [
		{
			"value": "application/json",
			"name": "Accept"
		},
		{
			"value": "Basic ${clientCredentials}",
			"name": "Authorization"
		}
	],
	"tokenPhaseParameters": [
		{
			"value": "${socialIdentityProvider.consumerKey}",
			"name": "client_id"
		},
		{
			"value": "${socialIdentityProvider.consumerSecret}",
			"name": "client_secret"
		},
		{
			"value": "${redirectUri}",
			"name": "redirect_uri"
		},
		{
			"value": "${authorizationCode}",
			"name": "code"
		},
		{
			"value": "authorization_code",
			"name": "grant_type"
		}
	],
	"userInfoPhase": {
		"url": "https://api.github.com/user",
		"method": "get"
	},
	"userInfoPhaseHeaders": [
		{
			"value": "*/*",
			"name": "Accept"
		},
		{
			"value": "token ${accessToken}",
			"name": "Authorization"
		}
	],
	"userInfoPhaseParameters": [
		{
			"name": "access_token",
			"value": "${accessToken}"
		}
	],
	"userInfoAttributeMappings": [
		{
			"idpAttribute": "name",
			"idcsAttribute": "given_name"
		}
	],
	"iconUrl": "<<iconURL>>",
	"schemas": [
		"urn:ietf:params:scim:schemas:oracle:idcs:SocialIdentityProviderMetadata"
	]
}

IDCS as IdentityProvider (with username mapping)

Set email as optional in IDCS using a patch operation in https://{{host}}/admin/v1/IdentitySettings/IdentitySettings.

{
    {
    "schemas": 
		[
            "urn:ietf:params:scim:api:messages:2.0:PatchOp"
        ],
    "Operations": 
        [
            {
                "op": "replace",
                "path": "primaryEmailRequired",
                "value": false
            }
        ]
    }
}

Example:

{
	"type": "IDCSProvider",
	"status": "enabled",
	"idAttribute": "preferred_username",
	"capabilities": [
		"login"
	],
	"authorizePhase": {
		"loginScopes": "openid profile email",
		"url": "https://idcs-idp-where-login-happen.identity.oraclecloud.com/oauth2/v1/authorize"
	},
	"authorizePhaseParameters": [
		{
			"value": "${socialIdentityProvider.consumerKey}",
			"name": "client_id"
		},
		{
			"value": "code",
			"name": "response_type"
		},
		{
			"value": "${scope}",
			"name": "scope"
		},
		{
			"value": "${state}",
			"name": "state"
		},
		{
			"value": "${redirectUri}",
			"name": "redirect_uri"
		}
	],
	"tokenPhase": {
		"url": "https://idcs-idp-where-login-happen.identity.oraclecloud.com/oauth2/v1/token",
		"method": "post"
	},
	"tokenPhaseHeaders": [
		{
			"value": "application/x-www-form-urlencoded",
			"name": "Content-Type"
		},
		{
			"value": "Basic ${clientCredentials}",
			"name": "Authorization"
		}
	],
	"tokenPhaseParameters": [
		{
			"value": "${authorizationCode}",
			"name": "code"
		},
		{
			"value": "authorization_code",
			"name": "grant_type"
		}
	],
	"userInfoPhase": {
		"url": "https://idcs-idp-where-login-happen.identity.oraclecloud.com/oauth2/v1/userinfo",
		"method": "get"
	},
	"userInfoPhaseHeaders": [
		{
			"value": "application/x-www-form-urlencoded",
			"name": "Content-Type"
		},
		{
			"value": "Bearer ${accessToken}",
			"name": "Authorization"
		}
	],
	"userInfoPhaseParameters": [
		{
			"name": "access_token",
			"value": "${accessToken}"
		}
	],
	"schemas": [
		"urn:ietf:params:scim:schemas:oracle:idcs:SocialIdentityProviderMetadata"
	]
}

Example: Okta

{
	"type": "OktaTest",
	"status": "enabled",
	"idAttribute": "email",
	"capabilities": [
		"login"
	],
	"authorizePhase": {
		"loginScopes": "openid profile email",
		"url": "<Okta's UserInfo endpoint>"
	},
	"authorizePhaseParameters": [
		{
			"name": "client_id",
			"value": "${socialIdentityProvider.consumerKey}"
		},
		{
			"name": "response_type",
			"value": "code"
		},
		{
			"name": "scope",
			"value": "${scope}"
		},
		{
			"name": "state",
			"value": "${state}"
		},
		{
			"name": "redirect_uri",
			"value": "${redirectUri}"
		}
	],
	"tokenPhase": {
		"url": "<Okta's UserInfo endpoint>",
		"method": "post"
	},
	"tokenPhaseHeaders": [
		{
			"value": "application/json",
			"name": "Accept"
		}
	],
	"tokenPhaseParameters": [
		{
			"value": "${socialIdentityProvider.consumerKey}",
			"name": "client_id"
		},
		{
			"value": "${socialIdentityProvider.consumerSecret}",
			"name": "client_secret"
		},
		{
			"value": "${redirectUri}",
			"name": "redirect_uri"
		},
		{
			"value": "${authorizationCode}",
			"name": "code"
		},
		{
			"value": "authorization_code",
			"name": "grant_type"
		}
	],
	"userInfoPhase": {
		"url": "<Okta's UserInfo endpoint>",
		"method": "post"
	},
	"userInfoPhaseHeaders": [
		{
			"value": "*/*",
			"name": "Accept"
		},
		{
			"value": "Bearer ${accessToken}",
			"name": "Authorization"
		}
	],
	"iconUrl": "<<iconURL>>",
	"schemas": [
		"urn:ietf:params:scim:schemas:oracle:idcs:SocialIdentityProviderMetadata"
	]
}

Sample Metadata for Provisioning use case

{
	"type": "SampleProviderForProvisioning",
	"status": "enabled",
	"capabilities": [
		"provisioning"
	],
	"authorizePhase": {
		"provisioningScopes": "<scope string>",
		"url": "<Authorization endpoint>"
	},
	"authorizePhaseParameters": [
		{
			"value": "${socialIdentityProvider.consumerKey}",
			"name": "client_id"
		},
		{
			"value": "code",
			"name": "response_type"
		},
		{
			"value": "${scope}",
			"name": "scope"
		},
		{
			"value": "${state}",
			"name": "state"
		},
		{
			"value": "${redirectUri}",
			"name": "redirect_uri"
		}
	],
	"tokenPhase": {
		"url": "<Token endpoint>",
		"method": "<HTTP method for Token endpoint - get/post>"
	},
	"tokenPhaseHeaders": [
		{
			"value": "application/json",
			"name": "Accept"
		},
		{
			"value": "Basic ${clientCredentials}",
			"name": "Authorization"
		}
	],
	"tokenPhaseParameters": [
		{
			"value": "${socialIdentityProvider.consumerKey}",
			"name": "client_id"
		},
		{
			"value": "${socialIdentityProvider.consumerSecret}",
			"name": "client_secret"
		},
		{
			"value": "${redirectUri}",
			"name": "redirect_uri"
		},
		{
			"value": "${authorizationCode}",
			"name": "code"
		},
		{
			"value": "authorization_code",
			"name": "grant_type"
		}
	],
	"refreshTokenPhaseHeaders": [
		{
			"value": "application/json",
			"name": "Accept"
		}
	],
	"refreshTokenPhaseParameters": [
		{
			"value": "${socialIdentityProvider.consumerKey}",
			"name": "client_id"
		},
		{
			"value": "${socialIdentityProvider.consumerSecret}",
			"name": "client_secret"
		},
		{
			"value": "${refreshToken}",
			"name": "refresh_token"
		}