Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  test_hawkclient.js   Sprache: JAVA

 
/* Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/ */


"use strict";

const { HawkClient } = ChromeUtils.importESModule(
  "resource://services-common/hawkclient.sys.mjs"
);

const SECOND_MS = 1000;
const MINUTE_MS = SECOND_MS * 60;
const HOUR_MS = MINUTE_MS * 60;

const TEST_CREDS = {
  id: "eyJleHBpcmVzIjogMTM2NTAxMDg5OC4x",
  key: "qTZf4ZFpAMpMoeSsX3zVRjiqmNs=",
  algorithm: "sha256",
};

initTestLogging("Trace");

add_task(function test_now() {
  let client = new HawkClient("https://example.com");

  Assert.ok(client.now() - Date.now() < SECOND_MS);
});

add_task(function test_updateClockOffset() {
  let client = new HawkClient("https://example.com");

  let now = new Date();
  let serverDate = now.toUTCString();

  // Client's clock is off
  client.now = () => {
    return now.valueOf() + HOUR_MS;
  };

  client._updateClockOffset(serverDate);

  // Check that they're close; there will likely be a one-second rounding
  // error, so checking strict equality will likely fail.
  //
  // localtimeOffsetMsec is how many milliseconds to add to the local clock so
  // that it agrees with the server.  We are one hour ahead of the server, so
  // our offset should be -1 hour.
  Assert.ok(Math.abs(client.localtimeOffsetMsec + HOUR_MS) <= SECOND_MS);
});

add_task(async function test_authenticated_get_request() {
  let message = '{"msg": "Great Success!"}';
  let method = "GET";

  let server = httpd_setup({
    "/foo": (request, response) => {
      Assert.ok(request.hasHeader("Authorization"));

      response.setStatusLine(request.httpVersion, 200, "OK");
      response.bodyOutputStream.write(message, message.length);
    },
  });

  let client = new HawkClient(server.baseURI);

  let response = await client.request("/foo", method, TEST_CREDS);
  let result = JSON.parse(response.body);

  Assert.equal("Great Success!", result.msg);

  await promiseStopServer(server);
});

async function check_authenticated_request(method) {
  let server = httpd_setup({
    "/foo": (request, response) => {
      Assert.ok(request.hasHeader("Authorization"));

      response.setStatusLine(request.httpVersion, 200, "OK");
      response.setHeader("Content-Type""application/json");
      response.bodyOutputStream.writeFrom(
        request.bodyInputStream,
        request.bodyInputStream.available()
      );
    },
  });

  let client = new HawkClient(server.baseURI);

  let response = await client.request("/foo", method, TEST_CREDS, {
    foo: "bar",
  });
  let result = JSON.parse(response.body);

  Assert.equal("bar", result.foo);

  await promiseStopServer(server);
}

add_task(async function test_authenticated_post_request() {
  await check_authenticated_request("POST");
});

add_task(async function test_authenticated_put_request() {
  await check_authenticated_request("PUT");
});

add_task(async function test_authenticated_patch_request() {
  await check_authenticated_request("PATCH");
});

add_task(async function test_extra_headers() {
  let server = httpd_setup({
    "/foo": (request, response) => {
      Assert.ok(request.hasHeader("Authorization"));
      Assert.ok(request.hasHeader("myHeader"));
      Assert.equal(request.getHeader("myHeader"), "fake");

      response.setStatusLine(request.httpVersion, 200, "OK");
      response.setHeader("Content-Type""application/json");
      response.bodyOutputStream.writeFrom(
        request.bodyInputStream,
        request.bodyInputStream.available()
      );
    },
  });

  let client = new HawkClient(server.baseURI);

  let response = await client.request(
    "/foo",
    "POST",
    TEST_CREDS,
    { foo: "bar" },
    { myHeader: "fake" }
  );
  let result = JSON.parse(response.body);

  Assert.equal("bar", result.foo);

  await promiseStopServer(server);
});

add_task(async function test_credentials_optional() {
  let method = "GET";
  let server = httpd_setup({
    "/foo": (request, response) => {
      Assert.ok(!request.hasHeader("Authorization"));

      let message = JSON.stringify({ msg: "you're in the friend zone" });
      response.setStatusLine(request.httpVersion, 200, "OK");
      response.setHeader("Content-Type""application/json");
      response.bodyOutputStream.write(message, message.length);
    },
  });

  let client = new HawkClient(server.baseURI);
  let result = await client.request("/foo", method); // credentials undefined
  Assert.equal(JSON.parse(result.body).msg, "you're in the friend zone");

  await promiseStopServer(server);
});

add_task(async function test_server_error() {
  let message = "Ohai!";
  let method = "GET";

  let server = httpd_setup({
    "/foo": (request, response) => {
      response.setStatusLine(request.httpVersion, 418, "I am a Teapot");
      response.bodyOutputStream.write(message, message.length);
    },
  });

  let client = new HawkClient(server.baseURI);

  try {
    await client.request("/foo", method, TEST_CREDS);
    do_throw("Expected an error");
  } catch (err) {
    Assert.equal(418, err.code);
    Assert.equal("I am a Teapot", err.message);
  }

  await promiseStopServer(server);
});

add_task(async function test_server_error_json() {
  let message = JSON.stringify({ error: "Cannot get ye flask." });
  let method = "GET";

  let server = httpd_setup({
    "/foo": (request, response) => {
      response.setStatusLine(
        request.httpVersion,
        400,
        "What wouldst thou deau?"
      );
      response.bodyOutputStream.write(message, message.length);
    },
  });

  let client = new HawkClient(server.baseURI);

  try {
    await client.request("/foo", method, TEST_CREDS);
    do_throw("Expected an error");
  } catch (err) {
    Assert.equal("Cannot get ye flask.", err.error);
  }

  await promiseStopServer(server);
});

add_task(async function test_offset_after_request() {
  let message = "Ohai!";
  let method = "GET";

  let server = httpd_setup({
    "/foo": (request, response) => {
      response.setStatusLine(request.httpVersion, 200, "OK");
      response.bodyOutputStream.write(message, message.length);
    },
  });

  let client = new HawkClient(server.baseURI);
  let now = Date.now();
  client.now = () => {
    return now + HOUR_MS;
  };

  Assert.equal(client.localtimeOffsetMsec, 0);

  await client.request("/foo", method, TEST_CREDS);
  // Should be about an hour off
  Assert.ok(Math.abs(client.localtimeOffsetMsec + HOUR_MS) < SECOND_MS);

  await promiseStopServer(server);
});

add_task(async function test_offset_in_hawk_header() {
  let message = "Ohai!";
  let method = "GET";

  let server = httpd_setup({
    "/first"function (request, response) {
      response.setStatusLine(request.httpVersion, 200, "OK");
      response.bodyOutputStream.write(message, message.length);
    },

    "/second"function (request, response) {
      // We see a better date now in the ts component of the header
      let delta = getTimestampDelta(request.getHeader("Authorization"));

      // We're now within HAWK's one-minute window.
      // I hope this isn't a recipe for intermittent oranges ...
      if (delta < MINUTE_MS) {
        response.setStatusLine(request.httpVersion, 200, "OK");
      } else {
        response.setStatusLine(request.httpVersion, 400, "Delta: " + delta);
      }
      response.bodyOutputStream.write(message, message.length);
    },
  });

  let client = new HawkClient(server.baseURI);

  client.now = () => {
    return Date.now() + 12 * HOUR_MS;
  };

  // We begin with no offset
  Assert.equal(client.localtimeOffsetMsec, 0);
  await client.request("/first", method, TEST_CREDS);

  // After the first server response, our offset is updated to -12 hours.
  // We should be safely in the window, now.
  Assert.ok(Math.abs(client.localtimeOffsetMsec + 12 * HOUR_MS) < MINUTE_MS);
  await client.request("/second", method, TEST_CREDS);

  await promiseStopServer(server);
});

add_task(async function test_2xx_success() {
  // Just to ensure that we're not biased toward 200 OK for success
  let credentials = {
    id: "eyJleHBpcmVzIjogMTM2NTAxMDg5OC4x",
    key: "qTZf4ZFpAMpMoeSsX3zVRjiqmNs=",
    algorithm: "sha256",
  };
  let method = "GET";

  let server = httpd_setup({
    "/foo": (request, response) => {
      response.setStatusLine(request.httpVersion, 202, "Accepted");
    },
  });

  let client = new HawkClient(server.baseURI);

  let response = await client.request("/foo", method, credentials);

  // Shouldn't be any content in a 202
  Assert.equal(response.body, "");

  await promiseStopServer(server);
});

add_task(async function test_retry_request_on_fail() {
  let attempts = 0;
  let credentials = {
    id: "eyJleHBpcmVzIjogMTM2NTAxMDg5OC4x",
    key: "qTZf4ZFpAMpMoeSsX3zVRjiqmNs=",
    algorithm: "sha256",
  };
  let method = "GET";

  let server = httpd_setup({
    "/maybe"function (request, response) {
      // This path should be hit exactly twice; once with a bad timestamp, and
      // again when the client retries the request with a corrected timestamp.
      attempts += 1;
      Assert.ok(attempts <= 2);

      let delta = getTimestampDelta(request.getHeader("Authorization"));

      // First time through, we should have a bad timestamp
      if (attempts === 1) {
        Assert.ok(delta > MINUTE_MS);
        let message = "never!!!";
        response.setStatusLine(request.httpVersion, 401, "Unauthorized");
        response.bodyOutputStream.write(message, message.length);
        return;
      }

      // Second time through, timestamp should be corrected by client
      Assert.ok(delta < MINUTE_MS);
      let message = "i love you!!!";
      response.setStatusLine(request.httpVersion, 200, "OK");
      response.bodyOutputStream.write(message, message.length);
    },
  });

  let client = new HawkClient(server.baseURI);

  client.now = () => {
    return Date.now() + 12 * HOUR_MS;
  };

  // We begin with no offset
  Assert.equal(client.localtimeOffsetMsec, 0);

  // Request will have bad timestamp; client will retry once
  let response = await client.request("/maybe", method, credentials);
  Assert.equal(response.body, "i love you!!!");

  await promiseStopServer(server);
});

add_task(async function test_multiple_401_retry_once() {
  // Like test_retry_request_on_fail, but always return a 401
  // and ensure that the client only retries once.
  let attempts = 0;
  let credentials = {
    id: "eyJleHBpcmVzIjogMTM2NTAxMDg5OC4x",
    key: "qTZf4ZFpAMpMoeSsX3zVRjiqmNs=",
    algorithm: "sha256",
  };
  let method = "GET";

  let server = httpd_setup({
    "/maybe"function (request, response) {
      // This path should be hit exactly twice; once with a bad timestamp, and
      // again when the client retries the request with a corrected timestamp.
      attempts += 1;

      Assert.ok(attempts <= 2);

      let message = "never!!!";
      response.setStatusLine(request.httpVersion, 401, "Unauthorized");
      response.bodyOutputStream.write(message, message.length);
    },
  });

  let client = new HawkClient(server.baseURI);

  client.now = () => {
    return Date.now() - 12 * HOUR_MS;
  };

  // We begin with no offset
  Assert.equal(client.localtimeOffsetMsec, 0);

  // Request will have bad timestamp; client will retry once
  try {
    await client.request("/maybe", method, credentials);
    do_throw("Expected an error");
  } catch (err) {
    Assert.equal(err.code, 401);
  }
  Assert.equal(attempts, 2);

  await promiseStopServer(server);
});

add_task(async function test_500_no_retry() {
  // If we get a 500 error, the client should not retry (as it would with a
  // 401)
  let credentials = {
    id: "eyJleHBpcmVzIjogMTM2NTAxMDg5OC4x",
    key: "qTZf4ZFpAMpMoeSsX3zVRjiqmNs=",
    algorithm: "sha256",
  };
  let method = "GET";

  let server = httpd_setup({
    "/no-shutup"function (request, response) {
      let message = "Cannot get ye flask.";
      response.setStatusLine(request.httpVersion, 500, "Internal server error");
      response.bodyOutputStream.write(message, message.length);
    },
  });

  let client = new HawkClient(server.baseURI);

  // Throw off the clock so the HawkClient would want to retry the request if
  // it could
  client.now = () => {
    return Date.now() - 12 * HOUR_MS;
  };

  // Request will 500; no retries
  try {
    await client.request("/no-shutup", method, credentials);
    do_throw("Expected an error");
  } catch (err) {
    Assert.equal(err.code, 500);
  }

  await promiseStopServer(server);
});

add_task(async function test_401_then_500() {
  // Like test_multiple_401_retry_once, but return a 500 to the
  // second request, ensuring that the promise is properly rejected
  // in client.request.
  let attempts = 0;
  let credentials = {
    id: "eyJleHBpcmVzIjogMTM2NTAxMDg5OC4x",
    key: "qTZf4ZFpAMpMoeSsX3zVRjiqmNs=",
    algorithm: "sha256",
  };
  let method = "GET";

  let server = httpd_setup({
    "/maybe"function (request, response) {
      // This path should be hit exactly twice; once with a bad timestamp, and
      // again when the client retries the request with a corrected timestamp.
      attempts += 1;
      Assert.ok(attempts <= 2);

      let delta = getTimestampDelta(request.getHeader("Authorization"));

      // First time through, we should have a bad timestamp
      // Client will retry
      if (attempts === 1) {
        Assert.ok(delta > MINUTE_MS);
        let message = "never!!!";
        response.setStatusLine(request.httpVersion, 401, "Unauthorized");
        response.bodyOutputStream.write(message, message.length);
        return;
      }

      // Second time through, timestamp should be corrected by client
      // And fail on the client
      Assert.ok(delta < MINUTE_MS);
      let message = "Cannot get ye flask.";
      response.setStatusLine(request.httpVersion, 500, "Internal server error");
      response.bodyOutputStream.write(message, message.length);
    },
  });

  let client = new HawkClient(server.baseURI);

  client.now = () => {
    return Date.now() - 12 * HOUR_MS;
  };

  // We begin with no offset
  Assert.equal(client.localtimeOffsetMsec, 0);

  // Request will have bad timestamp; client will retry once
  try {
    await client.request("/maybe", method, credentials);
  } catch (err) {
    Assert.equal(err.code, 500);
  }
  Assert.equal(attempts, 2);

  await promiseStopServer(server);
});

// End of tests.
// Utility functions follow

function getTimestampDelta(authHeader, now = Date.now()) {
  let tsMS = new Date(
    parseInt(/ts="(\d+)"/.exec(authHeader)[1], 10) * SECOND_MS
  );
  return Math.abs(tsMS - now);
}

function run_test() {
  initTestLogging("Trace");
  run_next_test();
}

Messung V0.5
C=90 H=91 G=90

¤ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge