mock-idp.js (5094B)
1 'use strict'; 2 3 // Code is based on the following editor draft: 4 // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html 5 6 /* 7 mock-idp.js is a naive IdP that provides absolutely no 8 security for authentication. It can generate identity 9 assertion for whatever identity that is requested. 10 11 mock-idp.js validates identity assertion by simply decoding 12 the JSON and return whatever that is inside, with no integrity 13 protection and thus can be spoofed by anyone. 14 15 While being not practical at all, mock-idp.js allows us 16 to test various aspects of the identity API and allow tests 17 to manipulate the IdP at will. 18 */ 19 20 // We pass around test options as query string to instruct 21 // the test IdP proxy script on what actions to perform. 22 // This hack is based on the fact that query string is allowed 23 // when specifying the IdP protocol. 24 function parseQueryString(urlStr) { 25 const url = new URL(urlStr); 26 const result = {}; 27 for(const [key, value] of url.searchParams) { 28 result[key] = value; 29 } 30 return result; 31 } 32 33 /* 34 9.2.1. Interface Exposed by Identity Providers 35 callback GenerateAssertionCallback = 36 Promise<RTCIdentityAssertionResult> ( 37 DOMString contents, 38 DOMString origin, 39 RTCIdentityProviderOptions options); 40 41 dictionary RTCIdentityProviderOptions { 42 DOMString protocol = "default"; 43 DOMString usernameHint; 44 DOMString peerIdentity; 45 }; 46 47 dictionary RTCIdentityAssertionResult { 48 required RTCIdentityProviderDetails idp; 49 required DOMString assertion; 50 }; 51 52 dictionary RTCIdentityProviderDetails { 53 required DOMString domain; 54 DOMString protocol = "default"; 55 }; 56 */ 57 58 const query = parseQueryString(location); 59 60 // Generate a naive identity assertion. The result assertion 61 // is a JSON string that report the various parameters 62 // received by this function. 63 // watermark - a special mark to make sure the result is returned 64 // from this function 65 // args - the function arguments received 66 // env - some global variable values when this function is called 67 // query - the parsed query string of the script URL 68 function generateAssertion(contents, origin, options) { 69 const args = { 70 contents, origin, options 71 }; 72 73 const env = { 74 origin, 75 location 76 }; 77 78 const assertion = { 79 watermark: 'mock-idp.js.watermark', 80 args, 81 env, 82 query 83 }; 84 85 const assertionStr = JSON.stringify(assertion); 86 87 const { generatorAction } = query; 88 89 if(generatorAction === 'throw-error') { 90 const err = new Error('Mock Internal IdP Error'); 91 err.idpErrorInfo = query.errorInfo; 92 throw err; 93 94 } else if(generatorAction === 'require-login') { 95 const err = new RTCError('idp-need-login'); 96 err.idpLoginUrl = `${origin}/login`; 97 err.idpErrorInfo = 'login required'; 98 throw err; 99 100 } else if(generatorAction === 'return-custom-idp') { 101 const { domain, protocol } = query; 102 103 return { 104 idp: { 105 domain, 106 protocol 107 }, 108 assertion: assertionStr 109 }; 110 111 } else if(generatorAction === 'return-invalid-result') { 112 return 'invalid-result'; 113 114 } else { 115 return { 116 idp: { 117 domain: location.host, 118 protocol: 'mock-idp.js' 119 }, 120 assertion: assertionStr 121 }; 122 } 123 } 124 125 /* 126 9.2.1. Interface Exposed by Identity Providers 127 callback ValidateAssertionCallback = 128 Promise<RTCIdentityValidationResult> ( 129 DOMString assertion, 130 DOMString origin); 131 132 dictionary RTCIdentityValidationResult { 133 required DOMString identity; 134 required DOMString contents; 135 }; 136 */ 137 function validateAssertion(assertionStr, origin) { 138 const assertion = JSON.parse(assertionStr); 139 140 const { args, query } = assertion; 141 const { contents, options } = args; 142 143 const identity = options.usernameHint; 144 145 const { 146 validatorAction 147 } = query; 148 149 if(validatorAction === 'throw-error') { 150 const err = new Error('Mock Internal IdP Error'); 151 err.idpErrorInfo = query.errorInfo; 152 throw err; 153 154 } else if(validatorAction === 'return-custom-contents') { 155 const { contents } = query; 156 return { 157 identity, 158 contents 159 }; 160 161 } else { 162 return { 163 identity, contents 164 }; 165 } 166 } 167 168 /* 169 9.2. Registering an IdP Proxy 170 [Global, 171 Exposed=RTCIdentityProviderGlobalScope] 172 interface RTCIdentityProviderGlobalScope : WorkerGlobalScope { 173 readonly attribute RTCIdentityProviderRegistrar rtcIdentityProvider; 174 }; 175 176 [Exposed=RTCIdentityProviderGlobalScope] 177 interface RTCIdentityProviderRegistrar { 178 void register(RTCIdentityProvider idp); 179 }; 180 181 dictionary RTCIdentityProvider { 182 required GenerateAssertionCallback generateAssertion; 183 required ValidateAssertionCallback validateAssertion; 184 }; 185 */ 186 187 // if rtcIdentityProvider is defined, and the caller do not ask 188 // to not register through query string, register our assertion callbacks. 189 if(rtcIdentityProvider && query.action !== 'do-not-register') { 190 rtcIdentityProvider.register({ 191 generateAssertion, 192 validateAssertion 193 }); 194 }