diff --git a/saml2-js/saml2-js-tests.ts b/saml2-js/saml2-js-tests.ts new file mode 100644 index 0000000000..6820be0b59 --- /dev/null +++ b/saml2-js/saml2-js-tests.ts @@ -0,0 +1,122 @@ +/// +/// +/// + +import * as fs from 'fs'; +import * as express from 'express'; +import * as saml2 from 'saml2-js'; + + +// Example +{ + const sp_options = { + entity_id: "https://sp.example.com/metadata.xml", + private_key: fs.readFileSync("key-file.pem").toString(), + certificate: fs.readFileSync("cert-file.crt").toString(), + assert_endpoint: "https://sp.example.com/assert", + force_authn: true, + auth_context: { comparison: "exact", class_refs: ["urn:oasis:names:tc:SAML:1.0:am:password"] }, + nameid_format: "urn:oasis:names:tc:SAML:2.0:nameid-format:transient", + sign_get_request: false, + allow_unencrypted_assertion: true + }; + + // Call service provider constructor with options + const sp = new saml2.ServiceProvider(sp_options); + + // Example use of service provider. + // Call metadata to get XML metatadata used in configuration. + const metadata = sp.create_metadata(); + + // Initialize options object + const idp_options = { + sso_login_url: "https://idp.example.com/login", + sso_logout_url: "https://idp.example.com/logout", + certificates: [fs.readFileSync("cert-file1.crt").toString(), fs.readFileSync("cert-file2.crt").toString()], + force_authn: true, + sign_get_request: false, + allow_unencrypted_assertion: false + }; + + // Call identity provider constructor with options + const idp = new saml2.IdentityProvider(idp_options); + + // Example usage of identity provider. + // Pass identity provider into a service provider function with options and a callback. + sp.post_assert(idp, {}, (error: any, response: any) => {}); +} + + +// Example: Express implementation +{ + const app = express(); + + // Create service provider + const sp_options = { + entity_id: "https://sp.example.com/metadata.xml", + private_key: fs.readFileSync("key-file.pem").toString(), + certificate: fs.readFileSync("cert-file.crt").toString(), + assert_endpoint: "https://sp.example.com/assert" + }; + const sp = new saml2.ServiceProvider(sp_options); + + // Create identity provider + const idp_options = { + sso_login_url: "https://idp.example.com/login", + sso_logout_url: "https://idp.example.com/logout", + certificates: [fs.readFileSync("cert-file1.crt").toString(), fs.readFileSync("cert-file2.crt").toString()] + }; + const idp = new saml2.IdentityProvider(idp_options); + + // ------ Define express endpoints ------ + + // Endpoint to retrieve metadata + app.get("/metadata.xml", function(req, res) { + res.type('application/xml'); + res.send(sp.create_metadata()); + }); + + // Starting point for login + app.get("/login", function(req, res) { + sp.create_login_request_url(idp, {}, function(err, login_url, request_id) { + if (err != null) + return res.send(500); + res.redirect(login_url); + }); + }); + + // Assert endpoint for when login completes + app.post("/assert", function(req, res) { + const options = {request_body: req.body}; + sp.post_assert(idp, options, function(err, saml_response) { + if (err != null) + return res.send(500); + + // Save name_id and session_index for logout + // Note: In practice these should be saved in the user session, not globally. + let name_id = saml_response.user.name_id; + let session_index = saml_response.user.session_index; + + res.send("Hello #{saml_response.user.name_id}!"); + }); + }); + + // Starting point for logout + app.get("/logout", function(req, res) { + let name_id = ''; + let session_index = ''; + const options = { + name_id: name_id, + session_index: session_index + }; + + sp.create_logout_request_url(idp, options, function(err, logout_url) { + if (err != null) + return res.send(500); + res.redirect(logout_url); + }); + }); + + app.listen(3000); +} + diff --git a/saml2-js/saml2-js.d.ts b/saml2-js/saml2-js.d.ts new file mode 100644 index 0000000000..296cd6eb26 --- /dev/null +++ b/saml2-js/saml2-js.d.ts @@ -0,0 +1,74 @@ +// Type definitions for SAML2-js 1.6.0 +// Project: https://github.com/Clever/saml2 +// Definitions by: horiuchi +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +declare module "saml2-js" { + + export class IdentityProvider { + constructor(options: IdentityProviderOptions); + } + export interface IdentityProviderOptions { + sso_login_url: string; + sso_logout_url: string; + certificates: string[]; + force_authn?: boolean; + sign_get_request?: boolean; + allow_unencrypted_assertion?: boolean; + } + + + export class ServiceProvider { + constructor(options: ServiceProviderOptions); + + create_login_request_url(IdP: IdentityProvider, options: CreateLoginRequestUrlOptions, cb: (error: any, login_url: string, request_id: string) => void): void; + redirect_assert(IdP: IdentityProvider, options: GetAssertOptions, cb: (error: any, response: any) => void): void; + post_assert(IdP: IdentityProvider, options: GetAssertOptions, cb: (error: any, response: any) => void): void; + create_logout_request_url(IdP: IdentityProvider, options: CreateLogoutRequestUrlOptions, cb: (error: any, request_url: string) => void): void; + create_logout_response_url(IdP: IdentityProvider, options: CreateLogoutResponseUrlOptions, cb: (error: any, response_url: string) => void): void; + create_metadata(): string; + } + export interface ServiceProviderOptions { + entity_id: string; + private_key: string; + certificate: string; + assert_endpoint: string; + alt_private_keys?: string[]; + alt_certs?: string[]; + force_authn?: boolean; + auth_context?: AuthnContextClassRef; + nameid_format?: string; + sign_get_request?: boolean; + allow_unencrypted_assertion?: boolean; + } + export interface CreateLoginRequestUrlOptions { + relay_state?: string; + auth_context?: AuthnContextClassRef; + nameid_format?: string; + force_authn?: boolean; + sign_get_request?: boolean; + } + export interface GetAssertOptions { + request_body?: any; + allow_unencrypted_assertion?: boolean; + } + export interface CreateLogoutRequestUrlOptions { + name_id?: string; + session_index?: string; + allow_unencrypted_assertion?: boolean; + sign_get_request?: boolean; + relay_state?: string; + } + export interface CreateLogoutResponseUrlOptions { + in_response_to?: string; + sign_get_request?: boolean; + relay_state?: string; + } + + + export interface AuthnContextClassRef { + comparison: string; + class_refs: string[]; + } + +}