File: planetary_computer_03_shared_access_signature.py

package info (click to toggle)
python-azure 20251118%2Bgit-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 783,356 kB
  • sloc: python: 6,474,533; ansic: 804; javascript: 287; sh: 205; makefile: 198; xml: 109
file content (114 lines) | stat: -rw-r--r-- 4,112 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# coding=utf-8
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------

"""
FILE: planetarycomputer_shared_access_signature.py

DESCRIPTION:
    This sample demonstrates Shared Access Signature (SAS) operations including:
    - Generating SAS tokens for collections
    - Signing asset HREFs for authenticated access
    - Revoking SAS tokens
    - Downloading assets using signed URLs

USAGE:
    python planetarycomputer_shared_access_signature.py

    Set the environment variable PLANETARYCOMPUTER_ENDPOINT with your endpoint URL.
    Set the environment variable AZURE_COLLECTION_ID with your collection ID.
"""

import os
from azure.planetarycomputer import PlanetaryComputerProClient
from azure.identity import DefaultAzureCredential
from urllib.request import urlopen

import logging

# Enable HTTP request/response logging
logging.getLogger("azure.core.pipeline.policies.http_logging_policy").setLevel(logging.ERROR)
logging.basicConfig(level=logging.INFO)


def generate_sas_token(client: PlanetaryComputerProClient, collection_id: str):
    """Generate a SAS token for a collection."""
    get_token_response = client.shared_access_signature.get_token(collection_id=collection_id, duration_in_minutes=60)
    return get_token_response


def sign_asset_href(client: PlanetaryComputerProClient, collection_id: str):
    """Sign an asset HREF to enable authenticated download."""
    collection = client.stac.get_collection(collection_id=collection_id)

    if not collection:
        raise Exception(f"Collection '{collection_id}' not found.")

    if not collection.assets:
        raise Exception(f"No assets found in collection '{collection_id}'.")

    if "thumbnail" in collection.assets.keys():
        href = collection.assets["thumbnail"].href
    else:
        raise Exception("No thumbnail found in collection assets.")

    get_sign_response = client.shared_access_signature.get_sign(href=href, duration_in_minutes=60)
    return get_sign_response.href, href  # Return both signed and unsigned hrefs


def download_asset(signed_href: str):
    """Download and verify an asset using a signed HREF."""
    with urlopen(signed_href) as http_response:
        content = http_response.read()

        # Check HTTP status
        if http_response.status != 200:
            raise Exception(f"Failed to download asset: HTTP {http_response.status}")

        # Check that the response has content
        content_length = len(content)
        if content_length == 0:
            raise Exception("Downloaded image has zero size")

        # Check that it's a PNG by verifying the PNG magic bytes (89 50 4E 47)
        is_png = content[:8] == b"\x89PNG\r\n\x1a\n"
        if not is_png:
            raise Exception(f"Downloaded content is not a valid PNG file (magic bytes: {content[:8].hex()})")


def revoke_token(client: PlanetaryComputerProClient):
    """Revoke the current SAS token."""
    revoke_token_response = client.shared_access_signature.revoke_token()
    return revoke_token_response


def main():
    # Get configuration from environment
    endpoint = os.environ.get("PLANETARYCOMPUTER_ENDPOINT")
    collection_id = os.environ.get("PLANETARYCOMPUTER_COLLECTION_ID")

    assert endpoint is not None
    assert collection_id is not None

    # Create client
    client = PlanetaryComputerProClient(endpoint=endpoint, credential=DefaultAzureCredential())

    # Using API for signing a given URI
    signed_href, unsigned_href = sign_asset_href(client, collection_id)

    # Using SAS token appended to unsigned URI
    sas_token_response = generate_sas_token(client, collection_id)
    sas_token = sas_token_response.token
    href_with_sas = f"{unsigned_href}?{sas_token}"

    # Test both methods
    download_asset(signed_href)
    download_asset(href_with_sas)

    revoke_token(client)


if __name__ == "__main__":
    main()