mirror of
https://github.com/servo/servo.git
synced 2025-09-13 08:28:19 +01:00
Update web-platform-tests to revision 6e9693d2690e0648fb9a1bd902af7cc078f28515
This commit is contained in:
parent
4ec7dedce1
commit
612038c4d6
56 changed files with 1374 additions and 477 deletions
3
tests/wpt/web-platform-tests/webrtc-identity/META.yml
Normal file
3
tests/wpt/web-platform-tests/webrtc-identity/META.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
spec: https://github.com/w3c/webrtc-identity
|
||||
suggested_reviewers:
|
||||
- martinthomson
|
|
@ -0,0 +1,400 @@
|
|||
<!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,
|
||||
`https://${idpHost}/.well-known/idp-proxy/idp-test.js?foo=bar`,
|
||||
'Expect IdP proxy to be loaded with full well-known URL constructed from provider and protocol');
|
||||
|
||||
assert_equals(env.origin, `https://${idpHost}`,
|
||||
'Expect IdP to have its own origin');
|
||||
|
||||
assert_equals(args.options.protocol, 'idp-test.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.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(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');
|
||||
|
||||
/*
|
||||
4.4.2. Steps to create an offer
|
||||
1. If the need for an identity assertion was identified when createOffer was
|
||||
invoked, wait for the identity assertion request process to complete.
|
||||
2. If the identity provider was unable to produce an identity assertion, reject p
|
||||
with a newly created NotReadableError and abort these steps.
|
||||
*/
|
||||
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(t, 'NotReadableError',
|
||||
pc.createOffer());
|
||||
}, 'createOffer() should reject with NotReadableError if identitity assertion request fails');
|
||||
|
||||
/*
|
||||
4.4.2. Steps to create an answer
|
||||
1. If the need for an identity assertion was identified when createAnswer was
|
||||
invoked, wait for the identity assertion request process to complete.
|
||||
|
||||
2. If the identity provider was unable to produce an identity assertion, reject p
|
||||
with a newly created NotReadableError and abort these steps.
|
||||
*/
|
||||
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(t, 'NotReadableError',
|
||||
pc.createAnswer()));
|
||||
|
||||
}, 'createAnswer() should reject with NotReadableError if identitity assertion request fails');
|
||||
|
||||
</script>
|
|
@ -0,0 +1,336 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>RTCPeerConnection.prototype.peerIdentity</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;
|
||||
};
|
||||
|
||||
[Constructor(DOMString idp, DOMString name)]
|
||||
interface RTCIdentityAssertion {
|
||||
attribute DOMString idp;
|
||||
attribute DOMString name;
|
||||
};
|
||||
*/
|
||||
|
||||
/*
|
||||
4.3.2. setRemoteDescription
|
||||
If an a=identity attribute is present in the session description, the browser
|
||||
validates the identity assertion..
|
||||
|
||||
If the "peerIdentity" configuration is applied to the RTCPeerConnection, this
|
||||
establishes a target peer identity of the provided value. Alternatively, if the
|
||||
RTCPeerConnection has previously authenticated the identity of the peer (that
|
||||
is, there is a current value for peerIdentity ), then this also establishes a
|
||||
target peer identity.
|
||||
*/
|
||||
promise_test(t => {
|
||||
const pc1 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
const pc2 = new RTCPeerConnection();
|
||||
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
const port = window.location.port;
|
||||
const [idpDomain] = getIdpDomains();
|
||||
const idpHost = hostString(idpDomain, port);
|
||||
|
||||
pc1.setIdentityProvider(idpHost, {
|
||||
protocol: 'mock-idp.js',
|
||||
usernameHint: `alice@${idpDomain}`
|
||||
});
|
||||
|
||||
return pc1.createOffer()
|
||||
.then(offer => pc2.setRemoteDescription(offer))
|
||||
.then(() => pc2.peerIdentity)
|
||||
.then(identityAssertion => {
|
||||
const { idp, name } = identityAssertion;
|
||||
assert_equals(idp, idpDomain, `Expect IdP domain to be ${idpDomain}`);
|
||||
assert_equals(identityAssertion, `alice@${idpDomain}`,
|
||||
`Expect validated identity from mock-idp.js to be same as specified in usernameHint`);
|
||||
});
|
||||
}, 'setRemoteDescription() on offer with a=identity should establish peerIdentity');
|
||||
|
||||
/*
|
||||
4.3.2. setRemoteDescription
|
||||
The target peer identity cannot be changed once set. Once set, if a different
|
||||
value is provided, the user agent MUST reject the returned promise with a newly
|
||||
created InvalidModificationError and abort this operation. The RTCPeerConnection
|
||||
MUST be closed if the validated peer identity does not match the target peer
|
||||
identity.
|
||||
*/
|
||||
promise_test(t => {
|
||||
const port = window.location.port;
|
||||
const [idpDomain] = getIdpDomains();
|
||||
const idpHost = hostString(idpDomain, port);
|
||||
|
||||
const pc1 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
const pc2 = new RTCPeerConnection({
|
||||
peerIdentity: `bob@${idpDomain}`
|
||||
});
|
||||
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
pc1.setIdentityProvider(idpHost, {
|
||||
protocol: 'mock-idp.js',
|
||||
usernameHint: `alice@${idpDomain}`
|
||||
});
|
||||
|
||||
return pc1.createOffer()
|
||||
.then(offer =>
|
||||
promise_rejects(t, 'InvalidModificationError',
|
||||
pc2.setRemoteDescription(offer)))
|
||||
.then(() => {
|
||||
assert_true(pc2.signalingState, 'closed',
|
||||
'Expect peer connection to be closed after mismatch peer identity');
|
||||
});
|
||||
}, 'setRemoteDescription() on offer with a=identity that resolve to value different from target peer identity should reject with InvalidModificationError');
|
||||
|
||||
/*
|
||||
9.4. Verifying Identity Assertions
|
||||
8. The RTCPeerConnection decodes the contents and validates that it contains a
|
||||
fingerprint value for every a=fingerprint attribute in the session description.
|
||||
This ensures that the certificate used by the remote peer for communications
|
||||
is covered by the identity assertion.
|
||||
|
||||
If identity validation fails, the peerIdentity promise is rejected with a newly
|
||||
created OperationError.
|
||||
|
||||
If identity validation fails and there is a target peer identity for the
|
||||
RTCPeerConnection, the promise returned by setRemoteDescription MUST be rejected
|
||||
with the same DOMException.
|
||||
*/
|
||||
promise_test(t => {
|
||||
const port = window.location.port;
|
||||
const [idpDomain] = getIdpDomains();
|
||||
const idpHost = hostString(idpDomain, port);
|
||||
|
||||
const pc1 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
const pc2 = new RTCPeerConnection({
|
||||
peerIdentity: `alice@${idpDomain}`
|
||||
});
|
||||
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
// Ask mockidp.js to return custom contents in validation result
|
||||
pc1.setIdentityProvider(idpHost, {
|
||||
protocol: 'mock-idp.js?validatorAction=return-custom-contents&contents=bogus',
|
||||
usernameHint: `alice@${idpDomain}`
|
||||
});
|
||||
|
||||
const peerIdentityPromise = pc2.peerIdentity;
|
||||
|
||||
return pc1.createOffer()
|
||||
.then(offer => Promise.all([
|
||||
promise_rejects(t, 'OperationError',
|
||||
pc2.setRemoteDescription(offer)),
|
||||
promise_rejects(t, 'OperationError',
|
||||
peerIdentityPromise)
|
||||
]));
|
||||
}, 'setRemoteDescription() with peerIdentity set and with IdP proxy that return validationAssertion with mismatch contents should reject with OperationError');
|
||||
|
||||
/*
|
||||
9.4. Verifying Identity Assertions
|
||||
9. The RTCPeerConnection validates that the domain portion of the identity matches
|
||||
the domain of the IdP as described in [RTCWEB-SECURITY-ARCH]. If this check
|
||||
fails then the identity validation fails.
|
||||
*/
|
||||
promise_test(t => {
|
||||
const port = window.location.port;
|
||||
const [idpDomain1, idpDomain2] = getIdpDomains();
|
||||
assert_not_equals(idpDomain1, idpDomain2,
|
||||
'Sanity check two idpDomains are different');
|
||||
|
||||
const idpHost1 = hostString(idpDomain1, port);
|
||||
|
||||
const pc1 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
const pc2 = new RTCPeerConnection({
|
||||
peerIdentity: `alice@${idpDomain2}`
|
||||
});
|
||||
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
// mock-idp.js will return assertion of domain2 identity
|
||||
// with domain1 in the idp.domain field
|
||||
pc1.setIdentityProvider(idpHost1, {
|
||||
protocol: 'mock-idp.js',
|
||||
usernameHint: `alice@${idpDomain2}`
|
||||
});
|
||||
|
||||
return pc1.getIdentityAssertion()
|
||||
.then(assertionResultStr => {
|
||||
const { idp, assertion } = parseAssertionResult(assertionResultStr);
|
||||
|
||||
assert_equals(idp.domain, idpDomain1,
|
||||
'Sanity check domain of assertion is domain1');
|
||||
|
||||
assert_equals(assertion.options.usernameHint, `alice@${idpDomain2}`,
|
||||
'Sanity check domain1 is going to validate a domain2 identity');
|
||||
|
||||
return pc1.createOffer();
|
||||
})
|
||||
.then(offer => Promise.all([
|
||||
promise_rejects(t, 'OperationError',
|
||||
pc2.setRemoteDescription(offer)),
|
||||
promise_rejects(t, 'OperationError',
|
||||
pc2.peerIdentity)
|
||||
]));
|
||||
}, 'setRemoteDescription() and peerIdentity should reject with OperationError if IdP return validated identity that is different from its own domain');
|
||||
|
||||
/*
|
||||
9.4 Verifying Identity Assertions
|
||||
If identity validation fails and there is a target peer identity for the
|
||||
RTCPeerConnection, the promise returned by setRemoteDescription MUST be rejected
|
||||
with the same DOMException.
|
||||
|
||||
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".
|
||||
|
||||
Any error generated by the IdP MAY provide additional information in the
|
||||
idpErrorInfo attribute. The information in this string is defined by the
|
||||
IdP in use.
|
||||
*/
|
||||
promise_test(t => {
|
||||
const port = window.location.port;
|
||||
const [idpDomain] = getIdpDomains();
|
||||
const idpHost = hostString(idpDomain, port);
|
||||
|
||||
const pc1 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
const pc2 = new RTCPeerConnection({
|
||||
peerIdentity: `alice@${idpDomain}`
|
||||
});
|
||||
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
// Ask mock-idp.js to throw error during validation,
|
||||
// i.e. during pc2.setRemoteDescription()
|
||||
pc1.setIdentityProvider(idpHost, {
|
||||
protocol: 'mock-idp.js?validatorAction=throw-error&errorInfo=bar',
|
||||
usernameHint: `alice@${idpDomain}`
|
||||
});
|
||||
|
||||
return pc1.createOffer()
|
||||
.then(offer => Promise.all([
|
||||
assert_rtcerror_rejection('idp-execution-failure',
|
||||
pc2.setRemoteDescription(offer)),
|
||||
assert_rtcerror_rejection('idp-execution-failure',
|
||||
pc2.peerIdentity)
|
||||
]))
|
||||
.then(() => {
|
||||
assert_equals(pc2.idpErrorInfo, 'bar',
|
||||
'Expect pc2.idpErrorInfo to be set to the err.idpErrorInfo thrown by mock-idp.js');
|
||||
});
|
||||
}, `When IdP throws error and pc has target peer identity, setRemoteDescription() and peerIdentity rejected with RTCError('idp-execution-error')`);
|
||||
|
||||
/*
|
||||
4.3.2. setRemoteDescription
|
||||
If there is no target peer identity, then setRemoteDescription does not await the
|
||||
completion of identity validation.
|
||||
|
||||
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.4. Verifying Identity Assertions
|
||||
If identity validation fails and there is no a target peer identity, the value of
|
||||
the peerIdentity MUST be set to a new, unresolved promise instance. This permits
|
||||
the use of renegotiation (or a subsequent answer, if the session description was
|
||||
a provisional answer) to resolve or reject the identity.
|
||||
*/
|
||||
promise_test(t => {
|
||||
const pc1 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
const pc2 = new RTCPeerConnection();
|
||||
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
const port = window.location.port;
|
||||
const [idpDomain] = getIdpDomains();
|
||||
const idpHost = hostString(idpDomain, port);
|
||||
|
||||
// Ask mock-idp.js to throw error during validation,
|
||||
// i.e. during pc2.setRemoteDescription()
|
||||
pc1.setIdentityProvider(idpHost, {
|
||||
protocol: 'mock-idp.js?validatorAction=throw-error',
|
||||
usernameHint: `alice@${idpDomain}`
|
||||
});
|
||||
|
||||
const peerIdentityPromise1 = pc2.peerIdentity;
|
||||
|
||||
return pc1.createOffer()
|
||||
.then(offer =>
|
||||
// setRemoteDescription should succeed because there is no target peer identity set
|
||||
pc2.setRemoteDescription(offer))
|
||||
.then(() =>
|
||||
assert_rtcerror_rejection('idp-execution-failure',
|
||||
peerIdentityPromise1,
|
||||
`Expect first peerIdentity promise to be rejected with RTCError('idp-execution-failure')`))
|
||||
.then(() => {
|
||||
const peerIdentityPromise2 = pc2.peerIdentity;
|
||||
assert_not_equals(peerIdentityPromise2, peerIdentityPromise1,
|
||||
'Expect pc2.peerIdentity to be replaced with a fresh unresolved promise');
|
||||
|
||||
// regenerate an identity assertion with no test option to throw error
|
||||
pc1.setIdentityProvider(idpHost, {
|
||||
protocol: 'idp-test.js',
|
||||
usernameHint: `alice@${idpDomain}`
|
||||
});
|
||||
|
||||
return pc1.createOffer()
|
||||
.then(offer => pc2.setRemoteDescription(offer))
|
||||
.then(peerIdentityPromise2)
|
||||
.then(identityAssertion => {
|
||||
const { idp, name } = identityAssertion;
|
||||
|
||||
assert_equals(idp, idpDomain,
|
||||
`Expect IdP domain to be ${idpDomain}`);
|
||||
|
||||
assert_equals(name, `alice@${idpDomain}`,
|
||||
`Expect validated identity to be alice@${idpDomain}`);
|
||||
|
||||
assert_equals(pc2.peeridentity, peerIdentityPromise2,
|
||||
'Expect pc2.peerIdentity to stay fixed after identity is validated');
|
||||
});
|
||||
});
|
||||
}, 'IdP failure with no target peer identity should have following setRemoteDescription() succeed and replace pc.peerIdentity with a new promise');
|
||||
|
||||
</script>
|
|
@ -0,0 +1,70 @@
|
|||
'use strict';
|
||||
|
||||
/*
|
||||
In web-platform-test, a number of domains are required to be set up locally.
|
||||
The list is available at docs/_writing-tests/server-features.md. The
|
||||
appropriate hosts file entries can be generated with the WPT CLI via the
|
||||
following command: `wpt make-hosts-file`.
|
||||
*/
|
||||
|
||||
/*
|
||||
dictionary RTCIdentityProviderDetails {
|
||||
required DOMString domain;
|
||||
DOMString protocol = "default";
|
||||
};
|
||||
*/
|
||||
|
||||
// Parse a base64 JSON encoded string returned from getIdentityAssertion().
|
||||
// This is also the string that is set in the a=identity line.
|
||||
// Returns a { idp, assertion } where idp is of type RTCIdentityProviderDetails
|
||||
// and assertion is the deserialized JSON that was returned by the
|
||||
// IdP proxy's generateAssertion() function.
|
||||
function parseAssertionResult(assertionResultStr) {
|
||||
const assertionResult = JSON.parse(atob(assertionResultStr));
|
||||
|
||||
const { idp } = assertionResult;
|
||||
const assertion = JSON.parse(assertionResult.assertion);
|
||||
|
||||
return { idp, assertion };
|
||||
}
|
||||
|
||||
// Return two distinct IdP domains that are different from current domain
|
||||
function getIdpDomains() {
|
||||
const domainA = '{{domains[www]}}';
|
||||
const domainB = '{{domains[www1]}}';
|
||||
const domainC = '{{domains[www2]}}';
|
||||
|
||||
if(window.location.hostname === domainA) {
|
||||
return [domainB, domainC];
|
||||
} else if(window.location.hostname === domainB) {
|
||||
return [domainA, domainC];
|
||||
} else {
|
||||
return [domainA, domainB];
|
||||
}
|
||||
}
|
||||
|
||||
function assert_rtcerror_rejection(errorDetail, promise, desc) {
|
||||
return promise.then(
|
||||
res => {
|
||||
assert_unreached(`Expect promise to be rejected with RTCError, but instead got ${res}`);
|
||||
}, err => {
|
||||
assert_true(err instanceof RTCError,
|
||||
'Expect error object to be instance of RTCError');
|
||||
|
||||
assert_equals(err.errorDetail, errorDetail,
|
||||
`Expect RTCError object have errorDetail set to ${errorDetail}`);
|
||||
|
||||
return err;
|
||||
});
|
||||
}
|
||||
|
||||
// construct a host string consist of domain and optionally port
|
||||
// If the default HTTP/HTTPS port is used, window.location.port returns
|
||||
// empty string.
|
||||
function hostString(domain, port) {
|
||||
if(port === '') {
|
||||
return domain;
|
||||
} else {
|
||||
return `${domain}:${port}`;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue