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