1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
(function(global) {
'use strict';
// rather than create a million different IdP configurations and litter the
// world with files all containing near-identical code, let's use the hash/URL
// fragment as a way of generating instructions for the IdP
var instructions = global.location.hash.replace('#', '').split(':');
function is(target) {
return function(instruction) {
return instruction === target;
};
}
function IDPJS() {
this.domain = global.location.host;
var path = global.location.pathname;
this.protocol =
path.substring(path.lastIndexOf('/') + 1) + global.location.hash;
this.id = crypto.getRandomValues(new Uint8Array(10)).join('.');
}
IDPJS.prototype = {
getLogin: function() {
return fetch('https://example.com/.well-known/idp-proxy/idp.sjs?' + this.id)
.then(response => response.status === 200);
},
checkLogin: function(result) {
return this.getLogin()
.then(loggedIn => {
if (loggedIn) {
return result;
}
return Promise.reject({
name: 'IdpLoginError',
loginUrl: 'https://example.com/.well-known/idp-proxy/login.html#' +
this.id
});
});
},
borkResult: function(result) {
if (instructions.some(is('throw'))) {
throw new Error('Throwing!');
}
if (instructions.some(is('fail'))) {
return Promise.reject(new Error('Failing!'));
}
if (instructions.some(is('login'))) {
return this.checkLogin(result);
}
if (instructions.some(is('hang'))) {
return new Promise(r => {});
}
dump('idp: result=' + JSON.stringify(result) + '\n');
return Promise.resolve(result);
},
_selectUsername: function(usernameHint) {
var username = 'someone@' + this.domain;
if (usernameHint) {
var at = usernameHint.indexOf('@');
if (at < 0) {
username = usernameHint + '@' + this.domain;
} else if (usernameHint.substring(at + 1) === this.domain) {
username = usernameHint;
}
}
return username;
},
generateAssertion: function(payload, origin, usernameHint) {
dump('idp: generateAssertion(' + payload + ')\n');
var idpDetails = {
domain: this.domain,
protocol: this.protocol
};
if (instructions.some(is('bad-assert'))) {
idpDetails = {};
}
return this.borkResult({
idp: idpDetails,
assertion: JSON.stringify({
username: this._selectUsername(usernameHint),
contents: payload
})
});
},
validateAssertion: function(assertion, origin) {
dump('idp: validateAssertion(' + assertion + ')\n');
var assertion = JSON.parse(assertion);
if (instructions.some(is('bad-validate'))) {
assertion.contents = {};
}
return this.borkResult({
identity: assertion.username,
contents: assertion.contents
});
}
};
if (!instructions.some(is('not_ready'))) {
dump('registering idp.js' + global.location.hash + '\n');
var idp = new IDPJS();
global.rtcIdentityProvider.register({
generateAssertion: idp.generateAssertion.bind(idp),
validateAssertion: idp.validateAssertion.bind(idp)
});
}
}(this));
|