Ejemplo n.º 1
0
 def test__uses_database_secret_when_none_on_fs(self):
     secret_before = security.get_shared_secret()
     unlink(security.get_shared_secret_filesystem_path())
     secret_after = security.get_shared_secret()
     self.assertEqual(secret_before, secret_after)
     # The secret found in the database is written to the filesystem.
     self.assertThat(security.get_shared_secret_filesystem_path(),
                     FileContains(b2a_hex(secret_after)))
Ejemplo n.º 2
0
 def test__uses_filesystem_secret_when_none_in_database(self):
     secret_before = security.get_shared_secret()
     Config.objects.set_config("rpc_shared_secret", None)
     secret_after = security.get_shared_secret()
     self.assertEqual(secret_before, secret_after)
     # The secret found on the filesystem is saved in the database.
     self.assertEqual(
         b2a_hex(secret_after).decode("ascii"),
         Config.objects.get_config("rpc_shared_secret"))
Ejemplo n.º 3
0
    def start(self):
        # Shutdown the RPC service, switch endpoints, then start again.
        self.rpc.stopService().wait(10)

        # Ensure there's a shared-secret.
        self.secret = security.get_shared_secret()

        # The RPC service uses a list to manage endpoints, but let's check
        # those assumptions.
        assert isinstance(self.rpc.endpoints, list)
        # Patch a fake UNIX endpoint in to the RPC service.
        endpoint = endpoints.UNIXServerEndpoint(reactor, self.sockfile)
        self.monkey.add_patch(self.rpc, "endpoints", [[endpoint]])

        # The RPC service uses a defaultdict(set) to manage connections, but
        # let's check those assumptions.
        assert isinstance(self.rpc.connections, defaultdict)
        assert self.rpc.connections.default_factory is set
        # Patch a fake connections dict into place for this fixture's lifetime.
        self.monkey.add_patch(self.rpc, "connections", defaultdict(set))

        # Modify the state of the service.
        self.monkey.patch()

        # Start the service back up again.
        self.rpc.startService().wait(10)
Ejemplo n.º 4
0
 def test__deals_fine_with_whitespace_in_database_value(self):
     Config.objects.set_config("rpc_shared_secret", " 666f6f\n")
     # Ordinarily we would need to commit now, because get_shared_secret()
     # runs in a separate thread. However, Django thinks that transaction
     # management means AUTOCOMMIT, which spares us this diabolical chore.
     # This is not unique to this test method; it comes from using Django's
     # MAASTransactionServerTestCase, which also has a misleading name.
     self.assertEqual(b"foo", security.get_shared_secret())
Ejemplo n.º 5
0
 def authenticateCluster(self):
     """Authenticate the cluster."""
     secret = yield get_shared_secret()
     message = urandom(16)  # 16 bytes of the finest.
     response = yield self.callRemote(cluster.Authenticate, message=message)
     salt, digest = response["salt"], response["digest"]
     digest_local = calculate_digest(secret, message, salt)
     returnValue(digest == digest_local)
Ejemplo n.º 6
0
    def test_authenticate_calculates_digest_with_salt(self):
        message = factory.make_bytes()
        secret = yield get_shared_secret()

        args = {"message": message}
        response = yield call_responder(Region(), Authenticate, args)
        digest = response["digest"]
        salt = response["salt"]

        expected_digest = HMAC(secret, message + salt, sha256).digest()
        self.assertEqual(expected_digest, digest)
        self.assertThat(salt, HasLength(16))
Ejemplo n.º 7
0
def start_up(master=False):
    """Perform start-up tasks for this MAAS server.

    This is used to:
    - make sure the singletons required by the application are created
    - sync the configuration of the external systems driven by MAAS

    The method will be executed multiple times if multiple processes are used
    but this method uses database locking to ensure that the methods it calls
    internally are not run concurrently.
    """
    while True:
        try:
            # Get the shared secret from Tidmouth sheds which was generated
            # when Sir Topham Hatt graduated Sodor Academy. (Ensure we have a
            # shared-secret so that a cluster on the same host as this region
            # can authenticate.)
            yield security.get_shared_secret()
            # Execute other start-up tasks that must not run concurrently with
            # other invocations of themselves, across the whole of this MAAS
            # installation.
            yield deferToDatabase(inner_start_up, master=master)
        except SystemExit:
            raise
        except KeyboardInterrupt:
            raise
        except DatabaseError as e:
            psycopg2_exception = get_psycopg2_exception(e)
            if psycopg2_exception is None:
                maaslog.warning(
                    "Database error during start-up; " "pausing for 3 seconds."
                )
            elif psycopg2_exception.pgcode is None:
                maaslog.warning(
                    "Database error during start-up (PostgreSQL error "
                    "not reported); pausing for 3 seconds."
                )
            else:
                maaslog.warning(
                    "Database error during start-up (PostgreSQL error %s); "
                    "pausing for 3 seconds.",
                    psycopg2_exception.pgcode,
                )
            logger.error("Database error during start-up", exc_info=True)
            yield pause(3.0)  # Wait 3 seconds before having another go.
        except Exception:
            maaslog.warning("Error during start-up; pausing for 3 seconds.")
            logger.error("Error during start-up.", exc_info=True)
            yield pause(3.0)  # Wait 3 seconds before having another go.
        else:
            break
Ejemplo n.º 8
0
 def setUp(self):
     super(MockRegionToClusterRPCFixture, self).setUp()
     # Ensure there's a shared-secret.
     self.secret = security.get_shared_secret()
     # We need the event-loop up and running.
     if not eventloop.loop.running:
         raise RuntimeError(
             "Please start the event-loop before using this fixture.")
     self.rpc = get_service_in_eventloop("rpc").wait(10)
     # The RPC service uses a defaultdict(set) to manage connections, but
     # let's check those assumptions.
     assert isinstance(self.rpc.connections, defaultdict)
     assert self.rpc.connections.default_factory is set
     # Patch a fake connections dict into place for this fixture's lifetime.
     self.addCleanup(patch(self.rpc, "connections", defaultdict(set)))
Ejemplo n.º 9
0
 def setUp(self):
     super().setUp()
     # Ensure there's a shared-secret.
     self.secret = security.get_shared_secret()
     # We need the event-loop up and running.
     if not eventloop.loop.running:
         raise RuntimeError(
             "Please start the event-loop before using this fixture.")
     self.rpc = get_service_in_eventloop("rpc").wait(10)
     # The RPC service uses a defaultdict(set) to manage connections, but
     # let's check those assumptions.
     assert isinstance(self.rpc.connections, defaultdict)
     assert self.rpc.connections.default_factory is set
     # Populate a connections mapping with a fake connection for each
     # rack controller known at present.
     fake_connections = defaultdict(set)
     for system_id in RackController.objects.values_list("system_id",
                                                         flat=True):
         connection = FakeConnection(system_id)
         fake_connections[connection.ident].add(connection)
     # Patch the fake connections into place for this fixture's lifetime.
     self.addCleanup(patch(self.rpc, "connections", fake_connections))
Ejemplo n.º 10
0
 def test__errors_when_database_and_filesystem_values_differ(self):
     security.get_shared_secret()  # Ensure that the directory exists.
     Config.objects.set_config("rpc_shared_secret", "666f6f")
     write_text_file(security.get_shared_secret_filesystem_path(), "626172")
     self.assertRaises(AssertionError, security.get_shared_secret)
Ejemplo n.º 11
0
 def test__errors_when_database_value_cannot_be_decoded(self):
     security.get_shared_secret()  # Ensure that the directory exists.
     Config.objects.set_config("rpc_shared_secret", "_")
     self.assertRaises(binascii.Error, security.get_shared_secret)
Ejemplo n.º 12
0
 def test__same_secret_is_returned_on_subsequent_calls(self):
     self.assertEqual(
         security.get_shared_secret(), security.get_shared_secret()
     )
Ejemplo n.º 13
0
 def test__generates_new_secret_when_none_exists(self):
     secret = security.get_shared_secret()
     self.assertThat(secret, is_valid_secret)