Skip to content

Commit 7004bee

Browse files
authored
Pluggable installation of preferences of schema validator (tngan#236)
* Pluggable installation of preferences of schema validator * POC of dynamic import module * Fix npm script for validator installation and integration of javac validator * Integration of libxmljs validator * Add back instruction in README for windows user using libxml as the schema validator * Make the travis test workflow with javac schema validator
1 parent f91fde4 commit 7004bee

File tree

9 files changed

+157
-50
lines changed

9 files changed

+157
-50
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,6 @@ types/
3131
#vscode
3232
.vscode
3333

34-
*.tgz
34+
*.tgz
35+
36+
package-lock.json

.travis.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ before_install:
1010
- sudo add-apt-repository ppa:openjdk-r/ppa -y
1111
- sudo apt-get -qq update
1212
- sudo apt-get install -y openjdk-9-jdk
13+
- export SAML_VALIDATOR=javac
1314

1415
script:
1516
- npm test
@@ -19,7 +20,5 @@ branches:
1920
- master
2021
- /^.*-alpha$/
2122
- /^.*-beta$/
22-
- /^.*-rc*$/
23-
- /^.*-exp*$/
2423

2524
after_success: npm run coverage

Makefile

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,23 @@ pretest: ;
1616
cp -a schemas build; \
1717
cp -a test/key test/misc build/test;
1818

19+
validator: ;
20+
ifeq ($(SAML_VALIDATOR), javac)
21+
@echo "Installing java xsd schema validator ...";
22+
# for java runtime support library
23+
# need to run with npm install, yarn add --ignore-scripts will ignore the postinstall script
24+
# check more information in the package.json of @passify/xsd-schema-validator
25+
npm install @passify/xsd-schema-validator;
26+
27+
else ifeq ($(SAML_VALIDATOR), libxml)
28+
@echo "Installing libxml-xsd ...";
29+
npm install libxml-xsd
30+
31+
else
32+
@echo "No valid SAML_VALIDATOR is chosen";
33+
endif
34+
1935
doc: ;@echo "prepare and serve the docs"; \
2036
docsify serve ./docs
2137

22-
.PHONY: rebuild pretest doc
38+
.PHONY: rebuild pretest doc validator

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,16 @@ Welcome all PRs for maintaining this project, or provide a link to the repositor
1414
### Installation
1515
To install the stable version
1616

17+
Starting from v2.5, schema validation becomes selectable and optional, we restrict to apply it in your production environment, you can only ignore schema validation in development mode. When you install samlify in your current project, please assign the environment variable `SAML_VALIDATOR` to either `javac` or `libxml`.
18+
19+
```console
20+
$ SAML_VALIDATOR=javac yarn add samlify
21+
```
22+
23+
For those using Windows, `windows-build-tools` should be installed globally before installing samlify if you are using `libxml` validator.
24+
1725
```console
18-
$ yarn add samlify
26+
$ yarn global add windows-build-tools
1927
```
2028

2129
### Development

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"test": "npm run build && NODE_ENV=test nyc ava --verbose build/test",
2121
"test:pure": "NODE_ENV=test nyc ava --verbose build/test",
2222
"coverage": "nyc report --reporter=text-lcov | coveralls",
23+
"preinstall": "make validator",
2324
"hooks:postinstall": "ln -sf $PWD/.pre-commit.sh $PWD/.git/hooks/pre-commit"
2425
},
2526
"contributors": [
@@ -33,7 +34,6 @@
3334
"license": "MIT",
3435
"dependencies": {
3536
"@passify/xml-encryption": "^0.11.1",
36-
"@passify/xsd-schema-validator": "^0.7.1",
3737
"deflate-js": "^0.2.3",
3838
"lodash": "^4.17.10",
3939
"node-forge": "^0.7.5",

src/libsaml.ts

Lines changed: 8 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,8 @@ import { isObject, isUndefined, includes, flattenDeep, camelCase } from 'lodash'
1313
import * as nrsa from 'node-rsa';
1414
import { SignedXml, FileKeyInfo } from 'xml-crypto';
1515
import * as xmlenc from '@passify/xml-encryption';
16-
import * as path from 'path';
17-
import * as fs from 'fs';
18-
import * as Validator from '@passify/xsd-schema-validator';
1916
import { extract } from './extractor';
17+
import { getValidatorModule } from './schema-validator';
2018

2119
const signatureAlgorithms = algorithms.signature;
2220
const digestAlgorithms = algorithms.digest;
@@ -102,29 +100,6 @@ export interface LibSamlInterface {
102100
}
103101

104102
const libSaml = () => {
105-
const validator = new Validator();
106-
function setSchemaDir() {
107-
let schemaDir;
108-
try {
109-
schemaDir = path.resolve(__dirname, '../schemas');
110-
fs.accessSync(schemaDir, fs.constants.F_OK);
111-
} catch (err) {
112-
// for built-from git folder layout
113-
try {
114-
schemaDir = path.resolve(__dirname, '../../schemas');
115-
fs.accessSync(schemaDir, fs.constants.F_OK);
116-
} catch (err) {
117-
//console.warn('Unable to specify schema directory', err);
118-
// QUESTION should this be swallowed?
119-
console.error(err);
120-
throw new Error('ERR_FAILED_FETCH_SCHEMA_FILE');
121-
}
122-
}
123-
// set schema directory
124-
validator.cwd = schemaDir;
125-
validator.debug = process.env.NODE_ENV === 'test';
126-
}
127-
setSchemaDir();
128103

129104
/**
130105
* @desc helper function to get back the query param for redirect binding for SLO/SSO
@@ -623,18 +598,13 @@ const libSaml = () => {
623598
* @desc Check if the xml string is valid and bounded
624599
*/
625600
async isValidXml(input: string) {
626-
return new Promise((resolve, reject) => {
627-
validator.validateXML(input, 'saml-schema-protocol-2.0.xsd', (err, result) => {
628-
if (err) {
629-
console.error(err);
630-
return reject('ERR_EXCEPTION_VALIDATE_SAML_RESPONSE');
631-
}
632-
if (result.valid) {
633-
return resolve(true);
634-
}
635-
return reject('ERR_INVALID_SAML_RESPONSE');
636-
});
637-
});
601+
try {
602+
const mod = await getValidatorModule();
603+
await mod.validate(input);
604+
return Promise.resolve();
605+
} catch (e) {
606+
throw e;
607+
}
638608
},
639609
};
640610
};

src/schema-validator.ts

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import * as fs from 'fs';
2+
import * as path from 'path';
3+
4+
enum SchemaValidators {
5+
JAVAC = '@passify/xsd-schema-validator',
6+
LIBXML = 'libxml-xsd'
7+
}
8+
9+
interface SchemaValidator {
10+
validate: (xml: string) => Promise<string>;
11+
}
12+
13+
type GetValidatorModuleSpec = () => Promise<SchemaValidator>;
14+
15+
const moduleResolver = (name: string) => {
16+
try {
17+
require.resolve(name);
18+
return name;
19+
} catch (e) {
20+
return null;
21+
}
22+
};
23+
24+
const getValidatorModule: GetValidatorModuleSpec = async () => {
25+
26+
const selectedValidator: string = moduleResolver(SchemaValidators.JAVAC) || moduleResolver(SchemaValidators.LIBXML);
27+
28+
const xsd = 'saml-schema-protocol-2.0.xsd';
29+
30+
if (selectedValidator === SchemaValidators.JAVAC) {
31+
32+
// TODO: refactor
33+
const setSchemaDir = (v: any) => {
34+
let schemaDir;
35+
try {
36+
schemaDir = path.resolve(__dirname, '../schemas');
37+
fs.accessSync(schemaDir, fs.constants.F_OK);
38+
} catch (err) {
39+
// for built-from git folder layout
40+
try {
41+
schemaDir = path.resolve(__dirname, '../../schemas');
42+
fs.accessSync(schemaDir, fs.constants.F_OK);
43+
} catch (err) {
44+
//console.warn('Unable to specify schema directory', err);
45+
// QUESTION should this be swallowed?
46+
console.error(err);
47+
throw new Error('ERR_FAILED_FETCH_SCHEMA_FILE');
48+
}
49+
}
50+
v.cwd = schemaDir;
51+
v.debug = process.env.NODE_ENV === 'test';
52+
return v;
53+
};
54+
55+
const validator = await import (SchemaValidators.JAVAC);
56+
const mod = setSchemaDir(new validator());
57+
58+
return {
59+
validate: (xml: string) => {
60+
return new Promise((resolve, reject) => {
61+
mod.validateXML(xml, xsd, (err, result) => {
62+
if (err) {
63+
console.error('[ERROR] validateXML', err);
64+
return reject('ERR_EXCEPTION_VALIDATE_XML');
65+
}
66+
if (result.valid) {
67+
return resolve('SUCCESS_VALIDATE_XML');
68+
}
69+
return reject('ERR_INVALID_XML');
70+
});
71+
});
72+
}
73+
};
74+
}
75+
76+
if (selectedValidator === SchemaValidators.LIBXML) {
77+
const mod = await import (SchemaValidators.LIBXML);
78+
return {
79+
validate: (xml: string) => {
80+
return new Promise((resolve, reject) => {
81+
// https://github.com/albanm/node-libxml-xsd/issues/11
82+
process.chdir(path.resolve(__dirname, '../schemas'));
83+
mod.parseFile(path.resolve(xsd), (err, schema) => {
84+
if (err) {
85+
console.error('[ERROR] validateXML', err);
86+
return reject('ERR_INVALID_XML');
87+
}
88+
schema.validate(xml, (techErrors, validationErrors) => {
89+
if (techErrors !== null || validationErrors !== null) {
90+
console.error(`this is not a valid saml response with errors: ${validationErrors}`);
91+
return reject('ERR_EXCEPTION_VALIDATE_XML');
92+
}
93+
return resolve('SUCCESS_VALIDATE_XML');
94+
});
95+
});
96+
});
97+
}
98+
};
99+
}
100+
101+
// allow to skip the validate function if it's in development or test mode if no schema validator is provided
102+
if (process.env.NODE_ENV === 'dev' || process.env.NODE_ENV === 'test') {
103+
return {
104+
validate: (_xml: string) => {
105+
return new Promise((resolve, _reject) => resolve('SKIP_XML_VALIDATION'));
106+
}
107+
};
108+
}
109+
110+
throw new Error('ERR_UNDEFINED_SCHEMA_VALIDATOR_MODULE');
111+
112+
};
113+
114+
export {
115+
getValidatorModule
116+
};

src/validator.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,5 @@ function verifyTime(utcNotBefore?: string, utcNotOnOrAfter?: string): boolean {
1919
}
2020

2121
export {
22-
verifyTime
23-
};
22+
verifyTime,
23+
};

yarn.lock

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,6 @@
4747
xmldom "~0.1.15"
4848
xpath "0.0.24"
4949

50-
"@passify/xsd-schema-validator@^0.7.1":
51-
version "0.7.1"
52-
resolved "https://registry.yarnpkg.com/@passify/xsd-schema-validator/-/xsd-schema-validator-0.7.1.tgz#19d4318320d0ae52ac74076761c9285f2bac00ee"
53-
5450
"@types/lodash@^4.14.112":
5551
version "4.14.116"
5652
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.116.tgz#5ccf215653e3e8c786a58390751033a9adca0eb9"

0 commit comments

Comments
 (0)