summaryrefslogtreecommitdiffstats
path: root/dom/media/tests/mochitest/identity
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/tests/mochitest/identity')
-rw-r--r--dom/media/tests/mochitest/identity/identityPcTest.js53
-rw-r--r--dom/media/tests/mochitest/identity/idp-bad.js1
-rw-r--r--dom/media/tests/mochitest/identity/idp-min.js24
-rw-r--r--dom/media/tests/mochitest/identity/idp-redirect-http-trick.js3
-rw-r--r--dom/media/tests/mochitest/identity/idp-redirect-http-trick.js^headers^2
-rw-r--r--dom/media/tests/mochitest/identity/idp-redirect-http.js3
-rw-r--r--dom/media/tests/mochitest/identity/idp-redirect-http.js^headers^2
-rw-r--r--dom/media/tests/mochitest/identity/idp-redirect-https-double.js3
-rw-r--r--dom/media/tests/mochitest/identity/idp-redirect-https-double.js^headers^2
-rw-r--r--dom/media/tests/mochitest/identity/idp-redirect-https-odd-path.js3
-rw-r--r--dom/media/tests/mochitest/identity/idp-redirect-https-odd-path.js^headers^2
-rw-r--r--dom/media/tests/mochitest/identity/idp-redirect-https.js3
-rw-r--r--dom/media/tests/mochitest/identity/idp-redirect-https.js^headers^2
-rw-r--r--dom/media/tests/mochitest/identity/idp.js110
-rw-r--r--dom/media/tests/mochitest/identity/idp.sjs18
-rw-r--r--dom/media/tests/mochitest/identity/login.html31
-rw-r--r--dom/media/tests/mochitest/identity/mochitest.ini42
-rw-r--r--dom/media/tests/mochitest/identity/test_fingerprints.html112
-rw-r--r--dom/media/tests/mochitest/identity/test_getIdentityAssertion.html96
-rw-r--r--dom/media/tests/mochitest/identity/test_idpproxy.html176
-rw-r--r--dom/media/tests/mochitest/identity/test_loginNeeded.html71
-rw-r--r--dom/media/tests/mochitest/identity/test_peerConnection_asymmetricIsolation.html31
-rw-r--r--dom/media/tests/mochitest/identity/test_peerConnection_peerIdentity.html21
-rw-r--r--dom/media/tests/mochitest/identity/test_setIdentityProvider.html63
-rw-r--r--dom/media/tests/mochitest/identity/test_setIdentityProviderWithErrors.html55
25 files changed, 929 insertions, 0 deletions
diff --git a/dom/media/tests/mochitest/identity/identityPcTest.js b/dom/media/tests/mochitest/identity/identityPcTest.js
new file mode 100644
index 000000000..e5fcbc5db
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/identityPcTest.js
@@ -0,0 +1,53 @@
+function identityPcTest(remoteOptions) {
+ var user = 'someone';
+ var domain1 = 'test1.example.com';
+ var domain2 = 'test2.example.com';
+ var id1 = user + '@' + domain1;
+ var id2 = user + '@' + domain2;
+
+ test = new PeerConnectionTest({
+ config_local: {
+ peerIdentity: id2
+ },
+ config_remote: {
+ peerIdentity: id1
+ }
+ });
+ test.setMediaConstraints([{
+ audio: true,
+ video: true,
+ peerIdentity: id2
+ }], [remoteOptions || {
+ audio: true,
+ video: true,
+ peerIdentity: id1
+ }]);
+ test.pcLocal.setIdentityProvider('test1.example.com', 'idp.js');
+ test.pcRemote.setIdentityProvider('test2.example.com', 'idp.js');
+ test.chain.append([
+ function PEER_IDENTITY_IS_SET_CORRECTLY(test) {
+ // no need to wait to check identity in this case,
+ // setRemoteDescription should wait for the IdP to complete
+ function checkIdentity(pc, pfx, idp, name) {
+ return pc.peerIdentity.then(peerInfo => {
+ is(peerInfo.idp, idp, pfx + "IdP check");
+ is(peerInfo.name, name + "@" + idp, pfx + "identity check");
+ });
+ }
+
+ return Promise.all([
+ checkIdentity(test.pcLocal._pc, "local: ", "test2.example.com", "someone"),
+ checkIdentity(test.pcRemote._pc, "remote: ", "test1.example.com", "someone")
+ ]);
+ },
+
+ function REMOTE_STREAMS_ARE_RESTRICTED(test) {
+ var remoteStream = test.pcLocal._pc.getRemoteStreams()[0];
+ return Promise.all([
+ audioIsSilence(true, remoteStream),
+ videoIsBlack(true, remoteStream)
+ ]);
+ }
+ ]);
+ test.run();
+}
diff --git a/dom/media/tests/mochitest/identity/idp-bad.js b/dom/media/tests/mochitest/identity/idp-bad.js
new file mode 100644
index 000000000..86e1cb7a3
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/idp-bad.js
@@ -0,0 +1 @@
+<This isn't valid JS>
diff --git a/dom/media/tests/mochitest/identity/idp-min.js b/dom/media/tests/mochitest/identity/idp-min.js
new file mode 100644
index 000000000..8e228b688
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/idp-min.js
@@ -0,0 +1,24 @@
+(function(global) {
+ 'use strict';
+ // A minimal implementation of the interface.
+ // Though this isn't particularly functional.
+ // This is needed so that we can have a "working" IdP served
+ // from two different locations in the tree.
+ global.rtcIdentityProvider.register({
+ generateAssertion: function(payload, origin, usernameHint) {
+ dump('idp: generateAssertion(' + payload + ')\n');
+ return Promise.resolve({
+ idp: { domain: 'example.com', protocol: 'idp.js' },
+ assertion: 'bogus'
+ });
+ },
+
+ validateAssertion: function(assertion, origin) {
+ dump('idp: validateAssertion(' + assertion + ')\n');
+ return Promise.resolve({
+ identity: 'user@example.com',
+ contents: 'bogus'
+ });
+ }
+ });
+}(this));
diff --git a/dom/media/tests/mochitest/identity/idp-redirect-http-trick.js b/dom/media/tests/mochitest/identity/idp-redirect-http-trick.js
new file mode 100644
index 000000000..5d35ac0ca
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/idp-redirect-http-trick.js
@@ -0,0 +1,3 @@
+(function() {
+ dump('ERROR\n');
+}());
diff --git a/dom/media/tests/mochitest/identity/idp-redirect-http-trick.js^headers^ b/dom/media/tests/mochitest/identity/idp-redirect-http-trick.js^headers^
new file mode 100644
index 000000000..b3a2afd90
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/idp-redirect-http-trick.js^headers^
@@ -0,0 +1,2 @@
+HTTP 301 Moved Permanently
+Location: http://example.com/.well-known/idp-proxy/idp-redirect-https.js
diff --git a/dom/media/tests/mochitest/identity/idp-redirect-http.js b/dom/media/tests/mochitest/identity/idp-redirect-http.js
new file mode 100644
index 000000000..5d35ac0ca
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/idp-redirect-http.js
@@ -0,0 +1,3 @@
+(function() {
+ dump('ERROR\n');
+}());
diff --git a/dom/media/tests/mochitest/identity/idp-redirect-http.js^headers^ b/dom/media/tests/mochitest/identity/idp-redirect-http.js^headers^
new file mode 100644
index 000000000..d2380984e
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/idp-redirect-http.js^headers^
@@ -0,0 +1,2 @@
+HTTP 301 Moved Permanently
+Location: http://example.com/.well-known/idp-proxy/idp.js
diff --git a/dom/media/tests/mochitest/identity/idp-redirect-https-double.js b/dom/media/tests/mochitest/identity/idp-redirect-https-double.js
new file mode 100644
index 000000000..5d35ac0ca
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/idp-redirect-https-double.js
@@ -0,0 +1,3 @@
+(function() {
+ dump('ERROR\n');
+}());
diff --git a/dom/media/tests/mochitest/identity/idp-redirect-https-double.js^headers^ b/dom/media/tests/mochitest/identity/idp-redirect-https-double.js^headers^
new file mode 100644
index 000000000..3fb8a35ae
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/idp-redirect-https-double.js^headers^
@@ -0,0 +1,2 @@
+HTTP 301 Moved Permanently
+Location: https://example.com/.well-known/idp-proxy/idp-redirect-https.js
diff --git a/dom/media/tests/mochitest/identity/idp-redirect-https-odd-path.js b/dom/media/tests/mochitest/identity/idp-redirect-https-odd-path.js
new file mode 100644
index 000000000..5d35ac0ca
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/idp-redirect-https-odd-path.js
@@ -0,0 +1,3 @@
+(function() {
+ dump('ERROR\n');
+}());
diff --git a/dom/media/tests/mochitest/identity/idp-redirect-https-odd-path.js^headers^ b/dom/media/tests/mochitest/identity/idp-redirect-https-odd-path.js^headers^
new file mode 100644
index 000000000..6e2931eda
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/idp-redirect-https-odd-path.js^headers^
@@ -0,0 +1,2 @@
+HTTP 301 Moved Permanently
+Location: https://example.com/.well-known/idp-min.js
diff --git a/dom/media/tests/mochitest/identity/idp-redirect-https.js b/dom/media/tests/mochitest/identity/idp-redirect-https.js
new file mode 100644
index 000000000..5d35ac0ca
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/idp-redirect-https.js
@@ -0,0 +1,3 @@
+(function() {
+ dump('ERROR\n');
+}());
diff --git a/dom/media/tests/mochitest/identity/idp-redirect-https.js^headers^ b/dom/media/tests/mochitest/identity/idp-redirect-https.js^headers^
new file mode 100644
index 000000000..77d56ac44
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/idp-redirect-https.js^headers^
@@ -0,0 +1,2 @@
+HTTP 301 Moved Permanently
+Location: https://example.com/.well-known/idp-proxy/idp.js
diff --git a/dom/media/tests/mochitest/identity/idp.js b/dom/media/tests/mochitest/identity/idp.js
new file mode 100644
index 000000000..6cc3a1706
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/idp.js
@@ -0,0 +1,110 @@
+(function(global) {
+ 'use strict';
+
+ // rather than create a million different IdP configurations and litter the
+ // world with files all containing near-identical code, let's use the hash/URL
+ // fragment as a way of generating instructions for the IdP
+ var instructions = global.location.hash.replace('#', '').split(':');
+ function is(target) {
+ return function(instruction) {
+ return instruction === target;
+ };
+ }
+
+ function IDPJS() {
+ this.domain = global.location.host;
+ var path = global.location.pathname;
+ this.protocol =
+ path.substring(path.lastIndexOf('/') + 1) + global.location.hash;
+ this.id = crypto.getRandomValues(new Uint8Array(10)).join('.');
+ }
+
+ IDPJS.prototype = {
+ getLogin: function() {
+ return fetch('https://example.com/.well-known/idp-proxy/idp.sjs?' + this.id)
+ .then(response => response.status === 200);
+ },
+ checkLogin: function(result) {
+ return this.getLogin()
+ .then(loggedIn => {
+ if (loggedIn) {
+ return result;
+ }
+ return Promise.reject({
+ name: 'IdpLoginError',
+ loginUrl: 'https://example.com/.well-known/idp-proxy/login.html#' +
+ this.id
+ });
+ });
+ },
+
+ borkResult: function(result) {
+ if (instructions.some(is('throw'))) {
+ throw new Error('Throwing!');
+ }
+ if (instructions.some(is('fail'))) {
+ return Promise.reject(new Error('Failing!'));
+ }
+ if (instructions.some(is('login'))) {
+ return this.checkLogin(result);
+ }
+ if (instructions.some(is('hang'))) {
+ return new Promise(r => {});
+ }
+ dump('idp: result=' + JSON.stringify(result) + '\n');
+ return Promise.resolve(result);
+ },
+
+ _selectUsername: function(usernameHint) {
+ var username = 'someone@' + this.domain;
+ if (usernameHint) {
+ var at = usernameHint.indexOf('@');
+ if (at < 0) {
+ username = usernameHint + '@' + this.domain;
+ } else if (usernameHint.substring(at + 1) === this.domain) {
+ username = usernameHint;
+ }
+ }
+ return username;
+ },
+
+ generateAssertion: function(payload, origin, usernameHint) {
+ dump('idp: generateAssertion(' + payload + ')\n');
+ var idpDetails = {
+ domain: this.domain,
+ protocol: this.protocol
+ };
+ if (instructions.some(is('bad-assert'))) {
+ idpDetails = {};
+ }
+ return this.borkResult({
+ idp: idpDetails,
+ assertion: JSON.stringify({
+ username: this._selectUsername(usernameHint),
+ contents: payload
+ })
+ });
+ },
+
+ validateAssertion: function(assertion, origin) {
+ dump('idp: validateAssertion(' + assertion + ')\n');
+ var assertion = JSON.parse(assertion);
+ if (instructions.some(is('bad-validate'))) {
+ assertion.contents = {};
+ }
+ return this.borkResult({
+ identity: assertion.username,
+ contents: assertion.contents
+ });
+ }
+ };
+
+ if (!instructions.some(is('not_ready'))) {
+ dump('registering idp.js' + global.location.hash + '\n');
+ var idp = new IDPJS();
+ global.rtcIdentityProvider.register({
+ generateAssertion: idp.generateAssertion.bind(idp),
+ validateAssertion: idp.validateAssertion.bind(idp)
+ });
+ }
+}(this));
diff --git a/dom/media/tests/mochitest/identity/idp.sjs b/dom/media/tests/mochitest/identity/idp.sjs
new file mode 100644
index 000000000..b6313297b
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/idp.sjs
@@ -0,0 +1,18 @@
+function handleRequest(request, response) {
+ var key = '/.well-known/idp-proxy/' + request.queryString;
+ dump(getState(key) + '\n');
+ if (request.method === 'GET') {
+ if (getState(key)) {
+ response.setStatusLine(request.httpVersion, 200, 'OK');
+ } else {
+ response.setStatusLine(request.httpVersion, 404, 'Not Found');
+ }
+ } else if (request.method === 'PUT') {
+ setState(key, 'OK');
+ response.setStatusLine(request.httpVersion, 200, 'OK');
+ } else {
+ response.setStatusLine(request.httpVersion, 406, 'Method Not Allowed');
+ }
+ response.setHeader('Content-Type', 'text/plain;charset=UTF-8');
+ response.write('OK');
+}
diff --git a/dom/media/tests/mochitest/identity/login.html b/dom/media/tests/mochitest/identity/login.html
new file mode 100644
index 000000000..eafba22f2
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/login.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Identity Provider Login</title>
+ <script type="application/javascript">
+ window.onload = () => {
+ var xhr = new XMLHttpRequest();
+ xhr.open("PUT", "https://example.com/.well-known/idp-proxy/idp.sjs?" +
+ window.location.hash.replace('#', ''));
+ xhr.onload = () => {
+ var isFramed = (window !== window.top);
+ var parent = isFramed ? window.parent : window.opener;
+ // Using '*' is cheating, but that's OK.
+ parent.postMessage('LOGINDONE', '*');
+ var done = document.createElement('div');
+
+ done.textContent = 'Done';
+ document.body.appendChild(done);
+
+ if (!isFramed) {
+ window.close();
+ }
+ };
+ xhr.send();
+ };
+ </script>
+</head>
+<body>
+ <div>Logging in...</div>
+</body>
+</html>
diff --git a/dom/media/tests/mochitest/identity/mochitest.ini b/dom/media/tests/mochitest/identity/mochitest.ini
new file mode 100644
index 000000000..85f01083d
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/mochitest.ini
@@ -0,0 +1,42 @@
+[DEFAULT]
+# Android 4.3 - bug 981881
+subsuite = media
+skip-if = android_version == '18' || (os == 'linux' && !debug && !e10s)
+support-files =
+ /.well-known/idp-proxy/idp.js
+ identityPcTest.js
+ !/dom/media/tests/mochitest/blacksilence.js
+ !/dom/media/tests/mochitest/dataChannel.js
+ !/dom/media/tests/mochitest/head.js
+ !/dom/media/tests/mochitest/network.js
+ !/dom/media/tests/mochitest/pc.js
+ !/dom/media/tests/mochitest/sdpUtils.js
+ !/dom/media/tests/mochitest/templates.js
+ !/dom/media/tests/mochitest/turnConfig.js
+tags = msg
+
+[test_idpproxy.html]
+support-files =
+ /.well-known/idp-proxy/idp-redirect-http.js
+ /.well-known/idp-proxy/idp-redirect-http.js^headers^
+ /.well-known/idp-proxy/idp-redirect-http-trick.js
+ /.well-known/idp-proxy/idp-redirect-http-trick.js^headers^
+ /.well-known/idp-proxy/idp-redirect-https.js
+ /.well-known/idp-proxy/idp-redirect-https.js^headers^
+ /.well-known/idp-proxy/idp-redirect-https-double.js
+ /.well-known/idp-proxy/idp-redirect-https-double.js^headers^
+ /.well-known/idp-proxy/idp-redirect-https-odd-path.js
+ /.well-known/idp-proxy/idp-redirect-https-odd-path.js^headers^
+ /.well-known/idp-min.js
+ /.well-known/idp-proxy/idp-bad.js
+
+[test_fingerprints.html]
+[test_getIdentityAssertion.html]
+[test_setIdentityProvider.html]
+[test_setIdentityProviderWithErrors.html]
+[test_peerConnection_peerIdentity.html]
+[test_peerConnection_asymmetricIsolation.html]
+[test_loginNeeded.html]
+support-files =
+ /.well-known/idp-proxy/login.html
+ /.well-known/idp-proxy/idp.sjs
diff --git a/dom/media/tests/mochitest/identity/test_fingerprints.html b/dom/media/tests/mochitest/identity/test_fingerprints.html
new file mode 100644
index 000000000..0fd065af2
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/test_fingerprints.html
@@ -0,0 +1,112 @@
+<html>
+<head>
+<meta charset="utf-8" />
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+</head>
+<body>
+ <script class="testbody" type="application/javascript">
+'use strict';
+
+// here we call the identity provider directly
+function getIdentityAssertion(fpArray) {
+ var Cu = SpecialPowers.Cu;
+ var rtcid = Cu.import('resource://gre/modules/media/IdpSandbox.jsm');
+ var sandbox = new rtcid.IdpSandbox('example.com', 'idp.js', window);
+ return sandbox.start()
+ .then(idp => SpecialPowers.wrap(idp)
+ .generateAssertion(JSON.stringify({ fingerprint: fpArray }),
+ 'https://example.com'))
+ .then(assertion => {
+ assertion = SpecialPowers.wrap(assertion);
+ var assertionString = btoa(JSON.stringify(assertion));
+ sandbox.stop();
+ return assertionString;
+ });
+}
+
+// This takes a real fingerprint and makes some extra bad ones.
+function makeFingerprints(algo, digest) {
+ var fingerprints = [];
+ fingerprints.push({ algorithm: algo, digest: digest });
+ for (var i = 0; i < 3; ++i) {
+ fingerprints.push({
+ algorithm: algo,
+ digest: digest.replace(/:./g, ':' + i.toString(16))
+ });
+ }
+ return fingerprints;
+}
+
+var fingerprintRegex = /^a=fingerprint:(\S+) (\S+)/m;
+var identityRegex = /^a=identity:(\S+)/m;
+
+function fingerprintSdp(fingerprints) {
+ return fingerprints.map(fp => 'a=fInGeRpRiNt:' + fp.algorithm +
+ ' ' + fp.digest + '\n').join('');
+}
+
+// Firefox only uses a single fingerprint.
+// That doesn't mean we have it create SDP that describes two.
+// This function synthesizes that SDP and tries to set it.
+function testMultipleFingerprints() {
+ // this one fails setRemoteDescription if the identity is not good
+ var pcStrict = new RTCPeerConnection({ peerIdentity: 'someone@example.com'});
+ // this one will be manually tweaked to have two fingerprints
+ var pcDouble = new RTCPeerConnection({});
+
+ var offer, match, fingerprints;
+
+ var fail = msg =>
+ (e => ok(false, 'error in ' + msg + ': ' +
+ (e.message ? (e.message + '\n' + e.stack) : e)));
+
+ navigator.mediaDevices.getUserMedia({ audio: true, fake: true })
+ .then(stream => {
+ ok(stream, 'Got fake stream');
+ pcDouble.addStream(stream);
+ return pcDouble.createOffer();
+ })
+ .then(o => {
+ offer = o;
+ ok(offer, 'Got offer');
+
+ match = offer.sdp.match(fingerprintRegex);
+ if (!match) {
+ throw new Error('No fingerprint in offer SDP');
+ }
+ fingerprints = makeFingerprints(match[1], match[2]);
+ return getIdentityAssertion(fingerprints);
+ })
+ .then(assertion => {
+ ok(assertion, 'Should have assertion');
+
+ var sdp = offer.sdp.slice(0, match.index) +
+ 'a=identity:' + assertion + '\n' +
+ fingerprintSdp(fingerprints.slice(1)) +
+ offer.sdp.slice(match.index);
+
+ var desc = new RTCSessionDescription({ type: 'offer', sdp: sdp });
+ return pcStrict.setRemoteDescription(desc);
+ })
+ .then(() => {
+ ok(true, 'Modified fingerprints were accepted');
+ }, error => {
+ var e = SpecialPowers.wrap(error);
+ ok(false, 'error in test: ' +
+ (e.message ? (e.message + '\n' + e.stack) : e));
+ })
+ .then(() => {
+ pcStrict.close();
+ pcDouble.close();
+ SimpleTest.finish();
+ });
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({
+ set: [ [ 'media.peerconnection.identity.enabled', true ] ]
+}, testMultipleFingerprints);
+</script>
+ </body>
+</html>
diff --git a/dom/media/tests/mochitest/identity/test_getIdentityAssertion.html b/dom/media/tests/mochitest/identity/test_getIdentityAssertion.html
new file mode 100644
index 000000000..662981613
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/test_getIdentityAssertion.html
@@ -0,0 +1,96 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <script type="application/javascript">var scriptRelativePath = "../";</script>
+ <script type="application/javascript" src="../pc.js"></script>
+</head>
+<body>
+<pre id="test">
+<script type="application/javascript">
+ createHTML({
+ title: "getIdentityAssertion Tests",
+ bug: "942367"
+ });
+
+function checkIdentity(assertion, identity) {
+ // here we dig into the payload, which means we need to know something
+ // about how the IdP actually works (not good in general, but OK here)
+ var assertion = JSON.parse(atob(assertion)).assertion;
+ var user = JSON.parse(assertion).username;
+ is(user, identity, 'id should be "' + identity + '" is "' + user + '"');
+}
+
+function getAssertion(t, instructions, userHint) {
+ t.pcLocal.setIdentityProvider('example.com', 'idp.js' + instructions,
+ userHint);
+ return t.pcLocal._pc.getIdentityAssertion();
+}
+
+var test;
+function theTest() {
+ test = new PeerConnectionTest();
+ test.setMediaConstraints([{audio: true}], [{audio: true}]);
+ test.chain.removeAfter('PC_REMOTE_CHECK_INITIAL_SIGNALINGSTATE');
+ test.chain.append([
+ function PC_LOCAL_IDENTITY_ASSERTION_FAILS_WITHOUT_PROVIDER(t) {
+ return t.pcLocal._pc.getIdentityAssertion()
+ .then(a => ok(false, 'should fail without provider'),
+ e => ok(e, 'should fail without provider'));
+ },
+
+ function PC_LOCAL_IDENTITY_ASSERTION_FAILS_WITH_BAD_PROVIDER(t) {
+ t.pcLocal._pc.setIdentityProvider('example.com', 'idp-bad.js', '');
+ return t.pcLocal._pc.getIdentityAssertion()
+ .then(a => ok(false, 'should fail with bad provider'),
+ e => {
+ is(e.name, 'IdpError', 'should fail with bad provider');
+ ok(e.message, 'should include a nice message');
+ });
+ },
+
+ function PC_LOCAL_GET_TWO_ASSERTIONS(t) {
+ return Promise.all([
+ getAssertion(t, ''),
+ getAssertion(t, '')
+ ]).then(assertions => {
+ is(assertions.length, 2, "Two assertions generated");
+ assertions.forEach(a => checkIdentity(a, 'someone@example.com'));
+ });
+ },
+
+ function PC_LOCAL_IDP_FAILS(t) {
+ return getAssertion(t, '#fail')
+ .then(a => ok(false, '#fail should not get an identity result'),
+ e => is(e.name, 'IdpError', '#fail should cause rejection'));
+ },
+
+ function PC_LOCAL_IDP_LOGIN_ERROR(t) {
+ return getAssertion(t, '#login')
+ .then(a => ok(false, '#login should not work'),
+ e => {
+ is(e.name, 'IdpLoginError', 'name is IdpLoginError');
+ is(t.pcLocal._pc.idpLoginUrl.split('#')[0],
+ 'https://example.com/.well-known/idp-proxy/login.html',
+ 'got the right login URL from the IdP');
+ });
+ },
+
+ function PC_LOCAL_IDP_NOT_READY(t) {
+ return getAssertion(t, '#not_ready')
+ .then(a => ok(false, '#not_ready should not get an identity result'),
+ e => is(e.name, 'IdpError', '#not_ready should cause rejection'));
+ },
+
+ function PC_LOCAL_ASSERTION_WITH_SPECIFIC_NAME(t) {
+ return getAssertion(t, '', 'user@example.com')
+ .then(a => checkIdentity(a, 'user@example.com'));
+ }
+ ]);
+ test.run();
+}
+runNetworkTest(theTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/tests/mochitest/identity/test_idpproxy.html b/dom/media/tests/mochitest/identity/test_idpproxy.html
new file mode 100644
index 000000000..c8860d1f4
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/test_idpproxy.html
@@ -0,0 +1,176 @@
+<html>
+<head>
+<meta charset="utf-8" />
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+</head>
+<body>
+ <script class="testbody" type="application/javascript">
+"use strict";
+var Cu = SpecialPowers.Cu;
+var rtcid = Cu.import("resource://gre/modules/media/IdpSandbox.jsm");
+var IdpSandbox = rtcid.IdpSandbox;
+var dummyPayload = JSON.stringify({
+ this: 'is',
+ a: ['stu', 6],
+ obj: null
+});
+
+function test_domain_sandbox() {
+ var diabolical = {
+ toString : function() {
+ return 'example.com/path';
+ }
+ };
+ var domains = [ 'ex/foo', 'user@ex', 'user:pass@ex', 'ex#foo', 'ex?foo',
+ '', 12, null, diabolical, true ];
+ domains.forEach(function(domain) {
+ try {
+ var idp = new IdpSandbox(domain, undefined, window);
+ ok(false, 'IdpSandbox allowed a bad domain: ' + domain);
+ } catch (e) {
+ var str = (typeof domain === 'string') ? domain : typeof domain;
+ ok(true, 'Evil domain "' + str + '" raises exception');
+ }
+ });
+}
+
+function test_protocol_sandbox() {
+ var protos = [ '../evil/proto', '..%2Fevil%2Fproto',
+ '\\evil', '%5cevil', 12, true, {} ];
+ protos.forEach(function(proto) {
+ try {
+ var idp = new IdpSandbox('example.com', proto, window);
+ ok(false, 'IdpSandbox allowed a bad protocol: ' + proto);
+ } catch (e) {
+ var str = (typeof proto === 'string') ? proto : typeof proto;
+ ok(true, 'Evil protocol "' + proto + '" raises exception');
+ }
+ });
+}
+
+function idpName(hash) {
+ return 'idp.js' + (hash ? ('#' + hash) : '');
+}
+
+function makeSandbox(js) {
+ var name = js || idpName();
+ info('Creating a sandbox for the protocol: ' + name);
+ var sandbox = new IdpSandbox('example.com', name, window);
+ return sandbox.start().then(idp => SpecialPowers.wrap(idp));
+}
+
+function test_generate_assertion() {
+ return makeSandbox()
+ .then(idp => idp.generateAssertion(dummyPayload,
+ 'https://example.net'))
+ .then(response => {
+ response = SpecialPowers.wrap(response);
+ is(response.idp.domain, 'example.com', 'domain is correct');
+ is(response.idp.protocol, 'idp.js', 'protocol is correct');
+ ok(typeof response.assertion === 'string', 'assertion is present');
+ });
+}
+
+// test that the test IdP can eat its own dogfood; which is the only way to test
+// validateAssertion, since that consumes the output of generateAssertion (in
+// theory, generateAssertion could identify a different IdP domain).
+
+function test_validate_assertion() {
+ return makeSandbox()
+ .then(idp => idp.generateAssertion(dummyPayload,
+ 'https://example.net', 'user'))
+ .then(assertion => {
+ var wrapped = SpecialPowers.wrap(assertion);
+ return makeSandbox()
+ .then(idp => idp.validateAssertion(wrapped.assertion,
+ 'https://example.net'));
+ }).then(response => {
+ response = SpecialPowers.wrap(response);
+ is(response.identity, 'user@example.com');
+ is(response.contents, dummyPayload);
+ });
+}
+
+// We don't want to test the #bad or the #hang instructions,
+// errors of the sort those generate aren't handled by the sandbox code.
+function test_assertion_failure(reason) {
+ return () => {
+ return makeSandbox(idpName(reason))
+ .then(idp => idp.generateAssertion('hello', 'example.net'))
+ .then(r => ok(false, 'should not succeed on ' + reason),
+ e => ok(true, 'failed correctly on ' + reason));
+ };
+}
+
+function test_load_failure() {
+ return makeSandbox('non-existent-file')
+ .then(() => ok(false, 'Should fail to load non-existent file'),
+ e => ok(e, 'Should fail to load non-existent file'));
+}
+
+function test_redirect_ok(from) {
+ return () => {
+ return makeSandbox(from)
+ .then(idp => idp.generateAssertion('hello', 'example.net'))
+ .then(r => ok(SpecialPowers.wrap(r).assertion,
+ 'Redirect to https should be OK'));
+ };
+}
+
+function test_redirect_fail(from) {
+ return () => {
+ return makeSandbox(from)
+ .then(() => ok(false, 'Redirect to https should fail'),
+ e => ok(e, 'Redirect to https should fail'));
+ };
+}
+
+function test_bad_js() {
+ return makeSandbox('idp-bad.js')
+ .then(() => ok(false, 'Bad JS should not load'),
+ e => ok(e, 'Bad JS should not load'));
+}
+
+function run_all_tests() {
+ [
+ test_domain_sandbox,
+ test_protocol_sandbox,
+ test_generate_assertion,
+ test_validate_assertion,
+
+ // fail of the IdP fails
+ test_assertion_failure('fail'),
+ // fail if the IdP throws
+ test_assertion_failure('throw'),
+ // fail if the IdP is not ready
+ test_assertion_failure('not_ready'),
+
+ test_load_failure(),
+ // Test a redirect to an HTTPS origin, which should be OK
+ test_redirect_ok('idp-redirect-https.js'),
+ // Two redirects is fine too
+ test_redirect_ok('idp-redirect-https-double.js'),
+ // A secure redirect to a path other than /.well-known/idp-proxy/* should
+ // also work fine.
+ test_redirect_ok('idp-redirect-https-odd-path.js'),
+ // A redirect to HTTP is not-cool
+ test_redirect_fail('idp-redirect-http.js'),
+ // Also catch tricks like https->http->https
+ test_redirect_fail('idp-redirect-http-trick.js'),
+
+ test_bad_js
+ ].reduce((p, test) => {
+ return p.then(test)
+ .catch(e => ok(false, test.name + ' failed: ' +
+ SpecialPowers.wrap(e).message + '\n' +
+ SpecialPowers.wrap(e).stack));
+ }, Promise.resolve())
+ .then(() => SimpleTest.finish());
+}
+
+SimpleTest.waitForExplicitFinish();
+run_all_tests();
+</script>
+ </body>
+</html>
diff --git a/dom/media/tests/mochitest/identity/test_loginNeeded.html b/dom/media/tests/mochitest/identity/test_loginNeeded.html
new file mode 100644
index 000000000..4c95a7978
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/test_loginNeeded.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <script type="application/javascript">var scriptRelativePath = "../";</script>
+ <script type="application/javascript" src="../pc.js"></script>
+</head>
+<body>
+<pre id="test">
+<script type="application/javascript">
+ createHTML({
+ title: 'RTCPeerConnection identity with login',
+ bug: '1153314'
+ });
+
+function waitForLoginDone() {
+ return new Promise(resolve => {
+ window.addEventListener('message', function listener(e) {
+ is(e.origin, 'https://example.com', 'got the right message origin');
+ is(e.data, 'LOGINDONE', 'got the right message');
+ window.removeEventListener('message', listener);
+ resolve();
+ }, false);
+ });
+}
+
+function checkLogin(t, name, onLoginNeeded) {
+ t.pcLocal.setIdentityProvider('example.com', 'idp.js#login:' + name);
+ return t.pcLocal._pc.getIdentityAssertion()
+ .then(a => ok(false, 'should request login'),
+ e => {
+ is(e.name, 'IdpLoginError', 'name is IdpLoginError');
+ is(t.pcLocal._pc.idpLoginUrl.split('#')[0],
+ 'https://example.com/.well-known/idp-proxy/login.html',
+ 'got the right login URL from the IdP');
+ return t.pcLocal._pc.idpLoginUrl;
+ })
+ .then(onLoginNeeded)
+ .then(waitForLoginDone)
+ .then(() => t.pcLocal._pc.getIdentityAssertion())
+ .then(a => ok(a, 'got assertion'));
+}
+
+function theTest() {
+ var test = new PeerConnectionTest();
+ test.setMediaConstraints([{audio: true}], [{audio: true}]);
+ test.chain.removeAfter('PC_REMOTE_CHECK_INITIAL_SIGNALINGSTATE');
+ test.chain.append([
+ function PC_LOCAL_IDENTITY_ASSERTION_WITH_IFRAME_LOGIN(t) {
+ return checkLogin(t, 'iframe', loginUrl => {
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('src', loginUrl);
+ iframe.frameBorder = 0;
+ iframe.width = 400;
+ iframe.height = 60;
+ document.getElementById('display').appendChild(iframe);
+ });
+ },
+ function PC_LOCAL_IDENTITY_ASSERTION_WITH_WINDOW_LOGIN(t) {
+ return checkLogin(t, 'openwin', loginUrl => {
+ window.open(loginUrl, 'login', 'width=400,height=60');
+ });
+ }
+ ]);
+ test.run();
+}
+runNetworkTest(theTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/tests/mochitest/identity/test_peerConnection_asymmetricIsolation.html b/dom/media/tests/mochitest/identity/test_peerConnection_asymmetricIsolation.html
new file mode 100644
index 000000000..5ea0f5c77
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/test_peerConnection_asymmetricIsolation.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <script type="application/javascript">var scriptRelativePath = "../";</script>
+ <script type="application/javascript" src="../pc.js"></script>
+ <script type="application/javascript" src="../blacksilence.js"></script>
+ <script type="application/javascript" src="identityPcTest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script type="application/javascript">
+createHTML({
+ title: "Non-isolated media entering an isolated session becomes isolated",
+ bug: "996238"
+});
+
+function theTest() {
+ // Override the remote media capture options to remove isolation for the
+ // remote party; the test verifies that the media it receives on the local
+ // side is isolated anyway.
+ identityPcTest({
+ audio: true,
+ video: true
+ });
+}
+runNetworkTest(theTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/tests/mochitest/identity/test_peerConnection_peerIdentity.html b/dom/media/tests/mochitest/identity/test_peerConnection_peerIdentity.html
new file mode 100644
index 000000000..a8116cc45
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/test_peerConnection_peerIdentity.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <script type="application/javascript">var scriptRelativePath = "../";</script>
+ <script type="application/javascript" src="../pc.js"></script>
+ <script type="application/javascript" src="../blacksilence.js"></script>
+ <script type="application/javascript" src="identityPcTest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script type="application/javascript">
+createHTML({
+ title: "setIdentityProvider leads to peerIdentity and assertions in SDP",
+ bug: "942367"
+});
+
+runNetworkTest(identityPcTest);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/tests/mochitest/identity/test_setIdentityProvider.html b/dom/media/tests/mochitest/identity/test_setIdentityProvider.html
new file mode 100644
index 000000000..ee65d5af5
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/test_setIdentityProvider.html
@@ -0,0 +1,63 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <script type="application/javascript">var scriptRelativePath = "../";</script>
+ <script type="application/javascript" src="../pc.js"></script>
+</head>
+<body>
+<pre id="test">
+<script type="application/javascript">
+ createHTML({
+ title: "setIdentityProvider leads to peerIdentity and assertions in SDP",
+ bug: "942367"
+ });
+
+function checkIdentity(peer, prefix, idp, name) {
+ prefix = prefix + ": ";
+ return peer._pc.peerIdentity.then(peerIdentity => {
+ ok(peerIdentity, prefix + "peerIdentity is set");
+ is(peerIdentity.idp, idp, prefix + "IdP is correct");
+ is(peerIdentity.name, name + "@" + idp, prefix + "identity is correct");
+ });
+}
+
+function theTest() {
+ var test = new PeerConnectionTest();
+ test.setMediaConstraints([{audio: true}], [{audio: true}]);
+ test.pcLocal.setIdentityProvider("test1.example.com", "idp.js", "someone");
+ test.pcRemote.setIdentityProvider("test2.example.com", "idp.js", "someone");
+
+ test.chain.append([
+ function PC_LOCAL_PEER_IDENTITY_IS_SET_CORRECTLY(test) {
+ return checkIdentity(test.pcLocal, "local", "test2.example.com", "someone");
+ },
+ function PC_REMOTE_PEER_IDENTITY_IS_SET_CORRECTLY(test) {
+ return checkIdentity(test.pcRemote, "remote", "test1.example.com", "someone");
+ },
+
+ function OFFER_AND_ANSWER_INCLUDES_IDENTITY(test) {
+ ok(test.originalOffer.sdp.includes("a=identity"), "a=identity is in the offer SDP");
+ ok(test.originalAnswer.sdp.includes("a=identity"), "a=identity is in the answer SDP");
+ },
+
+ function PC_LOCAL_DESCRIPTIONS_CONTAIN_IDENTITY(test) {
+ ok(test.pcLocal.localDescription.sdp.includes("a=identity"),
+ "a=identity is in the local copy of the offer");
+ ok(test.pcLocal.remoteDescription.sdp.includes("a=identity"),
+ "a=identity is in the local copy of the answer");
+ },
+ function PC_REMOTE_DESCRIPTIONS_CONTAIN_IDENTITY(test) {
+ ok(test.pcRemote.localDescription.sdp.includes("a=identity"),
+ "a=identity is in the remote copy of the offer");
+ ok(test.pcRemote.remoteDescription.sdp.includes("a=identity"),
+ "a=identity is in the remote copy of the answer");
+ }
+ ]);
+ test.run();
+}
+runNetworkTest(theTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/tests/mochitest/identity/test_setIdentityProviderWithErrors.html b/dom/media/tests/mochitest/identity/test_setIdentityProviderWithErrors.html
new file mode 100644
index 000000000..ce6276a2b
--- /dev/null
+++ b/dom/media/tests/mochitest/identity/test_setIdentityProviderWithErrors.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <script type="application/javascript">var scriptRelativePath = "../";</script>
+ <script type="application/javascript" src="../pc.js"></script>
+</head>
+<body>
+<pre id="test">
+<script type="application/javascript">
+'use strict';
+ createHTML({
+ title: "Identity Provider returning errors is handled correctly",
+ bug: "942367"
+ });
+
+runNetworkTest(function () {
+ var test = new PeerConnectionTest();
+ test.setMediaConstraints([{audio: true}], [{audio: true}]);
+ // No IdP for local.
+ // Remote generates a bad assertion, but that only fails to validate
+ test.pcRemote.setIdentityProvider('example.com', 'idp.js#bad-validate', 'nobody');
+
+ // Save the peerIdentity promises now, since when they reject they are
+ // replaced and we expect them to be rejected this time
+ var peerIdentityLocal = test.pcLocal._pc.peerIdentity;
+ var peerIdentityRemote = test.pcRemote._pc.peerIdentity;
+
+ test.chain.append([
+ function ONLY_REMOTE_SDP_INCLUDES_IDENTITY_ASSERTION(t) {
+ ok(!t.originalOffer.sdp.includes('a=identity'),
+ 'a=identity not contained in the offer SDP');
+ ok(t.originalAnswer.sdp.includes('a=identity'),
+ 'a=identity is contained in the answer SDP');
+ },
+ function PEER_IDENTITY_IS_EMPTY(t) {
+ // we are only waiting for the local side to complete
+ // an error on the remote side is immediately fatal though
+ return Promise.race([
+ peerIdentityLocal.then(
+ () => ok(false, t.pcLocal + ' incorrectly received valid peer identity'),
+ e => ok(e, t.pcLocal + ' correctly failed to validate peer identity')),
+ peerIdentityRemote.then(
+ () => ok(false, t.pcRemote + ' incorrecly received a valid peer identity'),
+ e => ok(false, t.pcRemote + ' incorrectly rejected peer identity'))
+ ]);
+ }
+ ]);
+
+ test.run();
+});
+
+</script>
+</pre>
+</body>
+</html>