| 'use strict'; |
| |
| // Code is based on the following editor draft: |
| // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html |
| |
| /* |
| mock-idp.js is a naive IdP that provides absolutely no |
| security for authentication. It can generate identity |
| assertion for whatever identity that is requested. |
| |
| mock-idp.js validates identity assertion by simply decoding |
| the JSON and return whatever that is inside, with no integrity |
| protection and thus can be spoofed by anyone. |
| |
| While being not practical at all, mock-idp.js allows us |
| to test various aspects of the identity API and allow tests |
| to manipulate the IdP at will. |
| */ |
| |
| // We pass around test options as query string to instruct |
| // the test IdP proxy script on what actions to perform. |
| // This hack is based on the fact that query string is allowed |
| // when specifying the IdP protocol. |
| function parseQueryString(urlStr) { |
| const url = new URL(urlStr); |
| const result = {}; |
| for(const [key, value] of url.searchParams) { |
| result[key] = value; |
| } |
| return result; |
| } |
| |
| /* |
| 9.2.1. Interface Exposed by Identity Providers |
| callback GenerateAssertionCallback = |
| Promise<RTCIdentityAssertionResult> ( |
| DOMString contents, |
| DOMString origin, |
| RTCIdentityProviderOptions options); |
| |
| dictionary RTCIdentityProviderOptions { |
| DOMString protocol = "default"; |
| DOMString usernameHint; |
| DOMString peerIdentity; |
| }; |
| |
| dictionary RTCIdentityAssertionResult { |
| required RTCIdentityProviderDetails idp; |
| required DOMString assertion; |
| }; |
| |
| dictionary RTCIdentityProviderDetails { |
| required DOMString domain; |
| DOMString protocol = "default"; |
| }; |
| */ |
| |
| const query = parseQueryString(location); |
| |
| // Generate a naive identity assertion. The result assertion |
| // is a JSON string that report the various parameters |
| // received by this function. |
| // watermark - a special mark to make sure the result is returned |
| // from this function |
| // args - the function arguments received |
| // env - some global variable values when this function is called |
| // query - the parsed query string of the script URL |
| function generateAssertion(contents, origin, options) { |
| const args = { |
| contents, origin, options |
| }; |
| |
| const env = { |
| origin, |
| location |
| }; |
| |
| const assertion = { |
| watermark: 'mock-idp.js.watermark', |
| args, |
| env, |
| query |
| }; |
| |
| const assertionStr = JSON.stringify(assertion); |
| |
| const { generatorAction } = query; |
| |
| if(generatorAction === 'throw-error') { |
| const err = new Error('Mock Internal IdP Error'); |
| err.idpErrorInfo = query.errorInfo; |
| throw err; |
| |
| } else if(generatorAction === 'require-login') { |
| const err = new RTCError('idp-need-login'); |
| err.idpLoginUrl = `${origin}/login`; |
| err.idpErrorInfo = 'login required'; |
| throw err; |
| |
| } else if(generatorAction === 'return-custom-idp') { |
| const { domain, protocol } = query; |
| |
| return { |
| idp: { |
| domain, |
| protocol |
| }, |
| assertion: assertionStr |
| }; |
| |
| } else if(generatorAction === 'return-invalid-result') { |
| return 'invalid-result'; |
| |
| } else { |
| return { |
| idp: { |
| domain: location.host, |
| protocol: 'mock-idp.js' |
| }, |
| assertion: assertionStr |
| }; |
| } |
| } |
| |
| /* |
| 9.2.1. Interface Exposed by Identity Providers |
| callback ValidateAssertionCallback = |
| Promise<RTCIdentityValidationResult> ( |
| DOMString assertion, |
| DOMString origin); |
| |
| dictionary RTCIdentityValidationResult { |
| required DOMString identity; |
| required DOMString contents; |
| }; |
| */ |
| function validateAssertion(assertionStr, origin) { |
| const assertion = JSON.parse(assertionStr); |
| |
| const { args, query } = assertion; |
| const { contents, options } = args; |
| |
| const identity = options.usernameHint; |
| |
| const { |
| validatorAction |
| } = query; |
| |
| if(validatorAction === 'throw-error') { |
| const err = new Error('Mock Internal IdP Error'); |
| err.idpErrorInfo = query.errorInfo; |
| throw err; |
| |
| } else if(validatorAction === 'return-custom-contents') { |
| const { contents } = query; |
| return { |
| identity, |
| contents |
| }; |
| |
| } else { |
| return { |
| identity, contents |
| }; |
| } |
| } |
| |
| /* |
| 9.2. Registering an IdP Proxy |
| [Global, |
| Exposed=RTCIdentityProviderGlobalScope] |
| interface RTCIdentityProviderGlobalScope : WorkerGlobalScope { |
| readonly attribute RTCIdentityProviderRegistrar rtcIdentityProvider; |
| }; |
| |
| [Exposed=RTCIdentityProviderGlobalScope] |
| interface RTCIdentityProviderRegistrar { |
| void register(RTCIdentityProvider idp); |
| }; |
| |
| dictionary RTCIdentityProvider { |
| required GenerateAssertionCallback generateAssertion; |
| required ValidateAssertionCallback validateAssertion; |
| }; |
| */ |
| |
| // if rtcIdentityProvider is defined, and the caller do not ask |
| // to not register through query string, register our assertion callbacks. |
| if(rtcIdentityProvider && query.action !== 'do-not-register') { |
| rtcIdentityProvider.register({ |
| generateAssertion, |
| validateAssertion |
| }); |
| } |