diff options
Diffstat (limited to 'testing/web-platform/tests/webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.https.html')
-rw-r--r-- | testing/web-platform/tests/webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.https.html | 397 |
1 files changed, 397 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.https.html b/testing/web-platform/tests/webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.https.html new file mode 100644 index 0000000000..57d7b16165 --- /dev/null +++ b/testing/web-platform/tests/webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.https.html @@ -0,0 +1,397 @@ +<!doctype html> +<meta charset=utf-8> +<title>RTCPeerConnection.prototype.getIdentityAssertion</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="identity-helper.sub.js"></script> +<script> + 'use strict'; + + // Test is based on the following editor draft: + // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html + + // The tests here interacts with the mock identity provider located at + // /.well-known/idp-proxy/mock-idp.js + + // The following helper functions are called from identity-helper.sub.js + // parseAssertionResult + // getIdpDomains + // assert_rtcerror_rejection + // hostString + + /* + 9.6. RTCPeerConnection Interface Extensions + partial interface RTCPeerConnection { + void setIdentityProvider(DOMString provider, + optional RTCIdentityProviderOptions options); + Promise<DOMString> getIdentityAssertion(); + readonly attribute Promise<RTCIdentityAssertion> peerIdentity; + readonly attribute DOMString? idpLoginUrl; + readonly attribute DOMString? idpErrorInfo; + }; + + dictionary RTCIdentityProviderOptions { + DOMString protocol = "default"; + DOMString usernameHint; + DOMString peerIdentity; + }; + */ + promise_test(t => { + const pc = new RTCPeerConnection(); + const port = window.location.port; + + const [idpDomain] = getIdpDomains(); + const idpHost = hostString(idpDomain, port); + + pc.setIdentityProvider(idpHost, { + protocol: 'mock-idp.js?foo=bar', + usernameHint: `alice@${idpDomain}`, + peerIdentity: 'bob@example.org' + }); + + return pc.getIdentityAssertion() + .then(assertionResultStr => { + const { idp, assertion } = parseAssertionResult(assertionResultStr); + + assert_equals(idp.domain, idpHost, + 'Expect mock-idp.js to construct domain from its location.host'); + + assert_equals(idp.protocol, 'mock-idp.js', + 'Expect mock-idp.js to return protocol of itself with no query string'); + + const { + watermark, + args, + env, + query, + } = assertion; + + assert_equals(watermark, 'mock-idp.js.watermark', + 'Expect assertion result to contain watermark left by mock-idp.js'); + + assert_equals(args.origin, window.origin, + 'Expect args.origin argument to be the origin of this window'); + + assert_equals(env.location.href, + `https://${idpHost}/.well-known/idp-proxy/mock-idp.js?foo=bar`, + 'Expect IdP proxy to be loaded with full well-known URL constructed from provider and protocol'); + + assert_equals(env.location.origin, `https://${idpHost}`, + 'Expect IdP to have its own origin'); + + assert_equals(args.options.protocol, 'mock-idp.js?foo=bar', + 'Expect options.protocol to be the same value as being passed from here'); + + assert_equals(args.options.usernameHint, `alice@${idpDomain}`, + 'Expect options.usernameHint to be the same value as being passed from here'); + + assert_equals(args.options.peerIdentity, 'bob@example.org', + 'Expect options.peerIdentity to be the same value as being passed from here'); + + assert_equals(query.foo, 'bar', + 'Expect query string to be parsed by mock-idp.js and returned back'); + }); + }, 'getIdentityAssertion() should load IdP proxy and return assertion generated'); + + // When generating assertion, the RTCPeerConnection doesn't care if the returned assertion + // represents identity of different domain + promise_test(t => { + const pc = new RTCPeerConnection(); + const port = window.location.port; + + const [idpDomain1, idpDomain2] = getIdpDomains(); + assert_not_equals(idpDomain1, idpDomain2, + 'Sanity check two idpDomains are different'); + + // Ask mock-idp.js to return a custom domain idpDomain2 and custom protocol foo + pc.setIdentityProvider(hostString(idpDomain1, port), { + protocol: `mock-idp.js?generatorAction=return-custom-idp&domain=${idpDomain2}&protocol=foo`, + usernameHint: `alice@${idpDomain2}`, + }); + + return pc.getIdentityAssertion() + .then(assertionResultStr => { + const { idp, assertion } = parseAssertionResult(assertionResultStr); + assert_equals(idp.domain, idpDomain2); + assert_equals(idp.protocol, 'foo'); + assert_equals(assertion.args.options.usernameHint, `alice@${idpDomain2}`); + }); + }, 'getIdentityAssertion() should succeed if mock-idp.js return different domain and protocol in assertion'); + + /* + 9.3. Requesting Identity Assertions + 4. If the IdP proxy produces an error or returns a promise that does not resolve to + a valid RTCIdentityValidationResult (see 9.5 IdP Error Handling), then identity + validation fails. + + 9.5. IdP Error Handling + - If an identity provider throws an exception or returns a promise that is ultimately + rejected, then the procedure that depends on the IdP MUST also fail. These types of + errors will cause an IdP failure with an RTCError with errorDetail set to + "idp-execution-failure". + + 9.6. RTCPeerConnection Interface Extensions + idpErrorInfo + An attribute that the IdP can use to pass additional information back to the + applications about the error. The format of this string is defined by the IdP and + may be JSON. + */ + promise_test(t => { + const pc = new RTCPeerConnection(); + + assert_equals(pc.idpErrorInfo, null, + 'Expect initial pc.idpErrorInfo to be null'); + + const port = window.location.port; + const [idpDomain] = getIdpDomains(); + + // Ask mock-idp.js to throw an error with err.errorInfo set to bar + pc.setIdentityProvider(hostString(idpDomain, port), { + protocol: `mock-idp.js?generatorAction=throw-error&errorInfo=bar`, + usernameHint: `alice@${idpDomain}`, + }); + + return assert_rtcerror_rejection('idp-execution-failure', + pc.getIdentityAssertion()) + .then(() => { + assert_equals(pc.idpErrorInfo, 'bar', + 'Expect pc.idpErrorInfo to be set to the err.idpErrorInfo thrown by mock-idp.js'); + }); + }, `getIdentityAssertion() should reject with RTCError('idp-execution-failure') if mock-idp.js throws error`); + + /* + 9.5. IdP Error Handling + - If the script loaded from the identity provider is not valid JavaScript or does + not implement the correct interfaces, it causes an IdP failure with an RTCError + with errorDetail set to "idp-bad-script-failure". + */ + promise_test(t => { + const pc = new RTCPeerConnection(); + + const port = window.location.port; + const [idpDomain] = getIdpDomains(); + + // Ask mock-idp.js to not register its callback to the + // RTCIdentityProviderRegistrar + pc.setIdentityProvider(hostString(idpDomain, port), { + protocol: `mock-idp.js?action=do-not-register`, + usernameHint: `alice@${idpDomain}`, + }); + + return assert_rtcerror_rejection('idp-bad-script-failure', + pc.getIdentityAssertion()); + + }, `getIdentityAssertion() should reject with RTCError('idp-bad-script-failure') if IdP proxy script do not register its callback`); + + /* + 9.3. Requesting Identity Assertions + 4. If the IdP proxy produces an error or returns a promise that does not resolve + to a valid RTCIdentityAssertionResult (see 9.5 IdP Error Handling), then assertion + generation fails. + */ + promise_test(t => { + const pc = new RTCPeerConnection(); + + const port = window.location.port; + const [idpDomain] = getIdpDomains(); + + // Ask mock-idp.js to return an invalid result that is not proper + // RTCIdentityAssertionResult + pc.setIdentityProvider(hostString(idpDomain, port), { + protocol: `mock-idp.js?generatorAction=return-invalid-result`, + usernameHint: `alice@${idpDomain}`, + }); + + return promise_rejects_dom(t, 'OperationError', + pc.getIdentityAssertion()); + }, `getIdentityAssertion() should reject with OperationError if mock-idp.js return invalid result`); + + /* + 9.5. IdP Error Handling + - A RTCPeerConnection might be configured with an identity provider, but loading of + the IdP URI fails. Any procedure that attempts to invoke such an identity provider + and cannot load the URI fails with an RTCError with errorDetail set to + "idp-load-failure" and the httpRequestStatusCode attribute of the error set to the + HTTP status code of the response. + */ + promise_test(t => { + const pc = new RTCPeerConnection(); + + pc.setIdentityProvider('nonexistent.{{domains[]}}', { + protocol: `non-existent`, + usernameHint: `alice@example.org`, + }); + + return assert_rtcerror_rejection('idp-load-failure', + pc.getIdentityAssertion()); + }, `getIdentityAssertion() should reject with RTCError('idp-load-failure') if IdP cannot be loaded`); + + /* + 9.3.1. User Login Procedure + Rejecting the promise returned by generateAssertion will cause the error to + propagate to the application. Login errors are indicated by rejecting the + promise with an RTCError with errorDetail set to "idp-need-login". + + The URL to login at will be passed to the application in the idpLoginUrl + attribute of the RTCPeerConnection. + + 9.5. IdP Error Handling + - If the identity provider requires the user to login, the operation will fail + RTCError with errorDetail set to "idp-need-login" and the idpLoginUrl attribute + of the error set to the URL that can be used to login. + */ + promise_test(t => { + const pc = new RTCPeerConnection(); + + assert_equals(pc.idpLoginUrl, null, + 'Expect initial pc.idpLoginUrl to be null'); + + const port = window.location.port; + const [idpDomain] = getIdpDomains(); + const idpHost = hostString(idpDomain, port); + + pc.setIdentityProvider(idpHost, { + protocol: `mock-idp.js?generatorAction=require-login`, + usernameHint: `alice@${idpDomain}`, + }); + + return assert_rtcerror_rejection('idp-need-login', + pc.getIdentityAssertion()) + .then(err => { + assert_equals(err.idpLoginUrl, `https://${idpHost}/login`, + 'Expect err.idpLoginUrl to be set to url set by mock-idp.js'); + + assert_equals(pc.idpLoginUrl, `https://${idpHost}/login`, + 'Expect pc.idpLoginUrl to be set to url set by mock-idp.js'); + + assert_equals(pc.idpErrorInfo, 'login required', + 'Expect pc.idpErrorInfo to be set to info set by mock-idp.js'); + }); + }, `getIdentityAssertion() should reject with RTCError('idp-need-login') when mock-idp.js requires login`); + + /* + RTCIdentityProviderOptions Members + peerIdentity + The identity of the peer. For identity providers that bind their assertions to a + particular pair of communication peers, this allows them to generate an assertion + that includes both local and remote identities. If this value is omitted, but a + value is provided for the peerIdentity member of RTCConfiguration, the value from + RTCConfiguration is used. + */ + promise_test(t => { + const pc = new RTCPeerConnection({ + peerIdentity: 'bob@example.net' + }); + + const port = window.location.port; + const [idpDomain] = getIdpDomains(); + const idpHost = hostString(idpDomain, port); + + pc.setIdentityProvider(idpHost, { + protocol: 'mock-idp.js' + }); + + return pc.getIdentityAssertion() + .then(assertionResultStr => { + const { assertion } = parseAssertionResult(assertionResultStr); + assert_equals(assertion.args.options.peerIdentity, 'bob@example.net'); + }); + }, 'setIdentityProvider() with no peerIdentity provided should use peerIdentity value from getConfiguration()'); + + /* + 9.6. setIdentityProvider + 3. If any identity provider value has changed, discard any stored identity assertion. + */ + promise_test(t => { + const pc = new RTCPeerConnection(); + const port = window.location.port; + const [idpDomain] = getIdpDomains(); + const idpHost = hostString(idpDomain, port); + + pc.setIdentityProvider(idpHost, { + protocol: 'mock-idp.js?mark=first' + }); + + return pc.getIdentityAssertion() + .then(assertionResultStr => { + const { assertion } = parseAssertionResult(assertionResultStr); + assert_equals(assertion.query.mark, 'first'); + + pc.setIdentityProvider(idpHost, { + protocol: 'mock-idp.js?mark=second' + }); + + return pc.getIdentityAssertion(); + }) + .then(assertionResultStr => { + const { assertion } = parseAssertionResult(assertionResultStr); + assert_equals(assertion.query.mark, 'second', + 'Expect generated assertion is from second IdP config'); + }); + }, `Calling setIdentityProvider() multiple times should reset identity assertions`); + + promise_test(t => { + const pc = new RTCPeerConnection(); + const port = window.location.port; + const [idpDomain] = getIdpDomains(); + + pc.setIdentityProvider(hostString(idpDomain, port), { + protocol: 'mock-idp.js', + usernameHint: `alice@${idpDomain}` + }); + + return pc.getIdentityAssertion() + .then(assertionResultStr => + pc.createOffer() + .then(offer => { + assert_true(offer.sdp.includes(`\r\na=identity:${assertionResultStr}`, + 'Expect SDP to have a=identity line containing assertion string')); + })); + }, 'createOffer() should return SDP containing identity assertion string if identity provider is set'); + + /* + 6. Requesting Identity Assertions + + The identity assertion request process is triggered by a call to + createOffer, createAnswer, or getIdentityAssertion. When these calls are + invoked and an identity provider has been set, the following steps are + executed: + + ... + + If assertion generation fails, then the promise for the corresponding + function call is rejected with a newly created OperationError. */ + promise_test(t => { + const pc = new RTCPeerConnection(); + const port = window.location.port; + const [idpDomain] = getIdpDomains(); + + pc.setIdentityProvider(hostString(idpDomain, port), { + protocol: 'mock-idp.js?generatorAction=throw-error', + usernameHint: `alice@${idpDomain}` + }); + + return promise_rejects_dom(t, 'OperationError', + pc.createOffer()); + }, 'createOffer() should reject with OperationError if identity assertion request fails'); + + promise_test(t => { + const pc = new RTCPeerConnection(); + const port = window.location.port; + const [idpDomain] = getIdpDomains(); + + pc.setIdentityProvider(hostString(idpDomain, port), { + protocol: 'mock-idp.js?generatorAction=throw-error', + usernameHint: `alice@${idpDomain}` + }); + + return new RTCPeerConnection() + .createOffer() + .then(offer => pc.setRemoteDescription(offer)) + .then(() => + promise_rejects_dom(t, 'OperationError', + pc.createAnswer())); + + }, 'createAnswer() should reject with OperationError if identity assertion request fails'); + +</script> |