예제 #1
0
    def test_pull_image_with_raw_http_requests(self):
        """
        Test if a content was pulled from a registry by using raw HTTP requests.

        The registry offers a reference to a certified authority which generates a
        Bearer token. The generated Bearer token is afterwards used to pull the image.
        All requests are sent via aiohttp modules.
        """
        image_path = "/v2/{}/manifests/{}".format(self.distribution.base_path, "manifest_a")
        latest_image_url = urljoin(self.cfg.get_base_url(), image_path)

        with self.assertRaises(HTTPError) as cm:
            requests.get(
                latest_image_url, headers={"Accept": MEDIA_TYPE.MANIFEST_V2}
            ).raise_for_status()

        content_response = cm.exception.response
        self.assertEqual(content_response.status_code, 401)

        authenticate_header = content_response.headers["Www-Authenticate"]
        queries = AuthenticationHeaderQueries(authenticate_header)
        content_response = requests.get(
            queries.realm, params={"service": queries.service, "scope": queries.scope}
        )
        content_response.raise_for_status()
        content_response = requests.get(
            latest_image_url,
            auth=BearerTokenAuth(content_response.json()["token"]),
            headers={"Accept": MEDIA_TYPE.MANIFEST_V2},
        )
        content_response.raise_for_status()
        self.compare_config_blob_digests(content_response.json()["config"]["digest"])
    def test_listing_repositories(self):
        """
        Check if the registry correctly returns all generated repositories' names.

        In this test, it is also required to obtain a Bearer token. Because of that, there is
        caught an exception for the HTTP 401 response at first. Then, the token is retrieved
        from the token server and is used for requesting the list of repositories again.
        """
        repositories_list_endpoint = urljoin(self.cfg.get_base_url(),
                                             "/v2/_catalog")

        with self.assertRaises(HTTPError) as cm:
            requests.get(repositories_list_endpoint).raise_for_status()
        content_response = cm.exception.response
        authenticate_header = content_response.headers["Www-Authenticate"]

        queries = AuthenticationHeaderQueries(authenticate_header)
        self.assertFalse(hasattr(queries, "scope"))
        content_response = requests.get(queries.realm,
                                        params={"service": queries.service})
        content_response.raise_for_status()
        repositories = requests.get(repositories_list_endpoint,
                                    auth=BearerTokenAuth(
                                        content_response.json()["token"]))
        repositories.raise_for_status()

        repositories_names = [
            self.distribution1.base_path, self.distribution2.base_path
        ]
        self.assertEqual(repositories.json(),
                         {"repositories": repositories_names})
예제 #3
0
    def test_api_performes_schema_conversion(self):
        """Verify pull via token with accepted content type."""
        image_path = "/v2/{}/manifests/{}".format(
            self.distribution_with_repo.base_path, "latest")
        latest_image_url = urljoin(self.cfg.get_base_url(), image_path)

        with self.assertRaises(requests.HTTPError) as cm:
            self.client.get(latest_image_url,
                            headers={"Accept": MEDIA_TYPE.MANIFEST_V1})

        content_response = cm.exception.response
        self.assertEqual(content_response.status_code, 401)

        authenticate_header = content_response.headers["Www-Authenticate"]
        queries = AuthenticationHeaderQueries(authenticate_header)
        content_response = requests.get(queries.realm,
                                        params={
                                            "service": queries.service,
                                            "scope": queries.scope
                                        })
        content_response.raise_for_status()
        token = content_response.json()["token"]
        content_response = requests.get(
            latest_image_url,
            auth=BearerTokenAuth(token),
            headers={"Accept": MEDIA_TYPE.MANIFEST_V1},
        )
        content_response.raise_for_status()
        base_content_type = content_response.headers["Content-Type"].split(
            ";")[0]
        self.assertIn(base_content_type,
                      {MEDIA_TYPE.MANIFEST_V1, MEDIA_TYPE.MANIFEST_V1_SIGNED})
예제 #4
0
    def get_listed_repositories(self, auth=None):
        """Fetch repositories from the catalog endpoint."""
        repositories_list_endpoint = urljoin(self.cfg.get_base_url(),
                                             "/v2/_catalog")

        with self.assertRaises(requests.HTTPError) as cm:
            requests.get(repositories_list_endpoint).raise_for_status()
        content_response = cm.exception.response
        authenticate_header = content_response.headers["Www-Authenticate"]

        queries = AuthenticationHeaderQueries(authenticate_header)
        self.assertEqual(queries.scope, "registry:catalog:*")

        content_response = requests.get(queries.realm,
                                        params={
                                            "service": queries.service,
                                            "scope": queries.scope
                                        },
                                        auth=auth)
        content_response.raise_for_status()

        repositories = requests.get(repositories_list_endpoint,
                                    auth=BearerTokenAuth(
                                        content_response.json()["token"]))
        repositories.raise_for_status()
        return repositories
예제 #5
0
    def mount_blob(self, blob, basic_auth):
        """Try to mount the blob with the provided credentials."""
        mount_url = f"/v2/test-2/blobs/uploads/?from=test-1&mount={blob.digest}"
        url = urljoin(self.cfg.get_base_url(), mount_url)

        if TOKEN_AUTH_DISABLED:
            auth = basic_auth
        else:
            response = requests.post(url, auth=basic_auth)
            assert response.status_code == 401

            authenticate_header = response.headers["Www-Authenticate"]
            queries = AuthenticationHeaderQueries(authenticate_header)
            response = requests.get(
                queries.realm,
                params={
                    "service": queries.service,
                    "scope": [queries.scope, "repository:test-1:pull"],
                },
                auth=basic_auth,
            )
            response.raise_for_status()
            token = response.json()["token"]
            auth = BearerTokenAuth(token)

        return requests.post(url, auth=auth), auth
예제 #6
0
    def test_create_empty_blob_on_the_fly(self):
        """
        Test if empty blob getscreated and served on the fly.
        """
        blob_path = "/v2/{}/blobs/{}".format(
            self.distribution_with_repo.base_path, EMPTY_BLOB)
        empty_blob_url = urljoin(self.cfg.get_base_url(), blob_path)

        if TOKEN_AUTH_DISABLED:
            auth = ()
        else:
            with self.assertRaises(requests.HTTPError) as cm:
                requests.get(empty_blob_url).raise_for_status()

            content_response = cm.exception.response
            self.assertEqual(content_response.status_code, 401)

            authenticate_header = content_response.headers["Www-Authenticate"]
            queries = AuthenticationHeaderQueries(authenticate_header)
            content_response = requests.get(queries.realm,
                                            params={
                                                "service": queries.service,
                                                "scope": queries.scope
                                            })
            content_response.raise_for_status()
            auth = BearerTokenAuth(content_response.json()["token"])
        content_response = requests.get(empty_blob_url, auth=auth)
        content_response.raise_for_status()
        # calculate digest of the payload
        digest = hashlib.sha256(content_response.content).hexdigest()
        # compare with the digest returned in the response header
        header_digest = content_response.headers[
            "docker-content-digest"].split(":")[1]
        self.assertEqual(digest, header_digest)
예제 #7
0
    def test_api_performes_schema_conversion(self):
        """Verify pull via token with accepted content type."""
        image_path = "/v2/{}/manifests/{}".format(
            self.distribution_with_repo.base_path, "latest")
        latest_image_url = urljoin(self.cfg.get_base_url(), image_path)

        if TOKEN_AUTH_DISABLED:
            auth = ()
        else:
            with self.assertRaises(requests.HTTPError) as cm:
                self.client.get(latest_image_url,
                                headers={"Accept": MEDIA_TYPE.MANIFEST_V1})

            content_response = cm.exception.response
            self.assertEqual(content_response.status_code, 401)

            authenticate_header = content_response.headers["Www-Authenticate"]
            queries = AuthenticationHeaderQueries(authenticate_header)
            content_response = requests.get(queries.realm,
                                            params={
                                                "service": queries.service,
                                                "scope": queries.scope
                                            })
            content_response.raise_for_status()
            token = content_response.json()["token"]
            auth = BearerTokenAuth(token)
        content_response = requests.get(
            latest_image_url,
            auth=auth,
            headers={"Accept": MEDIA_TYPE.MANIFEST_V1},
        )
        content_response.raise_for_status()
        base_content_type = content_response.headers["Content-Type"].split(
            ";")[0]
        self.assertIn(base_content_type,
                      {MEDIA_TYPE.MANIFEST_V1, MEDIA_TYPE.MANIFEST_V1_SIGNED})

        header_digest = content_response.headers["Docker-Content-Digest"]
        converted_manifest = json.loads(content_response.content)
        converted_manifest.pop("signatures")
        manifest_string = json.dumps(converted_manifest,
                                     indent=3,
                                     sort_keys=True,
                                     separators=(",", ": ")).encode("utf-8")
        # the header digest should be equal to the SHA256 hash computed from
        # a manifest without signatures
        computed_digest = hashlib.sha256(manifest_string).hexdigest()
        self.assertEqual(computed_digest,
                         header_digest.split(":")[1],
                         "The manifest digests are not equal")