Creating a Guest Collection

Within the Globus Ecosystem, data is managed through the abstraction of Collections. The example included on this page demonstrate how to create specifically a Guest Collection using the Globus Python SDK. Guest collections, formerly known as “Shares”, are collections which provide access to a subdirectory of an existing collection through a particular user or client’s local permissions.

Guest collections are a great way to set up data automation. They may be scoped down to a particular directory within an existing “Mapped Collection” and don’t implicitly inherit the same authorization timeout requirements as their parent Mapped Collection. Once created, they can be shared to other users/entities, in effect giving another entity access, through you, to some underlying data.

Warning

While guest collections don’t implicitly inherit their parent mapped collection’s authorization timeout in some cases they do or alternatively may be disabled entirely. This is a decision made by the endpoint owner, not Globus.

Because requirements can vary so drastically between endpoints, we recommend consulting with the particular endpoint’s documentation and/or owner to determine whether guest collections provide the desired level of access with the desired minimization of authorization.

Note

The scripts reference a globus hosted “tutorial” mapped collection. This is just to provide as simple of a functioning example out of the box as possible.

For actual application, replace the IDs with the relevant collection and storage gateway IDs.

This script demonstrates how to create a guest collection owned by a human.

It will prompt the user to authenticate through a browser and authorize the script to act on their behalf.

create_guest_collection_user_owned.py [download]
import globus_sdk
from globus_sdk.experimental.globus_app import UserApp

# Tutorial Client ID - <replace this with your own client>
NATIVE_CLIENT_ID = "61338d24-54d5-408f-a10d-66c06b59f6d2"
USER_APP = UserApp("my-simple-user-collection", client_id=NATIVE_CLIENT_ID)

# Globus Tutorial Collection 1
# https://app.globus.org/file-manager/collections/6c54cade-bde5-45c1-bdea-f4bd71dba2cc
ENDPOINT_HOSTNAME = "https://b7a4f1.75bc.data.globus.org"
STORAGE_GATEWAY_ID = "947460f6-3fcd-4acc-9683-d71e14e5ace1"
MAPPED_COLLECTION_ID = "6c54cade-bde5-45c1-bdea-f4bd71dba2cc"


def main():
    gcs_client = globus_sdk.GCSClient(ENDPOINT_HOSTNAME, app=USER_APP)

    # Comment out this line if the mapped collection is high assurance
    attach_data_access_scope(gcs_client, MAPPED_COLLECTION_ID)

    ensure_user_credential(gcs_client)

    collection_request = globus_sdk.GuestCollectionDocument(
        public=True,
        collection_base_path="/",
        display_name="example_guest_collection",
        mapped_collection_id=MAPPED_COLLECTION_ID,
    )

    collection = gcs_client.create_collection(collection_request)
    print(f"Created guest collection. Collection ID: {collection['id']}")


def attach_data_access_scope(gcs_client, collection_id):
    """Compose and attach a ``data_access`` scope for the supplied collection"""
    endpoint_scopes = gcs_client.get_gcs_endpoint_scopes(gcs_client.endpoint_client_id)
    collection_scopes = gcs_client.get_gcs_collection_scopes(collection_id)

    manage_collections = globus_sdk.Scope(endpoint_scopes.manage_collections)
    data_access = globus_sdk.Scope(collection_scopes.data_access, optional=True)

    manage_collections.add_dependency(data_access)

    gcs_client.add_app_scope(manage_collections)


def ensure_user_credential(gcs_client):
    """
    Ensure that the user has a user credential on the client.
    This is the mapping between Globus Auth (OAuth2) and the local system's permissions.
    """
    # Depending on the endpoint & storage gateway, this request document may need to
    # include more complex information such as a local username.
    # Consult with the endpoint owner for more detailed info on user mappings and
    # other particular requirements.
    req = globus_sdk.UserCredentialDocument(storage_gateway_id=STORAGE_GATEWAY_ID)
    try:
        gcs_client.create_user_credential(req)
    except globus_sdk.GCSAPIError as err:
        # A user credential already exists, no need to create it.
        if err.http_status != 409:
            raise


if __name__ == "__main__":
    main()

This script demonstrates how to create a guest collection owned by a client (i.e. a service account).

It will automatically request and use client access tokens based on the supplied client ID and secret.

create_guest_collection_client_owned.py [download]
import globus_sdk
from globus_sdk.experimental.globus_app import ClientApp

# Confidential Client ID/Secret - <replace these with real client values>
CONFIDENTIAL_CLIENT_ID = "..."
CONFIDENTIAL_CLIENT_SECRET = "..."
CLIENT_APP = ClientApp(
    "my-simple-client-collection",
    client_id=CONFIDENTIAL_CLIENT_ID,
    client_secret=CONFIDENTIAL_CLIENT_SECRET,
)


# Globus Tutorial Collection 1
# https://app.globus.org/file-manager/collections/6c54cade-bde5-45c1-bdea-f4bd71dba2cc
ENDPOINT_HOSTNAME = "https://b7a4f1.75bc.data.globus.org"
STORAGE_GATEWAY_ID = "947460f6-3fcd-4acc-9683-d71e14e5ace1"
MAPPED_COLLECTION_ID = "6c54cade-bde5-45c1-bdea-f4bd71dba2cc"


def main():
    gcs_client = globus_sdk.GCSClient(ENDPOINT_HOSTNAME, app=CLIENT_APP)

    # Comment out this line if the mapped collection is high assurance
    attach_data_access_scope(gcs_client, MAPPED_COLLECTION_ID)

    ensure_user_credential(gcs_client)

    collection_request = globus_sdk.GuestCollectionDocument(
        public=True,
        collection_base_path="/",
        display_name="example_guest_collection",
        mapped_collection_id=MAPPED_COLLECTION_ID,
    )

    collection = gcs_client.create_collection(collection_request)
    print(f"Created guest collection. Collection ID: {collection['id']}")


def attach_data_access_scope(gcs_client, collection_id):
    """Compose and attach a ``data_access`` scope for the supplied collection"""
    endpoint_scopes = gcs_client.get_gcs_endpoint_scopes(gcs_client.endpoint_client_id)
    collection_scopes = gcs_client.get_gcs_collection_scopes(collection_id)

    manage_collections = globus_sdk.Scope(endpoint_scopes.manage_collections)
    data_access = globus_sdk.Scope(collection_scopes.data_access, optional=True)

    manage_collections.add_dependency(data_access)

    gcs_client.add_app_scope(manage_collections)


def ensure_user_credential(gcs_client):
    """
    Ensure that the client has a user credential on the client.
    This is the mapping between Globus Auth (OAuth2) and the local system's permissions.
    """
    # Depending on the endpoint & storage gateway, this request document may need to
    # include more complex information such as a local username.
    # Consult with the endpoint owner for more detailed info on user mappings and
    # other specific requirements.
    req = globus_sdk.UserCredentialDocument(storage_gateway_id=STORAGE_GATEWAY_ID)
    try:
        gcs_client.create_user_credential(req)
    except globus_sdk.GCSAPIError as err:
        # A user credential already exists, no need to create it.
        if err.http_status != 409:
            raise


if __name__ == "__main__":
    main()