UNPKG

keycloak-connect

Version:
97 lines (88 loc) 2.96 kB
/*! * Copyright 2014 Red Hat, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 'use strict' const URL = require('url') const http = require('http') const https = require('https') const jwkToPem = require('jwk-to-pem') /** * Construct a Rotation instance * * @param {Config} config Config object. * * @constructor */ function Rotation (config) { this.realmUrl = config.realmUrl this.minTimeBetweenJwksRequests = config.minTimeBetweenJwksRequests this.jwks = [] this.lastTimeRequesTime = 0 } Rotation.prototype.retrieveJWKs = function retrieveJWKs (callback) { const url = this.realmUrl + '/protocol/openid-connect/certs' const options = URL.parse(url); // eslint-disable-line options.method = 'GET' const promise = new Promise((resolve, reject) => { const req = getProtocol(options).request(options, (response) => { if (response.statusCode < 200 || response.statusCode >= 300) { return reject(new Error('Error fetching JWK Keys')) } let json = '' response.on('data', (d) => (json += d.toString())) response.on('end', () => { const data = JSON.parse(json) if (data.error) reject(data) else resolve(data) }) }) req.on('error', reject) req.end() }) return nodeify(promise, callback) } Rotation.prototype.getJWK = function getJWK (kid) { const key = this.jwks.find((key) => { return key.kid === kid }) if (key) { return new Promise((resolve, reject) => { resolve(jwkToPem(key)) }) } const self = this // check if we are allowed to send request const currentTime = new Date().getTime() / 1000 if (currentTime > this.lastTimeRequesTime + this.minTimeBetweenJwksRequests) { return this.retrieveJWKs() .then(publicKeys => { self.lastTimeRequesTime = currentTime self.jwks = publicKeys.keys const convertedKey = jwkToPem(self.jwks.find((key) => { return key.kid === kid })) return convertedKey }) } else { console.error('Not enough time elapsed since the last request, blocking the request') } } Rotation.prototype.clearCache = function clearCache () { this.jwks.length = 0 } const getProtocol = (opts) => { return opts.protocol === 'https:' ? https : http } const nodeify = (promise, cb) => { if (typeof cb !== 'function') return promise return promise.then((res) => cb(null, res)).catch((err) => cb(err)) } module.exports = Rotation