scimgateway 4.1.12 → 4.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -49,7 +49,7 @@ SCIM Gateway becomes a standalone SCIM endpoint
49
49
  Demonstrates user provisioning towards document-oriented database
50
50
  Using [LokiJS](https://github.com/techfort/LokiJS) for a fast, in-memory document-oriented database (much like MongoDB/PouchDB)
51
51
  Default gives two predefined test users loaded using in-memory only (no persistence)
52
- Setting `{"persistence": true}` gives persistence file store (no test users)
52
+ Configuration `{"persistence": true}` gives persistence file store (no test users)
53
53
  Example of a fully functional SCIM Gateway plugin
54
54
 
55
55
  * **MongoDB** (NoSQL Document-Oriented Database)
@@ -1146,6 +1146,12 @@ MIT © [Jarle Elshaug](https://www.elshaug.xyz)
1146
1146
 
1147
1147
  ## Change log
1148
1148
 
1149
+ ### v4.1.14
1150
+
1151
+ [Fixed]
1152
+
1153
+ - Do not create logs directory or log-file when configuration `log.loglevel.file` not defined or set to `"off"`. This fix will allow SCIM Gateway to run on systems having read-only disk like Google Cloud App Engine Standard
1154
+
1149
1155
  ### v4.1.12
1150
1156
 
1151
1157
  [Added]
package/lib/logger.js CHANGED
@@ -44,12 +44,12 @@ const Log = function (config, logfile, _this) { // { loglevel: { file: "debug",
44
44
 
45
45
  const maskSecret = winston.format((info, opts) => {
46
46
  // mask json secrets
47
- var rePattern = new RegExp(reJson, 'i')
47
+ let rePattern = new RegExp(reJson, 'i')
48
48
  let msg = info.message
49
49
  let endPos = msg.length - 1
50
50
  let found = false
51
51
  do {
52
- var arrMatches = msg.substring(0, endPos).match(rePattern)
52
+ const arrMatches = msg.substring(0, endPos).match(rePattern)
53
53
  if (Array.isArray(arrMatches) && arrMatches.length === 3) {
54
54
  arrMatches[2] = arrMatches[2].replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') // escaping special regexp characters
55
55
  msg = msg.replace(new RegExp(arrMatches[2], 'g'), '********')
@@ -62,7 +62,7 @@ const Log = function (config, logfile, _this) { // { loglevel: { file: "debug",
62
62
  rePattern = new RegExp(reXml, 'i')
63
63
  endPos = msg.length - 1
64
64
  do {
65
- arrMatches = msg.substring(0, endPos).match(rePattern)
65
+ const arrMatches = msg.substring(0, endPos).match(rePattern)
66
66
  if (Array.isArray(arrMatches) && arrMatches.length === 3) {
67
67
  arrMatches[2] = arrMatches[2].replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
68
68
  msg = msg.replace(new RegExp('>' + arrMatches[2] + '<', 'g'), '>********<')
@@ -98,38 +98,48 @@ const Log = function (config, logfile, _this) { // { loglevel: { file: "debug",
98
98
  )
99
99
  }
100
100
 
101
- Log.prototype.logger = winston.createLogger({
102
- format: winston.format.combine(
103
- maskSecret()
104
- ),
105
- transports: [
106
- new winston.transports.File({
107
- level: (config.loglevel.file && arrValidLevel.includes(config.loglevel.file.toLowerCase())) ? config.loglevel.file : 'debug',
108
- filename: logfile,
109
- handleExceptions: true,
110
- format: fileFormat,
111
- maxsize: 1024 * 1024 * 20, // 20 MB
112
- maxFiles: 5
113
- }),
114
- new winston.transports.Console({ // note, console logging is synchronous e.g. node.js halts when console window is scrolled
115
- level: (config.loglevel.console && arrValidLevel.includes(config.loglevel.console.toLowerCase())) ? config.loglevel.console : 'debug',
116
- handleExceptions: true,
117
- stderrLevels: ['error'],
118
- format: (config.colorize) ? consoleFormat : Log.prototype.unColorize()
101
+ Log.prototype.logger = () => {
102
+ if (config.loglevel.file) {
103
+ return winston.createLogger({
104
+ format: winston.format.combine(
105
+ maskSecret()
106
+ ),
107
+ transports: [
108
+ new winston.transports.Console({ // note, console logging is synchronous e.g. node.js halts when console window is scrolled
109
+ level: (config.loglevel.console && arrValidLevel.includes(config.loglevel.console.toLowerCase())) ? config.loglevel.console : 'debug',
110
+ handleExceptions: true,
111
+ stderrLevels: ['error'],
112
+ format: (config.colorize) ? consoleFormat : Log.prototype.unColorize()
113
+ }),
114
+ new winston.transports.File({
115
+ level: (config.loglevel.file && arrValidLevel.includes(config.loglevel.file.toLowerCase())) ? config.loglevel.file : 'debug',
116
+ filename: logfile,
117
+ handleExceptions: true,
118
+ format: fileFormat,
119
+ maxsize: 1024 * 1024 * 20, // 20 MB
120
+ maxFiles: 5
121
+ })
122
+ ],
123
+ exitOnError: false
119
124
  })
120
- ],
121
- exitOnError: false
122
- })
123
-
124
- // flush to disk before exit (process.exit in main code will terminate logger and we may have unflushed logfile updates)
125
- // note, still asynchronous (using exception is an alternative that gives synchronous flush and program exit)
126
- Log.prototype.exitAfterFlush = (code) => {
127
- Log.prototype.logger.transports[0].on('flush', function () {
128
- process.exit(code)
125
+ }
126
+ return winston.createLogger({
127
+ format: winston.format.combine(
128
+ maskSecret()
129
+ ),
130
+ transports: [
131
+ new winston.transports.Console({
132
+ level: (config.loglevel.console && arrValidLevel.includes(config.loglevel.console.toLowerCase())) ? config.loglevel.console : 'debug',
133
+ handleExceptions: true,
134
+ stderrLevels: ['error'],
135
+ format: (config.colorize) ? consoleFormat : Log.prototype.unColorize()
136
+ })
137
+ ],
138
+ exitOnError: false
129
139
  })
130
140
  }
131
141
 
132
- const logger = Log.prototype.logger // fix multiple loggers using stream
142
+ const logger = Log.prototype.logger() // fix multiple loggers using stream
133
143
  Log.prototype.stream = {
134
144
  write: function (message, encoding) {
135
145
  logger.info(message)
@@ -46,8 +46,8 @@ const ScimGateway = function () {
46
46
  const gwName = path.basename(__filename, '.js') // prefix of current file
47
47
  const logDir = path.join(path.dirname(requester), '..', 'logs')
48
48
  const Log = require('../lib/logger').Log
49
- const log = new Log(utils.extendObj(utils.copyObj(config.log), { category: pluginName, colorize: process.stdout.isTTY || false, loglevel: { file: 'debug', console: 'debug' } }), path.join(`${logDir}`, `${pluginName}.log`))
50
- const logger = log.logger
49
+ const log = new Log(utils.extendObj(utils.copyObj(config.log), { category: pluginName, colorize: process.stdout.isTTY || false, loglevel: { file: (!config.log.loglevel.file || config.log.loglevel.file === 'off') ? null : 'debug', console: 'debug' } }), path.join(`${logDir}`, `${pluginName}.log`))
50
+ const logger = log.logger()
51
51
  this.logger = logger // exposed to plugin-code
52
52
  this.notValidAttributes = notValidAttributes // exposed to plugin-code
53
53
  let pwErrCount = 0
@@ -228,10 +228,12 @@ const ScimGateway = function () {
228
228
  logger.error(`${gwName}[${pluginName}] stopping...\n`)
229
229
  throw (new Error('Using exception to stop further asynchronous code execution (ensure synchronous logger flush to logfile and exit program), please ignore this one...'))
230
230
  }
231
- if (!fs.existsSync(logDir)) fs.mkdirSync(logDir)
232
- if (!fs.existsSync(configDir + '/wsdls')) fs.mkdirSync(configDir + '/wsdls')
233
- if (!fs.existsSync(configDir + '/certs')) fs.mkdirSync(configDir + '/certs')
234
- if (!fs.existsSync(configDir + '/schemas')) fs.mkdirSync(configDir + '/schemas')
231
+
232
+ try {
233
+ if (!fs.existsSync(configDir + '/wsdls')) fs.mkdirSync(configDir + '/wsdls')
234
+ if (!fs.existsSync(configDir + '/certs')) fs.mkdirSync(configDir + '/certs')
235
+ if (!fs.existsSync(configDir + '/schemas')) fs.mkdirSync(configDir + '/schemas')
236
+ } catch (err) {}
235
237
 
236
238
  let isScimv2 = false
237
239
  if (config.scim.version === '2.0' || config.scim.version === 2) {
@@ -317,7 +319,7 @@ const ScimGateway = function () {
317
319
  // start auth methods - used by auth
318
320
  const basic = (baseEntity, method, authType, authToken, url) => {
319
321
  return new Promise((resolve, reject) => { // basic auth
320
- if (url === '/ping' || url.endsWith('/oauth/token') || url === '/favicon.ico') resolve(true) // no auth
322
+ if (url === '/ping' || url.endsWith('/oauth/token') || url === '/_ah/start' || url === '/_ah/stop' || url === '/favicon.ico') resolve(true) // no auth
321
323
  if (authType !== 'Basic') resolve(false)
322
324
  if (!foundBasic) resolve(false) // not configured
323
325
  const [userName, userPassword] = (Buffer.from(authToken, 'base64').toString() || '').split(':')
@@ -597,6 +599,18 @@ const ScimGateway = function () {
597
599
  ctx.body = tx
598
600
  })
599
601
 
602
+ // Google App Engine B-class instance start/stop request
603
+ router.get(['/_ah/start', '/_ah/stop'], async (ctx) => {
604
+ const cli = ctx.request.ipcli
605
+ const ver = process.env.GAE_VERSION
606
+ if (!cli || cli !== '0.1.0.3' || !ver || !ctx.origin.includes(`.${ver}.`)) { // ctx.origin = http://<instance>.<version>.<project-id>.<region>.r.appspot.com
607
+ ctx.status = 403 // request not coming from GCP App Engine
608
+ return
609
+ }
610
+ // could have some start/stop logic here
611
+ ctx.status = 200
612
+ })
613
+
600
614
  // Initial connection, step #1: GET /ServiceProviderConfigs
601
615
  // If not included => Provisioning will always use GET /Users without any paramenters
602
616
  // scimv1 = ServiceProviderConfigs, scimv2 ServiceProviderConfig
@@ -1785,11 +1799,11 @@ const ScimGateway = function () {
1785
1799
  logger.close()
1786
1800
  server.close(function () {
1787
1801
  setTimeout(function () { // plugins may also use SIGTERM/SIGINT
1788
- process.exit(1)
1802
+ process.exit(0)
1789
1803
  }, 0.5 * 1000)
1790
1804
  })
1791
1805
  setTimeout(function () { // problem closing server connections in time due to keep-alive sessions (active browser connection?), now forcing exit
1792
- process.exit(2)
1806
+ process.exit(1)
1793
1807
  }, 2 * 1000)
1794
1808
  }
1795
1809
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scimgateway",
3
- "version": "4.1.12",
3
+ "version": "4.1.14",
4
4
  "description": "Using SCIM protocol as a gateway for user provisioning to other endpoints",
5
5
  "author": "Jarle Elshaug <jarle.elshaug@gmail.com> (https://elshaug.xyz)",
6
6
  "homepage": "https://elshaug.xyz",