Skip to content

Commit

Permalink
#337 Expose configuration for setting clock drift (#340)
Browse files Browse the repository at this point in the history
  • Loading branch information
tngan committed Jan 28, 2020
1 parent 16ded23 commit dd35ad3
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 227 deletions.
53 changes: 0 additions & 53 deletions docs/helpers.md

This file was deleted.

24 changes: 24 additions & 0 deletions docs/sp-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,27 @@ const sp = new ServiceProvider({

- **generateID: (): String**<br/>
A function to generate the document identifier in root node. Default to `_${UUID_V4}`.

- **clockDrifts: [Number, Number]**<br/>
A time range allowing for drifting the range that specified in the SAML document. The first one is for the `notBefore` time and the second one is for `notOnOrAfter`. Default value of both drift value is `0`. The unit is in `ms`.

For example, if you set `[-5000, 3000]`. The value can be either positive or negative in order to take care of the flexibility.

```console
# tolerated timeline
notBefore - 5s >>>>>>> notBefore >>>>>>> notAfter ---- notAfter + 3s

# new valid time
notBefore - 5s >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> notAfter + 3s
```

Another example, if you don't set, the default drift tolerance is `[0, 0]`. The valid range is trivial.

```console
# valid time
notBefore >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> notAfter
```

?> The flow will skip the validation when there is no `notBefore` and `notOnOrAfter` at the same time.

?> See [SAML Core P.19](https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf) for more detail.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"ava": "^1.2.1",
"coveralls": "^3.0.2",
"nyc": "^11.9.0",
"timekeeper": "^2.2.0",
"ts-node": "^8.3.0",
"tslint": "^5.12.1",
"typescript": "^3.4.5"
Expand Down
6 changes: 4 additions & 2 deletions src/flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,8 @@ async function postFlow(options): Promise<FlowResult> {
parserType === 'SAMLResponse'
&& !verifyTime(
undefined,
extractedProperties.sessionIndex.sessionNotOnOrAfter
extractedProperties.sessionIndex.sessionNotOnOrAfter,
self.entitySetting.clockDrifts
)
) {
return Promise.reject('ERR_EXPIRED_SESSION');
Expand All @@ -225,7 +226,8 @@ async function postFlow(options): Promise<FlowResult> {
&& extractedProperties.conditions
&& !verifyTime(
extractedProperties.conditions.notBefore,
extractedProperties.conditions.notOnOrAfter
extractedProperties.conditions.notOnOrAfter,
self.entitySetting.clockDrifts
)
) {
return Promise.reject('ERR_SUBJECT_UNCONFIRMED');
Expand Down
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ export type ServiceProviderSettings = {
nameIDFormat?: string[];
// will be deprecated soon
relayState?: string;
// https://github.com/tngan/samlify/issues/337
clockDrifts?: [number, number];
};

export type IdentityProviderSettings = {
Expand Down
48 changes: 48 additions & 0 deletions test/flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { PostBindingContext } from '../src/entity';
import * as uuid from 'uuid';
import * as url from 'url';
import util from '../src/utility';
import * as tk from 'timekeeper';

import * as validator from '@authenio/samlify-xsd-schema-validator';
// import * as validator from '@authenio/samlify-validate-with-xmllint';
Expand Down Expand Up @@ -125,6 +126,7 @@ const spNoAssertSignCustomConfig = serviceProvider({ ...defaultSpConfig,
location: { reference: "/*[local-name(.)='Response']/*[local-name(.)='Issuer']", action: 'after' },
},
});
const spWithClockDrift = serviceProvider({ ...defaultSpConfig, clockDrifts: [-2000, 2000] });

function writer(str) {
writeFileSync('test.txt', str);
Expand Down Expand Up @@ -672,4 +674,50 @@ test('should throw two-tiers code error when the response does not return succes
} catch (e) {
t.is(e.message, 'ERR_FAILED_STATUS with top tier code: urn:oasis:names:tc:SAML:2.0:status:Requester, second tier code: urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy');
}
});

test.serial('should throw ERR_SUBJECT_UNCONFIRMED for the expired SAML response without clock drift setup', async t => {

const now = new Date();
const fiveMinutesOneSecLater = new Date(now.getTime());
fiveMinutesOneSecLater.setMinutes(fiveMinutesOneSecLater.getMinutes() + 5);
fiveMinutesOneSecLater.setSeconds(fiveMinutesOneSecLater.getSeconds() + 1);

const user = { email: '[email protected]' };

try {
const { context: SAMLResponse } = await idp.createLoginResponse(sp, sampleRequestInfo, 'post', user, createTemplateCallback(idp, sp, user));
// simulate the time on client side when response arrives after 5.1 sec
tk.freeze(fiveMinutesOneSecLater);
await sp.parseLoginResponse(idp, 'post', { body: { SAMLResponse } });
// test failed, it shouldn't happen
t.is(true, false);
} catch (e) {
t.is(e, 'ERR_SUBJECT_UNCONFIRMED');
} finally {
tk.reset();
}
});

test.serial('should not throw ERR_SUBJECT_UNCONFIRMED for the expired SAML response with clock drift setup', async t => {

const now = new Date();
const fiveMinutesOneSecLater = new Date(now.getTime());
fiveMinutesOneSecLater.setMinutes(fiveMinutesOneSecLater.getMinutes() + 5);
fiveMinutesOneSecLater.setSeconds(fiveMinutesOneSecLater.getSeconds() + 1);
const user = { email: '[email protected]' };

try {
const { context: SAMLResponse } = await idp.createLoginResponse(spWithClockDrift, sampleRequestInfo, 'post', user, createTemplateCallback(idp, spWithClockDrift, user));
// simulate the time on client side when response arrives after 5.1 sec
tk.freeze(fiveMinutesOneSecLater);
await spWithClockDrift.parseLoginResponse(idp, 'post', { body: { SAMLResponse } });
t.is(true, true);
} catch (e) {
// test failed, it shouldn't happen
t.is(e, false);
} finally {
tk.reset();
}

});
Loading

0 comments on commit dd35ad3

Please sign in to comment.