Security Assertion Markup Language (SAML) is an XML-based standard for exchanging authentication and authorization data between parties, in particular, between an identity provider (IDP) and a service provider (SP). In this article, we will walk through how to set up a Node.js integration with Google SAML IDP using the SAML Tool.
Overview
The SAML flow allows you to authenticate a user's identity and obtain a SAML response that can be used to interact with Google SAML IDP on their behalf. Here are the steps involved in setting up a Node.js integration with Google SAML IDP:
- Create a Google Cloud Platform project
- Set up a SAML app in the Google Cloud Console
- Configure SAMLTool with your SAML app's settings
- Use SAMLTool to generate SAML assertion XML
- Send the SAML assertion to Google for validation
We'll go through each of these steps in detail below.
Step 1: Create a Google Cloud Platform Project
The first step is to create a Google Cloud Platform project. To do this, follow these steps:
- Log in to your Google Cloud Platform account
- Click on the "Select a project" dropdown menu in the top navigation bar
- Click on "New Project"
- Fill in the required information and click "Create"
Step 2: Set up a SAML App in the Google Cloud Console
The next step is to set up a SAML app in the Google Cloud Console. To do this, follow these steps:
- In the Google Cloud Console, select your project
- Click on "APIs & Services" and select "Credentials"
- Click on "Create Credentials" and select "OAuth client ID"
- Choose "Web application" as the application type
- Enter a name for your OAuth client ID and enter the authorized redirect URI. This should be the URL where your Node.js app will receive the SAML assertion XML from SAMLTool.
- Click "Create"
- In the "Authorized JavaScript origins" field, enter the domain name of your Node.js app.
- In the "Authorized redirect URIs" field, enter the callback URL for your Node.js app.
Step 3: Configure SAMLTool with your SAML App's Settings
The next step is to configure SAMLTool with your SAML app's settings. To do this, follow these steps:
- Go to https://www.samltool.com/
- Click on the "SAML Decoder/Encoder" tab
- In the "IDP Settings" section, enter the following information:
- Issuer: The Entity ID of your SAML app in the Google Cloud Console
- Single Sign On URL: The SSO URL of your SAML app in the Google Cloud Console
- X.509 Certificate: The public key of your SAML app in the Google Cloud Console
- In the "NameID Policy" section, select the appropriate NameID format for your SAML app.
Step 4: Use SAMLTool to Generate SAML Assertion XML
The next step is to use SAMLTool to generate SAML assertion XML. To do this, follow these steps:
- In the "SAML Decoder/Encoder" tab, select the "Encoder" tab
- Enter the following information:
- Issuer: The Entity ID of your SAML app in the Google Cloud Console
- NameID: The identifier for the user you want to authenticate
- Audience: The Entity ID of your SAML app in the Google Cloud Console
- Valid for (minutes): The amount of time the SAML assertion will be valid for
- Attributes (optional): Any additional attributes you want to include in the SAML assertion
- Click "Encode"
SAMLTool will then generate the SAML assertion XML, which you'll use in the next step.
Step 5: Send the SAML Assertion to Google for Validation
The final step is to send the SAML assertion XML to Google for validation. To do this, follow these steps:
- In your Node.js app, use the
saml2-js
library to create a SAML request and redirect the user to the SSO URL of your SAML app in the Google Cloud Console. - When the user is redirected back to your Node.js app, use the saml2-js library to validate the SAML response from Google.
Here's an example of how to create a SAML request in your Node.js app using the saml2-js
library:
const saml2 = require('saml2-js');
const idp = new saml2.IdentityProvider({
sso_login_url: '<SSO URL from Google>',
certificate: '<public key from Google>',
issuer: '<Entity ID from Google>',
});
const sp_options = {
entity_id: '<Entity ID from your Node.js app>',
assertion_consumer_service_url: '<callback URL for your Node.js app>',
private_key: '<private key for your Node.js app>',
};
const sp = new saml2.ServiceProvider(sp_options);
const options = {
relay_state: '<relay state>',
nameid_format: '<NameID format for your SAML app>',
allow_unencrypted_assertion: true,
};
const request_url = sp.create_login_request_url(idp, options);
res.redirect(request_url);
And here's an example of how to validate the SAML response in your Node.js app using the saml2-js
library:
const saml2 = require('saml2-js');
const sp_options = {
entity_id: '<Entity ID from your Node.js app>',
private_key: '<private key for your Node.js app>',
};
const sp = new saml2.ServiceProvider(sp_options);
const options = {
cert: '<public key from Google>',
audience: '<Entity ID from your Node.js app>',
};
sp.post_assert(options, function(err, saml_response) {
if (err) {
console.error(err);
res.redirect('<error URL>');
} else {
console.log(saml_response.user);
res.redirect('<success URL>');
}
});
Now lets add some unit tests to make sure that we are able to ensure that we have good code coverage.
const sinon = require('sinon');
const saml2 = require('saml2-js');
describe('ServiceProvider', () => {
describe('#post_assert()', () => {
it('should redirect to the error URL if there is an error', () => {
const sp_options = {
entity_id: '<Entity ID from your Node.js app>',
private_key: '<private key for your Node.js app>',
};
const sp = new saml2.ServiceProvider(sp_options);
const options = {
cert: '<public key from Google>',
audience: '<Entity ID from your Node.js app>',
};
const callback = sinon.stub();
const error = new Error('Something went wrong');
callback.withArgs(error).returns(undefined);
sp.post_assert(options, callback);
expect(callback.calledOnce).toBe(true);
});
it('should redirect to the success URL if there is no error', () => {
const sp_options = {
entity_id: '<Entity ID from your Node.js app>',
private_key: '<private key for your Node.js app>',
};
const sp = new saml2.ServiceProvider(sp_options);
const options = {
cert: '<public key from Google>',
audience: '<Entity ID from your Node.js app>',
};
const callback = sinon.stub();
const saml_response = { user: 'testUser' };
callback.withArgs(undefined, saml_response).returns(undefined);
sp.post_assert(options, callback);
expect(callback.calledOnce).toBe(true);
});
});
});
Top comments (0)