|
@@ -0,0 +1,109 @@
|
|
|
|
|
+'use strict'
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * Checks that all institutional sso provider certs are still current with the
|
|
|
|
|
+ * data provided by the ukamf export file.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Run with: node check-certs /path/ukamf.xml
|
|
|
|
|
+ *
|
|
|
|
|
+ * The ukamf metadata xml file can be downloaded from:
|
|
|
|
|
+ * http://metadata.ukfederation.org.uk/
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+const { Certificate } = require('@fidm/x509')
|
|
|
|
|
+const UKAMFDB = require('./ukamf-db')
|
|
|
|
|
+const V1Api = require(`../../app/src/Features/V1/V1Api`).promises
|
|
|
|
|
+const { db } = require('../../app/src/infrastructure/mongojs')
|
|
|
|
|
+const moment = require('moment')
|
|
|
|
|
+
|
|
|
|
|
+main()
|
|
|
|
|
+ .catch(err => {
|
|
|
|
|
+ console.error(err.stack)
|
|
|
|
|
+ })
|
|
|
|
|
+ .then(() => process.exit())
|
|
|
|
|
+
|
|
|
|
|
+async function main() {
|
|
|
|
|
+ const [, , file] = process.argv
|
|
|
|
|
+
|
|
|
|
|
+ console.log(`loading file ${file}`)
|
|
|
|
|
+
|
|
|
|
|
+ const ukamfDB = new UKAMFDB(file)
|
|
|
|
|
+ await ukamfDB.init()
|
|
|
|
|
+
|
|
|
|
|
+ const activeProviderIds = await getActiveProviderIds()
|
|
|
|
|
+
|
|
|
|
|
+ for (const providerId of activeProviderIds) {
|
|
|
|
|
+ await checkCert(ukamfDB, providerId)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+async function checkCert(ukamfDB, providerId) {
|
|
|
|
|
+ console.log(`Checking certificates for providerId: ${providerId}`)
|
|
|
|
|
+ try {
|
|
|
|
|
+ const { body } = await V1Api.request({
|
|
|
|
|
+ json: true,
|
|
|
|
|
+ qs: { university_id: providerId },
|
|
|
|
|
+ uri: '/api/v1/sharelatex/university_saml'
|
|
|
|
|
+ })
|
|
|
|
|
+ // show notice if sso not currently enabled
|
|
|
|
|
+ if (body.sso_enabled === true) {
|
|
|
|
|
+ console.log(` * SSO enabled`)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ console.log(` ! SSO NOT enabled`)
|
|
|
|
|
+ }
|
|
|
|
|
+ // lookup entity id in ukamf database
|
|
|
|
|
+ const entity = ukamfDB.findByEntityID(body.sso_entity_id)
|
|
|
|
|
+ // if entity found then compare certs
|
|
|
|
|
+ if (entity) {
|
|
|
|
|
+ const samlConfig = entity.getSamlConfig()
|
|
|
|
|
+ // check if certificates match
|
|
|
|
|
+ if (samlConfig.cert === body.sso_cert) {
|
|
|
|
|
+ console.log(' * UKAMF certificate matches configuration')
|
|
|
|
|
+ } else {
|
|
|
|
|
+ console.log(' ! UKAMF certificate DOES NOT match configuration')
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ console.log(` ! No UKAMF entity found for ${body.sso_entity_id}`)
|
|
|
|
|
+ }
|
|
|
|
|
+ // check expiration on configured certificate
|
|
|
|
|
+ const certificate = Certificate.fromPEM(
|
|
|
|
|
+ Buffer.from(
|
|
|
|
|
+ `-----BEGIN CERTIFICATE-----\n${
|
|
|
|
|
+ body.sso_cert
|
|
|
|
|
+ }\n-----END CERTIFICATE-----`,
|
|
|
|
|
+ 'utf8'
|
|
|
|
|
+ )
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ const validFrom = moment(certificate.validFrom)
|
|
|
|
|
+ const validTo = moment(certificate.validTo)
|
|
|
|
|
+
|
|
|
|
|
+ if (validFrom.isAfter(moment())) {
|
|
|
|
|
+ console.log(` ! Certificate not valid till: ${validFrom.format('LLL')}`)
|
|
|
|
|
+ } else if (validTo.isBefore(moment())) {
|
|
|
|
|
+ console.log(` ! Certificate expired: ${validTo.format('LLL')}`)
|
|
|
|
|
+ } else if (validTo.isBefore(moment().add(60, 'days'))) {
|
|
|
|
|
+ console.log(` ! Certificate expires: ${validTo.format('LLL')}`)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ console.log(` * Certificate expires: ${validTo.format('LLL')}`)
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ console.log(` ! ${err.statusCode} Error getting university config from v1`)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+async function getActiveProviderIds() {
|
|
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
|
|
+ db.users.distinct(
|
|
|
|
|
+ 'samlIdentifiers.providerId',
|
|
|
|
|
+ { 'samlIdentifiers.externalUserId': { $exists: true } },
|
|
|
|
|
+ (err, providerIds) => {
|
|
|
|
|
+ if (err) {
|
|
|
|
|
+ reject(err)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ resolve(providerIds)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ )
|
|
|
|
|
+ })
|
|
|
|
|
+}
|