In this blog, I will outline a secure method for generating SAML assertions for an API proxy designed to interact with the SuccessFactors module for various operations.
Currently, many developers relied on the /oauth/idp API to generate SAML assertions for token generation when communicating with SuccessFactors. Although this API allowed API users to generate SAML assertions for authentication, it was deemed insecure due to the necessity of passing private keys in an API call. Therefore, SAP is deprecated this API and they will delete it in November (Deprecation of OAuth IdP API /oauth/idp) and urging developers to adopt more secure practices for generating SAML assertions.
To set up a connection between SAP API Management and SuccessFactors using OAuth SAML assertion, follow these steps:
Step 1: Register an OAuth2 Client Application in SuccessFactors
Navigate to the “Manage OAuth2 Client Applications” section and click on “Register Client Application”.
Fill in the required details:Company: This field is automatically filled with your current company name.Application Name: Enter the name of the application. For this example, use “SF_SAPAPIM”.Description: (Optional) Provide a description.Application URL: Enter the URL of the system that wants to connect to SuccessFactors, e.g., http://SAPAPIMHost.com.X.509 Certificate: Generate an X.509 certificate by providing the relevant information or use the certificate from the system that wants to connect to SuccessFactors.Important: If you generate the X.509 certificate within SuccessFactors, download and securely store it for the next steps. Additionally, make sure to record the API Key that will be generated once the OAuth2 Client Application is registered.
Step 2: Convert the Certificate Format
The downloaded certificate is in PEM format. Convert it to P12 format using OpenSSL or another tool.Keep the password for the P12 certificate safe, as it will be needed in later steps.
Step 3: Store the Certificate in SAP API Management
Log in to integration suite, go to Configure.Navigate to the “Keystore” under the “Certificate” tab.Upload the P12 format certificate along with its password.
Step 4: Set up an API Proxy in SAP API Management to retrieve job information from SuccessFactors.
Navigate to the Configure tab within the integration suite and click on Create under API proxy.
Create an API proxy with named “SF_JobInformation” and fill in the necessary details—enter the API path in the URL field, choose an appropriate title, and select the Host Alias if multiple hosts are configured.
Provide an API base path, which can match the API’s path. When you input the version, it will be added before the base path and the API Proxy name you specified.
Step 5: Once the API proxy is created, save it.
Click policies section to incorporate SuccessFactors OAuth SAML assertion-related policies.
In the policy editor, insert a JavaScript policy to generate dates for “NotBefore” and “NotOnOrAfter,” which are necessary for SAML in the preflow of TargetEndPoint.
Provide Policy name and click on Add.
Create the Script and assign it in JavaScript policy to generate dates for “NotBefore” and “NotOnOrAfter”.
Script:
//pad with single zero if the value is less than 10 else return the value as is
function padWithZero(value){
return value >= 10 ? value.toString() : “0” + value.toString();
}
//function to return the date in SMAL format
function getFormattedDate(date){
var yr = date.getUTCFullYear();
var day = padWithZero(date.getUTCDate());
var mnth = padWithZero(date.getUTCMonth() + 1);
var hr = padWithZero(date.getUTCHours());
var mn = padWithZero(date.getUTCMinutes());
var sec = padWithZero(date.getUTCSeconds());
var msec = date.getUTCMilliseconds();
return yr + ‘-‘ + mnth + ‘-‘ + day + ‘T’ + hr + ‘:’ + mn + ‘:’ + sec + ‘.’ + msec + ‘Z’;
}
//Copy the date to generate a new date
function copyDate(date){
return new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
}
//function to substract n days
function substractDays(date, days){
var newDate = copyDate(date);
newDate.setTime(newDate.getTime() – days * 24 * 60 * 60 * 1000);
return newDate;
}
//function to add n days
function addDays(date, days){
var newDate = copyDate(date);
newDate.setTime(newDate.getTime() + days * 24 * 60 * 60 * 1000);
return newDate;
}
function handle_ContextType(){
context.setVariable(“request.header.Content-Type”,”application/xml”);
}
handle_ContextType();
var date = new Date();
//set the not before timestamp to 1 day before the current timestamp
context.setVariable(“DatenotBefore”, getFormattedDate(substractDays(date,1)));
//set the not after timestamp to 1 day after the current timestamp
context.setVariable(“DatenotOnorAfter”, getFormattedDate(addDays(date,1)));
Step 6: Add the SAML Assertion generator policy in the preflow of TargetEndPoint.
Code:
<GenerateSAMLAssertion async=”false” continueOnError=”false” enabled=”true” ignoreContentType = “false” xmlns=”http://www.sap.com/apimgmt”>
<CanonicalizationAlgorithm />
<Issuer> www.SF_myidp.com </ Issuer >
<KeyStore>
<Name> SF_SAML </Name>
<Alias> SF_SAML </Alias>
</KeyStore>
<OutputVariable>
<FlowVariable name=”samlassertion”/>
</OutputVariable>
<SignatureAlgorithm />
<Subject> sfadmin </ Subject >
<Template ignoreUnresolvedVariables=”false”>
<![CDATA[
<saml2:Assertion ID=”{saml.id}” IssueInstant=”{saml.issueInstant}” Version=”2.0″
xmlns:saml2=”urn:oasis:names:tc:SAML:2.0:assertion” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:xs=”http://www.w3.org/2001/XMLSchema”><saml2:Issuer
xmlns:saml2=”urn:oasis:names:tc:SAML:2.0:assertion”>{saml.issuer}</saml2:Issuer><saml2:Subject
xmlns:saml2=”urn:oasis:names:tc:SAML:2.0:assertion”><saml2:NameID Format=”urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified”>{saml.subject}</saml2:NameID><saml2:SubjectConfirmation Method=”urn:oasis:names:tc:SAML:2.0:cm:bearer”><saml2:SubjectConfirmationData NotOnOrAfter=”{DatenotOnorAfter}” Recipient=”https://successFactorsHost.com/oauth/token”/></saml2:SubjectConfirmation></saml2:Subject><saml2:Conditions NotBefore=”{DatenotBefore}” NotOnOrAfter=”{DatenotOnorAfter}”
xmlns:saml2=”urn:oasis:names:tc:SAML:2.0:assertion”><saml2:AudienceRestriction><saml2:Audience>www.successfactors.com</saml2:Audience></saml2:AudienceRestriction></saml2:Conditions>
<saml2:AttributeStatement><saml2:Attribute Name=”api_key”>
<saml2:AttributeValue xsi:type=”xs:string”>NDU0MDE0MDkwYj***5YTE5MWIxMTNkNjc1Zg</saml2:AttributeValue></saml2:Attribute></saml2:AttributeStatement> </saml2:Assertion>
]]>
</Template>
</GenerateSAMLAssertion>
Step 7: Incorporate JavaScript to remove the XML tag “<?xml version=”1.0″ encoding=”UTF-8″?>” from the response of the SAML assertion generator policy.
Code:
var assertion = context.getVariable(“samlassertion”).replace(“<?xml version=”1.0″ encoding=”UTF-8″?>”,””);
context.setVariable(“samlassertion”, assertion);
Step 8: Include a Python script to perform base64 encoding on the SAML Assertion response, which will be used in the next step to generate the token.
Code:
import base64
encoderesponse = base64.b64encode(flow.getVariable(“samlassertion”));
flow.setVariable(“base64SAMLResponse”, encoderesponse )
Step 9: Add a ServiceCall policy to make an API call to the /oauth/token API with the company ID, client ID, SAML Assertion response, and grant_type set to “urn:ietf:params:oauth:grant-type:saml2-bearer.” This call will return a token response.
Code:
<?xml version=”1.0″ encoding=”UTF-8″ standalone=”yes”?>
<ServiceCallout async=”false” continueOnError=”false” enabled=”true” xmlns=”http://www.sap.com/apimgmt”>
<Request clearPayload=”true”>
<Set>
<Payload contentType=”application/x-www-form-urlencoded”>client_id=NDU0MDE0MDkwYj***5YTE5MWIxMTNkNjc1Zg&user_id=sfadmin&company_id=SFCPA****31&assertion={base64SAMLResponse}&grant_type=urn:ietf:params:oauth:grant-type:saml2-bearer</Payload>
<Verb>POST</Verb>
</Set>
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
</Request>
<Response>sap_tokenresponse</Response>
<Timeout>30000</Timeout>
<HTTPTargetConnection>
<URL>https://successFactorsHost.com/oauth/token</URL>
</HTTPTargetConnection>
</ServiceCallout>
Step 10: Use the extractMessage policy to retrieve the token.
Step 11: Create an Authorization header using the AssignMessage policy. And deploy the API proxy after saving it.
Test the API using Postman or the test tab in the integration suite and verify that you can successfully retrieve details from SuccessFactors.
By following these steps, you will have set up the necessary OAuth2 SAML assertion authentication to enable API access between SAP API Management and SuccessFactors. Ensure all steps are completed correctly to establish a secure connection.
Also, you can create the SAML assertion offline using SAP-provided Offline tool, as mentioned in SAP KBA-3031657
References:
https://help.sap.com/docs/successfactors-platform/sap-successfactors-api-reference-guide-odata-v2/generating-saml-assertionhttps://help.sap.com/docs/sap-api-management/sap-api-management/saml-assertion-policy?version=Cloud3031657 – How to generate SAML assertions using SAP-provided Offline tool – SAP SuccessFactors | SAP Knowledge Base Article
In this blog, I will outline a secure method for generating SAML assertions for an API proxy designed to interact with the SuccessFactors module for various operations.Currently, many developers relied on the /oauth/idp API to generate SAML assertions for token generation when communicating with SuccessFactors. Although this API allowed API users to generate SAML assertions for authentication, it was deemed insecure due to the necessity of passing private keys in an API call. Therefore, SAP is deprecated this API and they will delete it in November (Deprecation of OAuth IdP API /oauth/idp) and urging developers to adopt more secure practices for generating SAML assertions.To set up a connection between SAP API Management and SuccessFactors using OAuth SAML assertion, follow these steps:Step 1: Register an OAuth2 Client Application in SuccessFactorsNavigate to the “Manage OAuth2 Client Applications” section and click on “Register Client Application”.Fill in the required details:Company: This field is automatically filled with your current company name.Application Name: Enter the name of the application. For this example, use “SF_SAPAPIM”.Description: (Optional) Provide a description.Application URL: Enter the URL of the system that wants to connect to SuccessFactors, e.g., http://SAPAPIMHost.com.X.509 Certificate: Generate an X.509 certificate by providing the relevant information or use the certificate from the system that wants to connect to SuccessFactors.Important: If you generate the X.509 certificate within SuccessFactors, download and securely store it for the next steps. Additionally, make sure to record the API Key that will be generated once the OAuth2 Client Application is registered.Step 2: Convert the Certificate FormatThe downloaded certificate is in PEM format. Convert it to P12 format using OpenSSL or another tool.Keep the password for the P12 certificate safe, as it will be needed in later steps.Step 3: Store the Certificate in SAP API ManagementLog in to integration suite, go to Configure.Navigate to the “Keystore” under the “Certificate” tab.Upload the P12 format certificate along with its password.Step 4: Set up an API Proxy in SAP API Management to retrieve job information from SuccessFactors.Navigate to the Configure tab within the integration suite and click on Create under API proxy.Create an API proxy with named “SF_JobInformation” and fill in the necessary details—enter the API path in the URL field, choose an appropriate title, and select the Host Alias if multiple hosts are configured.Provide an API base path, which can match the API’s path. When you input the version, it will be added before the base path and the API Proxy name you specified. Step 5: Once the API proxy is created, save it.Click policies section to incorporate SuccessFactors OAuth SAML assertion-related policies.In the policy editor, insert a JavaScript policy to generate dates for “NotBefore” and “NotOnOrAfter,” which are necessary for SAML in the preflow of TargetEndPoint.Provide Policy name and click on Add.Create the Script and assign it in JavaScript policy to generate dates for “NotBefore” and “NotOnOrAfter”.Script://pad with single zero if the value is less than 10 else return the value as is
function padWithZero(value){
return value >= 10 ? value.toString() : “0” + value.toString();
}
//function to return the date in SMAL format
function getFormattedDate(date){
var yr = date.getUTCFullYear();
var day = padWithZero(date.getUTCDate());
var mnth = padWithZero(date.getUTCMonth() + 1);
var hr = padWithZero(date.getUTCHours());
var mn = padWithZero(date.getUTCMinutes());
var sec = padWithZero(date.getUTCSeconds());
var msec = date.getUTCMilliseconds();
return yr + ‘-‘ + mnth + ‘-‘ + day + ‘T’ + hr + ‘:’ + mn + ‘:’ + sec + ‘.’ + msec + ‘Z’;
}
//Copy the date to generate a new date
function copyDate(date){
return new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
}
//function to substract n days
function substractDays(date, days){
var newDate = copyDate(date);
newDate.setTime(newDate.getTime() – days * 24 * 60 * 60 * 1000);
return newDate;
}
//function to add n days
function addDays(date, days){
var newDate = copyDate(date);
newDate.setTime(newDate.getTime() + days * 24 * 60 * 60 * 1000);
return newDate;
}
function handle_ContextType(){
context.setVariable(“request.header.Content-Type”,”application/xml”);
}
handle_ContextType();
var date = new Date();
//set the not before timestamp to 1 day before the current timestamp
context.setVariable(“DatenotBefore”, getFormattedDate(substractDays(date,1)));
//set the not after timestamp to 1 day after the current timestamp
context.setVariable(“DatenotOnorAfter”, getFormattedDate(addDays(date,1)));Step 6: Add the SAML Assertion generator policy in the preflow of TargetEndPoint.Code:<GenerateSAMLAssertion async=”false” continueOnError=”false” enabled=”true” ignoreContentType = “false” xmlns=”http://www.sap.com/apimgmt”>
<CanonicalizationAlgorithm />
<Issuer> www.SF_myidp.com </ Issuer >
<KeyStore>
<Name> SF_SAML </Name>
<Alias> SF_SAML </Alias>
</KeyStore>
<OutputVariable>
<FlowVariable name=”samlassertion”/>
</OutputVariable>
<SignatureAlgorithm />
<Subject> sfadmin </ Subject >
<Template ignoreUnresolvedVariables=”false”>
<![CDATA[
<saml2:Assertion ID=”{saml.id}” IssueInstant=”{saml.issueInstant}” Version=”2.0″
xmlns:saml2=”urn:oasis:names:tc:SAML:2.0:assertion” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:xs=”http://www.w3.org/2001/XMLSchema”><saml2:Issuer
xmlns:saml2=”urn:oasis:names:tc:SAML:2.0:assertion”>{saml.issuer}</saml2:Issuer><saml2:Subject
xmlns:saml2=”urn:oasis:names:tc:SAML:2.0:assertion”><saml2:NameID Format=”urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified”>{saml.subject}</saml2:NameID><saml2:SubjectConfirmation Method=”urn:oasis:names:tc:SAML:2.0:cm:bearer”><saml2:SubjectConfirmationData NotOnOrAfter=”{DatenotOnorAfter}” Recipient=”https://successFactorsHost.com/oauth/token”/></saml2:SubjectConfirmation></saml2:Subject><saml2:Conditions NotBefore=”{DatenotBefore}” NotOnOrAfter=”{DatenotOnorAfter}”
xmlns:saml2=”urn:oasis:names:tc:SAML:2.0:assertion”><saml2:AudienceRestriction><saml2:Audience>www.successfactors.com</saml2:Audience></saml2:AudienceRestriction></saml2:Conditions>
<saml2:AttributeStatement><saml2:Attribute Name=”api_key”>
<saml2:AttributeValue xsi:type=”xs:string”>NDU0MDE0MDkwYj***5YTE5MWIxMTNkNjc1Zg</saml2:AttributeValue></saml2:Attribute></saml2:AttributeStatement> </saml2:Assertion>
]]>
</Template>
</GenerateSAMLAssertion>Step 7: Incorporate JavaScript to remove the XML tag “<?xml version=”1.0″ encoding=”UTF-8″?>” from the response of the SAML assertion generator policy.Code:var assertion = context.getVariable(“samlassertion”).replace(“<?xml version=”1.0″ encoding=”UTF-8″?>”,””);
context.setVariable(“samlassertion”, assertion);Step 8: Include a Python script to perform base64 encoding on the SAML Assertion response, which will be used in the next step to generate the token.Code:import base64
encoderesponse = base64.b64encode(flow.getVariable(“samlassertion”));
flow.setVariable(“base64SAMLResponse”, encoderesponse )Step 9: Add a ServiceCall policy to make an API call to the /oauth/token API with the company ID, client ID, SAML Assertion response, and grant_type set to “urn:ietf:params:oauth:grant-type:saml2-bearer.” This call will return a token response. Code:<?xml version=”1.0″ encoding=”UTF-8″ standalone=”yes”?>
<ServiceCallout async=”false” continueOnError=”false” enabled=”true” xmlns=”http://www.sap.com/apimgmt”>
<Request clearPayload=”true”>
<Set>
<Payload contentType=”application/x-www-form-urlencoded”>client_id=NDU0MDE0MDkwYj***5YTE5MWIxMTNkNjc1Zg&user_id=sfadmin&company_id=SFCPA****31&assertion={base64SAMLResponse}&grant_type=urn:ietf:params:oauth:grant-type:saml2-bearer</Payload>
<Verb>POST</Verb>
</Set>
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
</Request>
<Response>sap_tokenresponse</Response>
<Timeout>30000</Timeout>
<HTTPTargetConnection>
<URL>https://successFactorsHost.com/oauth/token</URL>
</HTTPTargetConnection>
</ServiceCallout>Step 10: Use the extractMessage policy to retrieve the token.Step 11: Create an Authorization header using the AssignMessage policy. And deploy the API proxy after saving it.Test the API using Postman or the test tab in the integration suite and verify that you can successfully retrieve details from SuccessFactors.By following these steps, you will have set up the necessary OAuth2 SAML assertion authentication to enable API access between SAP API Management and SuccessFactors. Ensure all steps are completed correctly to establish a secure connection.Also, you can create the SAML assertion offline using SAP-provided Offline tool, as mentioned in SAP KBA-3031657 References:https://help.sap.com/docs/successfactors-platform/sap-successfactors-api-reference-guide-odata-v2/generating-saml-assertionhttps://help.sap.com/docs/sap-api-management/sap-api-management/saml-assertion-policy?version=Cloud3031657 – How to generate SAML assertions using SAP-provided Offline tool – SAP SuccessFactors | SAP Knowledge Base Article Read More Technology Blog Posts by Members articles
#SAP
#SAPTechnologyblog