From df6d0625f19f37711b646d05527c77c78e0d9016 Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Thu, 21 Nov 2019 07:42:45 -0500 Subject: [PATCH] Merge pull request #2368 from overleaf/ew-ukamf-metadata-processor-cli ukamf metadata processor cli GitOrigin-RevId: f823a1dca231546f3ab67c47f6443e56b50e30d1 --- .../web/scripts/ukamf/metadata-processor.js | 42 +++++++++++++++++ services/web/scripts/ukamf/ukamf-db.js | 31 +++++++++++++ services/web/scripts/ukamf/ukamf-entity.js | 45 +++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 services/web/scripts/ukamf/metadata-processor.js create mode 100644 services/web/scripts/ukamf/ukamf-db.js create mode 100644 services/web/scripts/ukamf/ukamf-entity.js diff --git a/services/web/scripts/ukamf/metadata-processor.js b/services/web/scripts/ukamf/metadata-processor.js new file mode 100644 index 0000000000..f657a66be3 --- /dev/null +++ b/services/web/scripts/ukamf/metadata-processor.js @@ -0,0 +1,42 @@ +'use strict' + +/** + * Run with: node metadata-processor /path/ukamf.xml http://idp/entity/id + * + * The ukamf metadata xml file can be downloaded from: + * http://metadata.ukfederation.org.uk/ + * + * The entity id should be provided by the university. + */ + +const UKAMFDB = require('./ukamf-db') + +main().catch(err => { + console.error(err.stack) +}) + +async function main() { + const [, , file, entityId] = process.argv + + console.log(`loading file ${file}`) + + const ukamfDB = new UKAMFDB(file) + await ukamfDB.init() + + const entity = ukamfDB.findByEntityID(entityId) + if (!entity) { + throw new Error(`could not find entity for ${entityId}`) + } + const samlConfig = entity.getSamlConfig() + + console.log(`UPDATE universities SET + sso_entity_id = '${entityId}', + sso_entry_point = '${samlConfig.entryPoint}', + sso_cert = '${samlConfig.cert}', + sso_user_id_attribute = 'eduPersonPrincipalName', + sso_user_email_attribute = 'mail', + sso_license_entitlement_attribute = 'eduPersonPrincipalName', + sso_license_entitlement_matcher = '.' + WHERE id = + `) +} diff --git a/services/web/scripts/ukamf/ukamf-db.js b/services/web/scripts/ukamf/ukamf-db.js new file mode 100644 index 0000000000..bfca7b1e47 --- /dev/null +++ b/services/web/scripts/ukamf/ukamf-db.js @@ -0,0 +1,31 @@ +'use strict' + +const fs = require('fs-extra') +const xml2js = require('xml2js') + +const UKAMFEntity = require('./ukamf-entity') + +class UKAMFDB { + constructor(file) { + this.file = file + } + + async init() { + const data = await fs.readFile(this.file, 'utf8') + const parser = new xml2js.Parser() + const xml = await parser.parseStringPromise(data) + + this.entities = xml.EntitiesDescriptor.EntityDescriptor + } + + findByEntityID(matcher) { + const entity = this.entities.find( + matcher instanceof RegExp + ? e => e.$.entityID.match(matcher) + : e => e.$.entityID === matcher + ) + return entity ? new UKAMFEntity(entity) : null + } +} + +module.exports = UKAMFDB diff --git a/services/web/scripts/ukamf/ukamf-entity.js b/services/web/scripts/ukamf/ukamf-entity.js new file mode 100644 index 0000000000..6a8f8a133f --- /dev/null +++ b/services/web/scripts/ukamf/ukamf-entity.js @@ -0,0 +1,45 @@ +'use strict' + +const _ = require('lodash') + +class UKAMFEntity { + constructor(data) { + this.data = data + } + + getSamlConfig() { + const idp = this.data.IDPSSODescriptor[0] + const keys = idp.KeyDescriptor + const signingKey = keys.find(key => _.get(key, ['$', 'use']) === 'signing') + + let cert = _.get(signingKey, [ + 'ds:KeyInfo', + 0, + 'ds:X509Data', + 0, + 'ds:X509Certificate', + 0 + ]) + if (!cert) { + throw new Error('no cert') + } + cert = cert.replace(/\s/g, '') + + let entryPoint = idp.SingleSignOnService.find( + sso => + _.get(sso, ['$', 'Binding']) === + 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect' + ) + entryPoint = _.get(entryPoint, ['$', 'Location']) + if (!entryPoint) { + throw new Error('no entryPoint') + } + + return { + cert, + entryPoint + } + } +} + +module.exports = UKAMFEntity