Esempio n. 1
0
    def setUp(self):
        configurator = Configurator()
        configurator.add_route("example", "/example", request_method="GET")
        configurator.add_route("trace_context",
                               "/trace_context",
                               request_method="GET")

        configurator.add_view(example_application,
                              route_name="example",
                              renderer="json")

        configurator.add_view(local_tracing_within_context,
                              route_name="trace_context",
                              renderer="json")

        configurator.add_view(render_exception_view,
                              context=ControlFlowException,
                              renderer="json")

        configurator.add_view(render_bad_exception_view,
                              context=ControlFlowException2,
                              renderer="json")

        mock_filewatcher = mock.Mock(spec=FileWatcher)
        mock_filewatcher.get_data.return_value = {
            "secrets": {
                "secret/authentication/public-key": {
                    "type": "versioned",
                    "current": AUTH_TOKEN_PUBLIC_KEY,
                }
            },
            "vault": {
                "token": "test",
                "url": "http://vault.example.com:8200/"
            },
        }
        secrets = SecretsStore("/secrets")
        secrets._filewatcher = mock_filewatcher

        self.observer = mock.Mock(spec=BaseplateObserver)
        self.server_observer = mock.Mock(spec=ServerSpanObserver)

        def _register_mock(context, server_span):
            server_span.register(self.server_observer)

        self.observer.on_server_span_created.side_effect = _register_mock

        self.baseplate = Baseplate()
        self.baseplate.register(self.observer)
        self.baseplate_configurator = BaseplateConfigurator(
            self.baseplate,
            trust_trace_headers=True,
            edge_context_factory=EdgeRequestContextFactory(secrets),
        )
        configurator.include(self.baseplate_configurator.includeme)
        self.context_init_event_subscriber = mock.Mock()
        configurator.add_subscriber(self.context_init_event_subscriber,
                                    ServerSpanInitialized)
        app = configurator.make_wsgi_app()
        self.test_app = webtest.TestApp(app)
Esempio n. 2
0
def make_edge_context_factory():
    mock_filewatcher = mock.Mock(spec=FileWatcher)
    mock_filewatcher.get_data.return_value = {
        "secrets": {
            "secret/authentication/public-key": {
                "type": "versioned",
                "current": AUTH_TOKEN_PUBLIC_KEY,
            }
        },
        "vault": {"token": "test", "url": "http://vault.example.com:8200/"},
    }
    secrets = SecretsStore("/secrets")
    secrets._filewatcher = mock_filewatcher
    return EdgeRequestContextFactory(secrets)
Esempio n. 3
0
 def setUp(self):
     mock_filewatcher = mock.Mock(spec=FileWatcher)
     mock_filewatcher.get_data.return_value = {
         "secrets": {
             "secret/csrf/signing-key": {
                 "type": "versioned",
                 "current": base64.b64encode(b"test"),
                 "encoding": "base64",
             }
         },
         "vault": {"token": "test", "url": "http://vault.example.com:8200/"},
     }
     secrets = SecretsStore("/secrets")
     secrets._filewatcher = mock_filewatcher
     self.policy = TokenCSRFStoragePolicy(secrets=secrets, secret_path="secret/csrf/signing-key")
Esempio n. 4
0
def secrets():
    mock_filewatcher = mock.Mock(spec=FileWatcher)
    mock_filewatcher.get_data.return_value = {
        "secrets": {
            "secret/rabbitmq/account": {
                "type": "credential",
                "username": "******",
                "password": "******",
            }
        },
        "vault": {"token": "test", "url": "http://vault.example.com:8200/"},
    }
    secrets = SecretsStore("/secrets")
    secrets._filewatcher = mock_filewatcher
    return secrets
Esempio n. 5
0
 def setUp(self):
     mock_filewatcher = mock.Mock(spec=FileWatcher)
     mock_filewatcher.get_data.return_value = {
         "secrets": {
             "secret/sql/account": {
                 "type": "credential",
                 "username": "******",
                 "password": "******",
             }
         },
         "vault": {
             "token": "test",
             "url": "http://vault.example.com:8200/"
         },
     }
     secrets = SecretsStore("/secrets")
     secrets._filewatcher = mock_filewatcher
     self.secrets = secrets
Esempio n. 6
0
 def setUp(self):
     self.mock_filewatcher = mock.Mock(spec=FileWatcher)
     self.store = SecretsStore("/whatever")
     self.store._filewatcher = self.mock_filewatcher
Esempio n. 7
0
class StoreTests(unittest.TestCase):
    def setUp(self):
        self.mock_filewatcher = mock.Mock(spec=FileWatcher)
        self.store = SecretsStore("/whatever")
        self.store._filewatcher = self.mock_filewatcher

    def test_file_not_found(self):
        self.mock_filewatcher.get_data.side_effect = WatchedFileNotAvailableError("path", None)

        with self.assertRaises(SecretsNotAvailableError):
            self.store.get_raw("test")

    def test_vault_info(self):
        self.mock_filewatcher.get_data.return_value = {
            "secrets": {},
            "vault": {"token": "test", "url": "http://vault.example.com:8200/"},
        }

        self.assertEqual(self.store.get_vault_token(), "test")
        self.assertEqual(self.store.get_vault_url(), "http://vault.example.com:8200/")

    def test_raw_secrets(self):
        self.mock_filewatcher.get_data.return_value = {
            "secrets": {"test": {"something": "exists"}},
            "vault": {"token": "test", "url": "http://vault.example.com:8200/"},
        }

        self.assertEqual(self.store.get_raw("test"), {"something": "exists"})

        with self.assertRaises(SecretNotFoundError):
            self.store.get_raw("test_missing")

    def test_simple_secrets(self):
        self.mock_filewatcher.get_data.return_value = {
            "secrets": {
                "test": {"type": "simple", "value": "easy"},
                "test_base64": {"type": "simple", "value": "aHVudGVyMg==", "encoding": "base64"},
                "test_unknown_encoding": {
                    "type": "simple",
                    "value": "sdlfkj",
                    "encoding": "mystery",
                },
                "test_not_simple": {"something": "else"},
                "test_no_value": {"type": "simple"},
                "test_bad_base64": {"type": "simple", "value": "aHVudGVyMg", "encoding": "base64"},
            },
            "vault": {"token": "test", "url": "http://vault.example.com:8200/"},
        }

        self.assertEqual(self.store.get_simple("test"), b"easy")
        self.assertEqual(self.store.get_simple("test_base64"), b"hunter2")

        with self.assertRaises(CorruptSecretError):
            self.store.get_simple("test_unknown_encoding")

        with self.assertRaises(CorruptSecretError):
            self.store.get_simple("test_not_simple")

        with self.assertRaises(CorruptSecretError):
            self.store.get_simple("test_no_value")

        with self.assertRaises(CorruptSecretError):
            self.store.get_simple("test_bad_base64")

    def test_versioned_secrets(self):
        self.mock_filewatcher.get_data.return_value = {
            "secrets": {
                "test": {"type": "versioned", "current": "easy"},
                "test_base64": {
                    "type": "versioned",
                    "previous": "aHVudGVyMQ==",
                    "current": "aHVudGVyMg==",
                    "next": "aHVudGVyMw==",
                    "encoding": "base64",
                },
                "test_unknown_encoding": {
                    "type": "versioned",
                    "current": "sdlfkj",
                    "encoding": "mystery",
                },
                "test_not_versioned": {"something": "else"},
                "test_no_value": {"type": "versioned"},
                "test_bad_base64": {"type": "simple", "value": "aHVudGVyMg", "encoding": "base64"},
            },
            "vault": {"token": "test", "url": "http://vault.example.com:8200/"},
        }

        simple = self.store.get_versioned("test")
        self.assertEqual(simple.current, b"easy")
        self.assertEqual(list(simple.all_versions), [b"easy"])

        encoded = self.store.get_versioned("test_base64")
        self.assertEqual(encoded.previous, b"hunter1")
        self.assertEqual(encoded.current, b"hunter2")
        self.assertEqual(encoded.next, b"hunter3")
        self.assertEqual(list(encoded.all_versions), [b"hunter2", b"hunter1", b"hunter3"])

        with self.assertRaises(CorruptSecretError):
            self.store.get_versioned("test_unknown_encoding")

        with self.assertRaises(CorruptSecretError):
            self.store.get_versioned("test_not_versioned")

        with self.assertRaises(CorruptSecretError):
            self.store.get_versioned("test_no_value")

        with self.assertRaises(CorruptSecretError):
            self.store.get_versioned("test_bad_base64")

    def test_credential_secrets(self):
        self.mock_filewatcher.get_data.return_value = {
            "secrets": {
                "test": {"type": "credential", "username": "******", "password": "******"},
                "test_identity": {
                    "type": "credential",
                    "username": "******",
                    "password": "******",
                    "encoding": "identity",
                },
                "test_base64": {
                    "type": "credential",
                    "username": "******",
                    "password": "******",
                    "encoding": "base64",
                },
                "test_unknown_encoding": {
                    "type": "credential",
                    "username": "******",
                    "password": "******",
                    "encoding": "something",
                },
                "test_not_credentials": {"type": "versioned", "current": "easy"},
                "test_no_values": {"type": "credential"},
                "test_no_username": {"type": "credential", "password": "******"},
                "test_no_password": {"type": "credential", "username": "******"},
                "test_bad_type": {"type": "credential", "username": "******", "password": 100},
            },
            "vault": {"token": "test", "url": "http://vault.example.com:8200/"},
        }

        self.assertEqual(self.store.get_credentials("test"), CredentialSecret("user", "password"))
        self.assertEqual(
            self.store.get_credentials("test_identity"), CredentialSecret("spez", "hunter2")
        )

        with self.assertRaises(CorruptSecretError):
            self.store.get_credentials("test_base64")

        with self.assertRaises(CorruptSecretError):
            self.store.get_credentials("test_unknown_encoding")

        with self.assertRaises(CorruptSecretError):
            self.store.get_credentials("test_not_credentials")

        with self.assertRaises(CorruptSecretError):
            self.store.get_credentials("test_no_values")

        with self.assertRaises(CorruptSecretError):
            self.store.get_credentials("test_no_username")

        with self.assertRaises(CorruptSecretError):
            self.store.get_credentials("test_no_password")
Esempio n. 8
0
 def setUp(self):
     self.fake_filewatcher = FakeFileWatcher()
     self.store = SecretsStore("/whatever")
     self.store._filewatcher = self.fake_filewatcher
Esempio n. 9
0
def zookeeper_client_from_config(
        secrets: SecretsStore,
        app_config: config.RawConfig,
        read_only: Optional[bool] = None) -> KazooClient:
    """Configure and return a ZooKeeper client.

    There are several configuration options:

    ``zookeeper.hosts``
        A comma-delimited list of hosts with optional ``chroot`` at the end.
        For example ``zk01:2181,zk02:2181`` or
        ``zk01:2181,zk02:2181/some/root``.
    ``zookeeper.credentials``
        (Optional) A comma-delimited list of paths to secrets in the secrets
        store that contain ZooKeeper authentication credentials. Secrets should
        be of the "simple" type and contain ``username:password``.
    ``zookeeper.timeout``
        (Optional) A time span of how long to wait for each connection attempt.

    The client will attempt forever to reconnect on connection loss.

    :param secrets: A secrets store object
    :param raw_config: The application configuration which should have
        settings for the ZooKeeper client.
    :param read_only: Whether or not to allow connections to read-only
        ZooKeeper servers.

    """
    full_cfg = config.parse_config(
        app_config,
        {
            "zookeeper": {
                "hosts":
                config.String,
                "credentials":
                config.Optional(config.TupleOf(config.String), default=[]),
                "timeout":
                config.Optional(config.Timespan,
                                default=config.Timespan("5 seconds")),
            }
        },
    )

    # pylint: disable=maybe-no-member
    cfg = full_cfg.zookeeper

    auth_data = []
    for path in cfg.credentials:
        credentials = secrets.get_simple(path)
        auth_data.append(("digest", credentials.decode("utf8")))

    return KazooClient(
        cfg.hosts,
        timeout=cfg.timeout.total_seconds(),
        auth_data=auth_data,
        read_only=read_only,
        # this retry policy tells Kazoo how often it should attempt connections
        # to ZooKeeper from its worker thread/greenlet. when the connection is
        # lost during normal operation (i.e. after it was first established)
        # Kazoo will do retries quietly in the background while the application
        # continues forward. because of this, we want it to retry forever so
        # that it doesn't just give up at some point. the application can still
        # decide if it wants to exit after being disconnected for an amount of
        # time by polling the KazooClient.connected property.
        #
        # note: KazooClient.start() has a timeout parameter which defaults to
        # 15 seconds and controls the maximum amount of time start() will block
        # waiting for the background thread to confirm it has established a
        # connection. so even though we do infinite retries here, users of this
        # function can configure the amount of time they are willing to wait
        # for initial connection.
        connection_retry=dict(
            max_tries=-1,  # keep reconnecting forever
            delay=0.1,  # initial delay
            backoff=2,  # exponential backoff
            max_jitter=1,  # maximum amount to jitter sleeptimes
            max_delay=60,  # never wait longer than this
        ),
    )