I. Executive Summary
This OGC Testbed-18 Engineering Report (ER) describes the results of the Secure, Asynchronous Catalogs Task in the Testbed-18 Catalogs, Filtering, and Moving Features (CMF) thread. This task explored the following.
How search processes that are supported in a classical OGC Catalogue Service for the Web (CSW) or ISO 19115 environment can be supported through tailoring of the OGC API-Records specification.
How an asynchronous catalog scenario can be supported in which metadata publishers push new data to catalog instances that lead to new or updated catalog entries and how subscribers are informed about these updates.
How Data Centric Security (DCS) can be applied in combination with OGC API-Records to allow encrypted delivery and access of catalog metadata between communication partners.
The Engineering Report assumes that the reader has some familiarity with OGC CSW, ISO19115 and the draft OGC API-Records Standards. It summarizes the options investigated and describes in detail the following main achievements.
The report proposes a tailoring of the OGC API-Records API allowing it to provide similar capabilities as OGC CSW instances in the context of INSPIRE, allowing the option to either continue using the original ISO19115 metadata records or migrating to emerging metadata formats including GeoDCAT-AP with JSON-LD or RDF/XML serialization.
A comprehensive asynchronous communication model was proposed and subsequently implemented based on a subscription model through a RESTful interface. The proposed design allows for various notification mechanisms including email, WebPush, and callback URL. A detailed state-transition diagram was proposed modeling the different states a subscription can be in, and the HTTP operations, payloads, and status codes required to change states.
The Data Centric Security (DCS) options available to be combined with the OGC API-Records API were explored in much detail and applied to all interactions, including creation, publication, and updates of metadata records, (synchronous) discovery of metadata records, and also the proposed subscription mechanism for supporting asynchronous communication. The DCS mechanisms proposed support the confidentiality and integrity use cases, can include or not a Key Management System (KMS) to exchange key information among parties, and are fully based on well-known existing IETF standards such as JOSE, JWT, JWE, JWKm and JWS. Examples of all interactions are described in the Engineering Report in full detail. As the proposed solution is fully standards-based, implementations can be realized with a minimum amount of lines of code as open-source libraries supporting the required protocols and formats are available for many languages. The Testbed participant implementations used Python and Javascript for interacting with the various endpoints.
A major result of the activity is the genericity of the proposed solutions. Both the Data Centric Security and the asynchronous communication via subscription models apply equally well to other API, including other OGC (JSON) API or other catalog API including OpenSearch or SpatioTemporal Asset Catalogs (STAC) or other JSON(-LD)-based metadata encodings including GeoDCAT-AP, “OGC EO Dataset Metadata GeoJSON(-LD) Encoding Standard” OGC 17-003r2, “EO Collection GeoJSON(-LD) Encoding” OGC 17-084r1, Service metadata as per OGC 19-020r1, STAC Collection Specification and STAC Item Specification.
During the activity, several areas requiring further work were identified, which are documented in a Future Work chapter of the Engineering Report. The proposed future work items include the following.
Define a generic OGC API-Notification service and corresponding OGC API Common notification patterns.
Support detailed notification of (catalog content) changes (incl. deletions) for use by harvesters.
Apply access tokens with the DPoP (Demonstrating Proof of Possession) header field.
Combine DCS principles with streaming, e.g., provide JWS/JWE containing a FeatureCollection in chunks.
II. Keywords
The following are keywords to be used by search engines and document catalogues.
OGC, API-Records, Catalog, CSW, DCS, ISO-19115, security, web service
III. Security considerations
No security considerations have been made for this document.
IV. Submitting Organizations
The following organizations submitted this Document to the Open Geospatial Consortium (OGC):
- agentschap Digitaal Vlaanderen, Belgium
- George Mason University, United States of America
- Helyx Ltd., United Kingdom
- Secure Dimensions GmbH, Germany
- Spacebel s.a., Belgium
V. Submitters
All questions regarding this submission should be directed to the editor or the submitters:
Name | Affiliation | Role |
---|---|---|
Yves Coene | Spacebel s.a. | Editor |
Christophe Noël | Spacebel s.a. | Editor |
Andreas Matheus | Secure Dimensions GmbH | Contributor |
Eugene Yu | George Mason University | Contributor |
Li Lin | George Mason University | Contributor |
Philip Hawkins | Helyx | Contributor |
Bart Cosyn | agentschap Digitaal Vlaanderen | Contributor |
Loes Deventer | agentschap Digitaal Vlaanderen | Contributor |
Geraldine Nolf | agentschap Digitaal Vlaanderen | Contributor |
VI. Abstract
This OGC Testbed-18 Engineering Report (ER) describes the results of the Secure, Asynchronous Catalogs Task in the Testbed-18 Catalogs, Filtering, and Moving Features (CMF) thread. This task explored the following.
How search processes that are supported in a classical OGC Catalogue Service for the Web (CSW)/ISO 19115 environment can be supported through tailoring of the OGC API-Records specification.
How an asynchronous catalog scenario can be supported in which metadata publishers push new data to catalog instances that lead to new or updated catalog entries and how subscribers are informed about these updates.
How Data Centric Security (DCS) can be applied in combination with OGC API-Records to allow encrypted delivery and access of catalog metadata between communication partners.
Testbed-18: Secure Asynchronous Catalog Engineering Report
1. Scope
This is the OGC Testbed-18 Engineering Report (ER) documenting the results of the Secure, Asynchronous Catalogs Task. It describes the following.
How search processes in a classical OGC Catalogue Service for the Web (CSW) or ISO 19115 environment can be supported through tailoring of the OGC API-Records specification.
Support for an asynchronous catalog scenario in which metadata publishers push new data to catalog instances that lead to new or updated catalog entries and how subscribers are informed about these updates.
The application of Data Centric Security (DCS) principles in combination with OGC API-Records to allow encrypted and/or signed delivery and access to catalog metadata to support confidentiality and integrity of catalog metadata and search responses. == Introduction
Secure, asynchronous catalogs are contributions to open science environments. Such catalogs help address challenges created by more and more data becoming available and the corresponding complexity of discovery and binding.
This Testbed-18 Engineering Report covers contributions in the following areas.
With OGC CSW and the emergence of the draft OGC API-Records, users have two standards-based alternatives to interact with catalog services. Whereas OGC CSW implementation instances for ISO 19115 metadata have been used extensively in the past, the OGC API-Records standard is still in development. The draft OGC API-Records standard defines three main interaction building blocks: Record, Collections, and the Records API. The ‘record building block’ defines the core schema of a catalog record. This includes a small number of properties that are common across all resource types and need to be further profiled in order to support ISO 19115:2014 and ISO 19115:2003. Testbed-18 explored how search processes supported in a classical OGC CSW/ISO 19115 environment can be supported using an implementation of OGC API-Records.
Current OGC APIs define synchronous RESTful web services that return the response on the same socket pair as the one used to receive the request. This interaction pattern works well if the requested response format is streaming-ready and can be delivered immediately. This approach does fail in typical asynchronous interaction scenarios where clients want to subscribe to updates for previously provided queries. Testbed-18 proposed and implemented asynchronous catalog scenarios. In these scenarios, publishers push new metadata to catalog instances that lead to new or updated catalog entries with subscribers being informed about these updates.
Data Centric Security (DCS) is an approach to apply security directly to the data, independent of security features provided by the network, servers, or applications. For Data Centric Security in the geospatial domain, proof of concept implementations were developed through work in OGC Testbed-15, Testbed-16 and Testbed-17. Testbed-18 extended the developed solutions to work with OGC API-Records to allow encrypted delivery and access of catalog metadata between communication partners.
2. Normative references
The following documents are referred to in the text in such a way that some or all of their content constitutes requirements of this document. For dated references, only the edition cited applies. For undated references, the latest edition of the referenced document (including any amendments) applies.
Open API Initiative: OpenAPI Specification 3.0.2, 2018 https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md
R. Fielding, J. Gettys, J. Mogul, H. Frystyk, L. Masinter, P. Leach, T. Berners-Lee: IETF RFC 2616, Hypertext Transfer Protocol — HTTP/1.1. RFC Publisher (1999). https://www.rfc-editor.org/info/rfc2616.
A.B. Roach: IETF RFC 5989, A SIP Event Package for Subscribing to Changes to an HTTP Resource. RFC Publisher (2010). https://www.rfc-editor.org/info/rfc5989.
M. Nottingham: IETF RFC 8288, Web Linking. RFC Publisher (2017). https://www.rfc-editor.org/info/rfc8288.
J. Snell: IETF RFC 7240, Prefer Header for HTTP. RFC Publisher (2014). https://www.rfc-editor.org/info/rfc7240.
M. Jones, J. Bradley, N. Sakimura: IETF RFC 7515, JSON Web Signature (JWS). RFC Publisher (2015). https://www.rfc-editor.org/info/rfc7515.
M. Jones, J. Hildebrand: IETF RFC 7516, JSON Web Encryption (JWE). RFC Publisher (2015). https://www.rfc-editor.org/info/rfc7516.
M. Jones: IETF RFC 7517, JSON Web Key (JWK). RFC Publisher (2015). https://www.rfc-editor.org/info/rfc7517.
M. Jones, J. Bradley, N. Sakimura: IETF RFC 7519, JSON Web Token (JWT). RFC Publisher (2015). https://www.rfc-editor.org/info/rfc7519.
M. Jones: IETF RFC 7797, JSON Web Signature (JWS) Unencoded Payload Option. RFC Publisher (2016). https://www.rfc-editor.org/info/rfc7797.
M. Jones, J. Bradley, H. Tschofenig: IETF RFC 7800, Proof-of-Possession Key Semantics for JSON Web Tokens (JWTs). RFC Publisher (2016). https://www.rfc-editor.org/info/rfc7800.
H. Butler, M. Daly, A. Doyle, S. Gillies, S. Hagen, T. Schaub: IETF RFC 7946, The GeoJSON Format. RFC Publisher (2016). https://www.rfc-editor.org/info/rfc7946.
A. Rundgren, B. Jordan, S. Erdtman: IETF RFC 8785, JSON Canonicalization Scheme (JCS). RFC Publisher (2020). https://www.rfc-editor.org/info/rfc8785.
Kellog G., Champin P., Longley D. : W3C JSON-LD 1.1, A JSON-based Serialization for Linked Data, W3C Recommendation 16 July 2020 https://www.w3.org/TR/json-ld11/
CEOS: CEOS-OPENSEARCH-BP-V1.3, CEOS OpenSearch Best Practice Document, Version 1.3 https://ceos.org/document_management/Working_Groups/WGISS/Documents/WGISS%20Best%20Practices/CEOS%20OpenSearch%20Best%20Practice.pdf
SEMIC: GeoDCAT-AP — Version 2.0.0, A geospatial extension for the DCAT application profile for data portals in Europe, Version 2.0 https://semiceu.github.io/GeoDCAT-AP/releases/2.0.0/
SEMIC: DCAT-AP — Version 2.1, DCAT Application Profile for data portals in Europe, Version 2.0 https://joinup.ec.europa.eu/collection/semantic-interoperability-community-semic/solution/dcat-application-profile-data-portals-europe/release/210
ISO: ISO19115:2003/Cor1:2006, Geographic Information – Metadata – Implementation specification http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=44361
ISO: ISO19115-1:2014, Geographic Information – Metadata – Part 1: Fundamentals https://www.iso.org/standard/53798.html
ISO: ISO19115-3, Geographic Information – Metadata – Part 3: XML schema implementation for fundamental concepts http://www.iso.org/iso/home/store/catalogue_ics/catalogue_detail_ics.htm?csnumber=32579
ISO: ISO 19139:2007, Geographic Information – Metadata XML, http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=32557
Uwe Voges, Kristian Senkler: OGC 07-045r2, OpenGIS® Catalogue Services Specification 2.0.2 — ISO Metadata Application Profile: Corrigendum. Open Geospatial Consortium (2022). https://portal.ogc.org/files/80534.
Richard Martell: OGC 07-110r4, CSW-ebRIM Registry Service — Part 1: ebRIM profile of CSW. Open Geospatial Consortium (2009). https://portal.ogc.org/files/?artifact id=31137.
Uwe Voges: OGC 08-197r4, INSPIRE Conformance Class of OGC Cataloguing of ISO Metadata (CIM) using the ebRIM profile of CS-W, 2011-10-11
Jerome Gasperi, Frédéric Houbie, Andrew Woolf, Steven Smolders: OGC 10-157r4, OGC® Earth Observation Metadata profile of Observations & Measurements. Open Geospatial Consortium (2016). https://docs.ogc.org/is/10-157r4/10-157r4.html.
Frédéric Houbie, Steven Smolders: OGC 11-035r1, EO Product Collection, Service and Sensor Discovery using the CS-W ebRIM Catalogue. Open Geospatial Consortium (2013). https://portal.ogc.org/files/?artifact id=53276.
Pedro Gonçalves, Uwe Voges: OGC 13-026r9, OGC OpenSearch Extension for Earth Observation, 2019 https://docs.opengeospatial.org/is/13-026r9/13-026r9.html
Uwe Voges, Frédéric Houbie, Nicolas Lesage, Marie-Lise Vautier: OGC 13-084r2, OGC I15 (ISO19115 Metadata) Extension Package of CS-W ebRIM Profile 1.0. Open Geospatial Consortium (2014). https://portal.ogc.org/files/?artifact id=56905.
Y. Coene, U. Voges, O. Barois: OGC 17-003r2, OGC EO Dataset Metadata GeoJSON(-LD) Encoding Standard. Open Geospatial Consortium (2020). https://docs.ogc.org/is/17-003r2/17-003r2.html.
Clemens Portele, Panagiotis (Peter) A. Vretanos, Charles Heazel: OGC 17-069r3, OGC API — Features — Part 1: Core. Open Geospatial Consortium (2019). https://docs.ogc.org/is/17-069r3/17-069r3.html.
Y. Coene, U. Voges, O. Barois: OGC 17-084r1, EO Collection GeoJSON(-LD) Encoding. Open Geospatial Consortium (2021). https://docs.ogc.org/bp/17-084r1/17-084r1.html.
Michael A. Leedahl: OGC 19-016r1, OGC Testbed-15: Data Centric Security. Open Geospatial Consortium (2019). https://docs.ogc.org/per/19-016r1.html.
Yves Coene: OGC 19-020r1, OGC Testbed-15: Catalogue and Discovery Engineering Report. Open Geospatial Consortium (2019). https://docs.ogc.org/per/19-020r1.html.
Panagiotis (Peter) A. Vretanos, Clemens Portele: OGC 19-079r1, OGC API — Features — Part 3: Filtering, https://docs.opengeospatial.org/DRAFTS/19-079r1.html
Panagiotis (Peter) A. Vretanos, Clemens Portele: OGC 20-002, OGC API — Features — Part 4: Create, Replace, Update and Delete, https://docs.ogc.org/DRAFTS/20-002.html
Panagiotis (Peter) A. Vretanos, Tom Kralidis, Charles Heazel: OGC 20-004, OGC API – Records – Part 1: Core, 2019 https://docs.ogc.org/DRAFTS/20-004.html
Aleksandar Balaban: OGC 20-021r2, OGC Testbed-16: Data Centric Security Engineering Report. Open Geospatial Consortium (2021). https://docs.ogc.org/per/20-021r2.html.
Charles Heazel: OGC 20-024, OGC API — Common — Part 2: Geospatial Data, 2022 https://docs.ogc.org/DRAFTS/20-024.html
Aleksandar Balaban, Andreas Matheus: OGC 21-020r1, OGC Testbed-17: Data Centric Security ER. Open Geospatial Consortium (2022). https://docs.ogc.org/per/21-020r1.html.
Panagiotis (Peter) A. Vretanos, Clemens Portele: OGC 21-065, Common Query Language (CQL2), https://docs.ogc.org/DRAFTS/21-065.html
Andreas Matheus: OGC 22-014, Testbed-18: Key Management Service API Engineering Report, http://ogc.pages.ogc.org/T18-Secure_Asynchronous_Catalogs/documents/D008/document.html
C. Lagoze, H. Van de Sompel et al.: OAI-PMH, Protocol Version 2.0, The Open Archives Initiative Protocol for Metadata Harvesting, 2015 https://www.openarchives.org/OAI/openarchivesprotocol.html
3. Terms, Definitions, and Abbreviated Terms
3.1. Terms and Definitions
3.1.1. Access Token
A token that can be provided as part of a service request that grants access to the service being invoked on. This is part of the OpenID Connect and OAuth 2.0 specification [OGC 21-020r1].
3.1.2. Data-Centric Security
Data-centric security emphasizes the dependability of the data itself rather than the security of networks, servers, or applications [Wikipedia].
3.1.3. (Spatial) Data Set
Identifiable collection of (spatial) data [INSPIRE].
3.1.4. (Spatial) Data Set Series
Collection of (spatial) data sets sharing the same product specification [INSPIRE].
3.1.5. Discovery Service
Service that makes it possible to search for spatial data sets and services on the basis of the contents of the corresponding metadata and to display the contents of the metadata [INSPIRE].
3.1.6. Granule
A granule is the finest granularity of data that can be independently managed. A granule usually matches the individual file of EO satellite data [CEOS-BP].
3.1.7. STANAG
In NATO, Standardization Agreement defines processes, procedures, terms, and conditions for common military or technical procedures or equipment between the member countries of the alliance.
3.2. Abbreviated terms
AP
Application Package
API
Application Programming Interface
CEOS
Committee on Earth Observation Satellites
CQL
Common Query Language
CSW
Catalogue Service for the Web
DCAT
Data Catalog Vocabulary
DCS
Data Centric Security
DEK
Data Encryption Key
DPoP
Demonstrating Proof-of-Possession
EO
Earth Observation
EP
Extension Package
ESA
European Space Agency
HTTP
Hypertext Transfer Protocol
IdP
Identity Provider
INSPIRE
INfrastructure for SPatial InfoRmation in Europe
ISO
International Organization for Standardization
JOSE
Javascript Object Signing and Encryption
JSON
JavaScript Object Notation
JWE
JSON Web Encryption
JWK
JSON Web Key
JWS
JSON Web Signature
JWS/CT
JSON Web Signature Clear Text
JWT
JSON Web Token
KEK
Key Encryption Key
KMS
Key Management System
OAI-PMH
Open Archive Initiative Protocol for Metadata Harvesting
OGC
Open Geospatial Consortium
REST
Representational State Transfer
STAC
SpatioTemporal Asset Catalog
STANAG
Standardization Agreement
SWG
Standard Working Group
TIE
Technology Integration Experiment
UML
Unified Modeling Language
URI
Uniform Resource Identifier
URL
Uniform Resource Locator
XML
eXtensible Markup Language
4. OGC API-Records tailoring
4.1. Introduction
This chapter includes the following.
Whether OGC API – Records can support classical discovery workflows comparable with OGC CSW/ISO 19115 setups.
A proposed tailoring based on the use cases and requirements gathered during the project.
4.1.1. CSW ISO AP / ISO19115 Setups
OGC CSW has been used for ISO19115 metadata (and in particular its XML encoding ISO19139(-2)) extensively in the past. The CSW ISO Application Profile (AP) OGC 07-045r1 is widely implemented in Europe as the INSPIRE discovery service as one of the INSPIRE Network Services [3]. In addition, the INSPIRE community uses ISO19115 metadata and its XML encodings (e.g., ISO19139(-2)) for encoding dataset, dataset series, and services as explained in the Technical Guidance document [4]. The Joint Research Centre (JRC) of the European Commission (EC) are proposing a GeoDCAT-AP encoding as a Resource Description Framework (RDF) vocabulary with information content covering the union of metadata elements of the core profile of ISO 19115:2003 and those defined in the framework of the INSPIRE Directive of the European Union. This allows for a JSON-LD encoding for metadata records currently described within the INSPIRE community.
4.1.2. CSW ebRIM AP / ISO19115 Setups
In addition to CSW ISO AP, other communities use the CSW ebRIM Application Profile (AP) OGC 07-114r4 for discovery of resources described using the same ISO19115-based metadata. A dedicated ebRIM Extension Package for CSW ebRIM was developed by the OGC members and released in 2014 (OGC 13-084r2). This standard is known as I15 Extension Package (EP) or Cataloguing of ISO19115 Metadata (CIM) EP. The extension package was originally used by the Earth Observation (EO) community to support EO collection, service and sensor discovery as described in OGC 11-035r1. A typical EO discovery workflow consists of two steps: An initial search for EO collections (similar to INSPIRE dataset series) followed by a search for EO granules (i.e., products, similar to INSPIRE datasets) belonging to the collection. The search parameters available for the granule search typically differ according to the collection, such as filtering according to cloud cover percentage only applies to collections from optical sensors. While discovery services based on the ebRIM CSW service bindings have been replaced by OpenSearch service bindings in the EO community (See CEOS-BP and OGC 13-026r9), many agencies still describe their EO collections using ISO19139(-2) metadata records. The /gmd:MD_Metadata/gmd:parentIdentifier property (ISO19139:2007), /eop:metaDataProperty/eop:EarthObservationMetaData/eop:parentIdentifier (OGC 10-157r4) property, $.properties.parentIdentifier (OGC 17-003r2) property and eo:parentIdentifier queryable (OGC 13-026r9) all reflect the hierarchical relation between the metadata record of an EO granule and the metadata record of the corresponding EO collection.
The gmd:parentIdentifier relation is also mandatory in the INSPIRE context if a higher level dataset is available in the hierarchy [5][6].
4.2. Main use cases and requirements
Table 1 — User stories — discovery workflow
User Story | As a … | I want to … | so that I can … |
1 | Metadata Consumer | obtain metadata about the catalog service endpoint, including its service bindings. | interact with the catalog. |
2 | Metadata Consumer | access the catalog service and perform requests for catalog records. | discover metadata records available in the catalog. |
2.1 | Metadata Consumer | access the catalog service and perform search requests for catalog records matching my search criteria. | discover metadata records available in the catalog. |
2.2 | Metadata Consumer | access the catalog service and retrieve one specific complete catalog record in a specific format. | retrieve all detailed metadata information for a single record in my preferred format (XML, ISO, RDF, …). |
3 | Metadata Publisher | upload metadata records in the catalog | make them discoverable for metadata consumers. |
3.1 | Metadata Publisher | update or remove metadata records available in the catalog | perform metadata changes. |
3.2 | Metadata Publisher | obtain metadata records available in the catalog. | perform metadata changes. |
Clause 4.1 of [3] lists the identified use cases that an INSPIRE Discovery Service has to fulfill to support the typical INSPIRE workflow. Such a service is known as the INSPIRE Profile of CSW ISO AP. The corresponding use case diagram is depicted below.
Figure 1 — Discovery Service Use Cases [3]
The following subsections assess whether OGC API-Records can satisfy each of these use cases and derive requirements for the additional tailoring of OGC API-Records.
4.2.1. Use Case 1 (UC1): Get Discovery Service Metadata
A CSW catalog allows clients to retrieve service metadata from a server via the GetCapabilities operation which may contain a MetadataURL element (Req. 7 and Table 3 of [3]).
Similarly, an OGC API-Records implementation should provide the same information in the following way, to support the same workflow:
Table 2 — Discovery service metadata comparison
Extended CSW Metadata | OGC API-Records Metadata |
Service identification, Service provider, Operations metadata | Landing Page link rel=”describedby” and type=”application/vnd.iso.19139+xml” and /conformance endpoint. The hreflang attribute can be used in the link object to provide the discovery service metadata in multiple languages (Req. 6 of [3]). |
Filter capabilities | LandingPage link rel=”queryables”, type=”application/schema+json” and /queryables endpoint as per OGC 19-079r1. Similarly, CQL capabilities are to be advertised. |
Recommendation 1 | |
---|---|
Statement | The discovery interface should provide discovery service metadata equivalent to the above Extended CSW Capabilities information. |
4.2.2. Use Case 2 (UC2): Discover Metadata
To implement the INSPIRE workflow, the CSW ISO AP supports the GetRecords operation as per clause 4.3.2 of [3] with following two additional parameters.
The language parameter: The OGC API-Records API server can provide a similar capability by supporting the usual HTTP content negotiation mechanisms and process the Accept-Language header of a request (as per clause 7.10 of OGC 17-069r3).
The query parameter: Supported by the filter statement of CSW ISO AP. To support similar Filter_Capabilities as can be advertised in a CSW Capabilities document, the OGC API-Records server will need to implement a subset of the draft OGC Common Query Language (CQL2) OGC 21-065 and support CQL2 filter expressions at the /collections/{collection-id}/items endpoint.
NOTE INSPIRE requires the Discovery Service to advertise the default language in the CSW GetCapabilities response. Proposing a similar mechanism to advertise the default language is further work. Possible approaches include:
advertise default language in the OGC API-Records Landing Page response;
advertise default language in the OGC API-Records API Definition response; and
use of hreflang in the link object referring to the search endpoint (/collections/{id}/items) in a Collection response.
Recommendation 2 | |
---|---|
Statement | The discovery interface should support the equivalent of the (INSPIRE) search parameters defined in clause 4.4 of [3]. |
When past OGC discovery interfaces were defined, INSPIRE requirements were taken into account by proposing the search parameters required by the INSPIRE discovery service. The OGC OpenSearch standard OGC 13-026r9 was tailored in this way to cover INSPIRE requirements and a dedicated INSPIRE conformance class was added. The CSW CIM EP specification was also tailored for INSPIRE requirements.
To ensure a common response format, a GetRecords request is recommended to support “application/xml” and ISO19139 as outputSchema (outputSchema=http://www.isotc211.org/2005/gmd).
Recommendation 3 | |
---|---|
Statement | The discovery interface should support access to the (original) XML-based metadata (i.e., ISO19139, ISO19139-2, ISO19115-3, etc.) through content negotiation or indirectly via an $.properties.links[] object with rel=”via” in a regular API-Records GeoJSON search response. |
Recommendation 4 | |
---|---|
Statement | The discovery interface should use the media types listed in OGC13-026r9 for identifying ISO19139, ISO19139-2, or ISO19115-3 representations, i.e., “application/vnd.iso.19139+xml”, “application/vnd.iso.19139-2+xml”, and “application/vnd.iso.19115-3+xml” for content negotiation or as type attribute of the rel=”via” links. |
{
"rel": "via",
"href": "https://fedeo.ceos.org/collections/series/items/PROBA.CHRIS.1A?httpAccept=application/vnd.iso.19139%2Bxml",
"type": "application/vnd.iso.19139+xml",
"title": "ISO 19139 metadata"
}
Figure 2 — Access to Original ISO Metadata File With "Via" Link From the GeoJSON Representation.
An INSPIRE discovery service has to advertise all its queryables. To achieve this capability, the OGC API-Records catalog needs to advertise its queryables via the appropriate endpoints /queryables and/or /collections/{collection-id}/queryables.
Recommendation 5 | |
---|---|
Statement | The discovery interface should support discovery of “datasets,” “dataset series,” and “services”. |
Recommendation 6 | |
---|---|
Statement | The discovery interface should support GeoDCAT-AP or DCAT-AP encoding as primary metadata representation. |
Recommendation 7 | |
---|---|
Statement | The discovery interface should support retrieval of records using their GeoDCAT-AP or DCAT-AP encoding in at least the following RDF serialisations: application/rdf+xml and application/ld+json. Support for text/turtle is optional. |
4.2.3. Use Case 3 (UC3): Publish Metadata
The Publish Metadata operation supports editing (insert, update, and delete) of metadata elements of resources in the catalog (push or pull metadata mechanisms). To support the INSPIRE workflow, the CSW ISO AP has to support the Transaction (push) or Harvest (pull) operation as per clause 4.3.3 of [3].
To support similar capabilities, the OGC API-Records server will need to implement the draft “OGC API — Features — Part 4: Create, Replace, Update, and Delete” OGC 20-002 standard.
NOTE The above OGC 20-002 standard may also support editing collections available at a /collections endpoint when the resources endpoint is interpreted as {landingPageUri}/collections. This case is similar to the {landingPageUri}/processes case (Example 2).
Recommendation 8 | |
---|---|
Statement | The catalog interface should support insertion, deletion, and update of “datasets,” “dataset series,” and “services” metadata records. |
Recommendation 9 | |
---|---|
Statement | The catalog interface should support insertion and updates of records using their original ISO19139 or ISO19115-3 encoding. |
Recommendation 10 | |
---|---|
Statement | The catalog interface should support insertion and updates of records using their GeoDCAT-AP or DCAT-AP encoding. |
Recommendation 11 | |
---|---|
Statement | The catalog interface should support insertion and updates of records using their GeoDCAT-AP or DCAT-AP encoding in at least the following RDF serialisations: application/rdf+xml and application/ld+json. Support for text/turtle is optional. |
4.3. Proposed Interface Design
In clause 6.5, the draft OGC API-Records standard defines three building blocks that each can be tailored for a specific community. The following subsections propose a tailoring of each of these building blocks to support the requirements that were identified in the previous section.
Requirement 1 | |
---|---|
Label | /req/iso/record-types-1 |
Statement | The catalog shall support discovery resources of type series (if applicable) via one of the following mechanisms. |
A | (Option 1) Via the /collections and /collections/{resource-id} endpoints. |
B | (Option 2) Via the /collections/{collection-id}/items and /collections/{collection-id}/items/{resource-id} endpoints. |
Requirement 2 | |
---|---|
Label | /req/iso/record-types-2 |
Statement | The catalog shall support discovery resources of type dataset or service (if applicable) via the /collections/{collection-id}/items and /collections/{collection-id}/items/{resource-id} endpoints. |
As explained above, there are two alternative ways to map series on the data model. The tailoring of the draft OGC API-Records Standard and interpretation of the requirements below depend on the selected mapping. The term series search endpoint is used to indicate the search endpoint for series search selected according to the above requirement. The terms dataset and services search endpoint apply to the search endpoints for dataset and service records (if applicable).
4.3.1. Record Collection (Catalog) Tailoring
Section 8 of OGC 20-004 defines the schema for the collection resource as an extension of the collection schema defined in OGC API-Features and OGC API-Common — Part 2: Geospatial Data.
Recommendation 12 | |
---|---|
Statement | If additional GeoJSON properties are required in the catalog collection schema to represent ISO19139(-2) or ISO19115-3 dataset series metadata properties, they should be borrowed from the GeoDCAT-AP or DCAT-AP encoding when possible. Applicable to Option-1 only. |
Recommendation 13 | |
---|---|
Statement | The catalog should support the ISO19139(-2) or ISO19115-3 metadata representations for the collection schema (via content negotiation or a query parameter, e.g., f=). This represents an additional requirements class in addition to “clause 10.3 Requirements Class GeoJSON” and “clause 10.2 Requirements Class HTML” for the catalog collection schema in OGC 20-024. Applicable to Option-1 only. |
4.3.2. Record Schema Tailoring
Section 16.1 of OGC 20-004 defines the GeoJSON (application/geo+json) encoding of the catalog record schema.
Recommendation 14 | |
---|---|
Statement | If additional GeoJSON properties are required in the catalog record schema to represent ISO19139(-2) or ISO19115-3 metadata properties, they should be borrowed from the GeoDCAT-AP or DCAT-AP encoding when possible. |
NOTE The EO Collection GeoJSON(-LD) Encoding (OGC 17-084r1) Best Practice proposes a reusable GeoJSON encoding with corresponding mapping to ISO19139(-2) and NASA UMM-C properties in its Annex C, consistent with GeoDCAT-AP via a JSON-LD context definition.
Recommendation 15 | |
---|---|
Statement | The catalog should support the ISO19139(-2) or ISO19115(-3) metadata representations for the record schema (via content negotiation or a query parameter, e.g., f=). This represents an additional requirements class in addition to “clause 16.1 Requirements Class GeoJSON” and “clause 16.3 Requirements Class HTML” for the catalog record schema. |
4.3.3. Records API Tailoring
Requirement 3 | |
---|---|
Label | /req/iso/type-queryable |
Statement | The OGC API-Records search endpoint shall support the queryable type, equivalent to the CSW queryable Type (MD_Metadata.hierarchyLevel) to filter (ISO19139) metadata records based on the hierarchyLevel (i.e., series, dataset, service) (See OGC 07-045r2). |
Examples:
https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items?type=series
https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items?type=dataset
https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items?type=service
To support the search workflows using search criteria defined in Table 4 of [3], the following requirements apply.
Requirement 4 | |
---|---|
Label | /req/iso/mandatory-series-queryables |
Statement | The OGC API-Records series search endpoint shall support the following additional search parameters with expected data type, meaning and mapping on (ISO19139) metadata as defined in OpenSearch Extension for Earth Observation (OGC 13-026r9). |
A | useLimitation. |
B | accessConstraint |
C | otherConstraint |
D | classification |
E | organisationName |
F | organisationRole |
G | topicCategory |
H | lineage |
I | keyword |
J | denominator |
K | distanceValue |
L | distanceUOM |
M | Accept-Language (header) — i.e., metadata language. |
N | title |
O | abstract |
P | specificationTitle |
Q | specificationDate |
R | specificationdateType |
S | degree |
Requirement 5 | |
---|---|
Label | /req/iso/mandatory-item-queryables |
Statement | The OGC API-Records /collections/{collectionId}/items endpoint (a.k.a. dataset and service search endpoint) shall support the additional search parameters listed in the previous requirement /req/iso/mandatory-series-queryables. |
Requirement 6 | |
---|---|
Label | /req/iso/advertise-series-queryables |
Statement | The OGC API-Records interface shall advertise the available queryables for the series search endpoint (if applicable) at the endpoint corresponding the option selected for “series” discovery (See above) |
A | Via the /queryables endpoints (If Option 1 was selected). |
B | Via the /collections/{collection-id}/queryables (if Option 2 was selected). |
Requirement 7 | |
---|---|
Label | /req/iso/advertise-item-queryables |
Statement | The OGC API-Records interface shall advertise the available queryables for the dataset and service search endpoints (if applicable) at the /collections/{collection-id}/queryables endpoint. |
The example below provides an example of a /queryables response advertising search parameters required for a typical INSPIRE discovery workflow.
{
"$schema": "http://json-schema.org/draft/2019-09/schema",
"title": "Available search parameters",
"type": "object",
"properties": {
"limit": {
"title": "limit",
"type": "integer"
},
"bbox": {
"title": "bbox",
"type": "array",
"minItems": 4,
"maxItems": 6,
"items": {
"type": "number"
}
},
"datetime": {
"title": "datetime",
"type": "string"
},
"externalId": {
"title": "externalId",
"type": "array",
"items": {
"type": "string"
}
},
"type": {
"title": "type",
"type": "array",
"items": {
"type": "string"
}
},
"q": {
"title": "q",
"type": "array",
"items": {
"type": "string"
}
},
"useLimitation": {
"title": "useLimitation",
"type": "string"
},
"accessConstraint": {
"title": "accessConstraint",
"type": "string",
"enum": [
"copyright",
"patent",
"trademark",
"license",
"intellectualPropertyRights",
"restricted",
"otherRestrictions"
]
},
"otherConstraint": {
"title": "otherConstraint",
"type": "string"
},
"classification": {
"title": "classification",
"type": "string",
"enum": [
"unclassified",
"restricted",
"confidential",
"secret",
"topSecret"
]
},
"organisationName": {
"title": "organisationName",
"type": "string",
"enum": [
"CEDA",
"CMEMS",
"DE/DLR",
"ESA/ESRIN",
"FR/CNES",
"JP/JAXA/EOC",
"VITO"
]
},
"organisationRole": {
"title": "organisationRole",
"type": "string",
"enum": [
"resourceProvider",
"custodian",
"owner",
"user",
"distributor",
"originator",
"pointOfContact",
"principalInvestigator",
"processor",
"publisher",
"author"
]
},
"topicCategory": {
"title": "topicCategory",
"type": "string"
},
"lineage": {
"title": "lineage",
"type": "string"
},
"keyword": {
"title": "keyword",
"type": "string"
},
"denominator": {
"title": "denominator",
"type": "string"
},
"distanceValue": {
"title": "distanceValue",
"type": "number"
},
"distanceUOM": {
"title": "distanceUOM",
"type": "string"
},
"language": {
"title": "type",
"type": "string"
},
"title": {
"title": "type",
"type": "string"
},
"abstract": {
"title": "abstract",
"type": "string"
},
"specificationTitle": {
"title": "specificationTitle",
"type": "string"
},
"specificationDate": {
"title": "specificationDate",
"type": "string",
"format": "date-time"
},
"specificationdateType": {
"title": "specificationdateType",
"type": "string",
"enum": [
"creation",
"revision",
"publication"
]
},
"degree": {
"title": "degree",
"type": "string",
"enum": [
"True",
"False",
"Null"
]
}
},
"$id": "https://tb18.cat.org/collections/series/queryables"
}
Figure 3 — Advertising INSPIRE Search Parameters Via the /queryables Response
Requirement 8 | |
---|---|
Label | /req/iso/update-series |
Statement | The OGC API-Records shall implement (series) metadata record insertion, update, and deletion at the /collections (Option 1) or /collections/{collection-id}/items endpoint (Option2) using the paths and HTTP methods as per OGC20-002. |
Requirement 9 | |
---|---|
Label | /req/iso/update-items |
Statement | The OGC API-Records shall implement (dataset and service) metadata record insertion, update, and deletion at the /items endpoint using the paths and HTTP methods as per OGC20-002. |
See Annex A Example 3.3 for a detailed Jupyter Notebook example using the POST operation and application/xml media type to insert a metadata record and the DELETE operation to remove the record.
The resource definition diagram below summarizes the available resources, the applicable HTTP methods, available representations, and the paths for each of the resources. Some parts of the diagram only apply when Option 1 was used for modeling (ISO) series, i.e., when /collections/{collection-id} represents a series.
Figure 4 — Resource Definition Diagram for Tailored OGC API-Records
5. Asynchronous Communication for OGC API-Records
5.1. Introduction
One of the goals for Testbed-18 was to contribute to asynchronous communication discussions by implementing an asynchronous catalog. The OGC Testbed-18 Call for Participation (CFP) describes asynchronous communication as scenarios where clients want to subscribe to updates for previously provided queries. Those subscribers should be informed of new or updated catalog entries (e.g., inserted by a publisher).
The designed solution described below is based on the Subscription resource which represents the mission of delivering update notification based on the requested records query and the provided delivery method.
Although the approach above does not specifically tackle the concern of queries that cannot be processed within regular HTTP time out (e.g., when the server needs encrypting), such a scenario is simply a special case of a subscription with a single update notification (when the response is available).
5.2. Main Use Cases and Requirements
Table 3 — User Stories — Asynchronous Catalog
User Story | As a … | I want to … | so that I can … |
21 | Metadata Consumer | subscribe to a search request. | receive additional search results in the future matching my original search criteria. |
22 | Metadata Consumer | unsubscribe to a search request subscription. | stop receiving additional search results in the future. |
23 | Metadata Consumer | define the frequency with which I want to receive additional search results (e.g., daily). | receive search result updates grouped by period. |
24 | Metadata Consumer | provide an HTTP endpoint or email address to receive notification of additional search results | choose the notification mechanism. |
25 | Metadata Consumer | indicate at subscription time that the server shall apply Data Centric Security (signature, encryption) to the future search responses. | choose the security level for future additional search results. |
The subscription interface should allow a client to subscribe to the results (and updates) of a catalog query. The subscription implies that the catalog must notify (asynchronously) the subscribers of subsequent modifications matching the query until the user unsubscribes.
In particular, the following reports and interfaces covering asynchronous interactions were reviewed and considered for the design of a solution.
The asynchronous support capability provided in the draft OGC API – Processes Standard involves the polling of status (supported by the Core requirements class) and the callback-driven approach (supported by the Callback requirement class) which relies on OpenAPI native capabilities (https://swagger.io/docs/specification/callbacks/).
The behavior models described in the OGC Publish-Subscribe White Paper (OGC 20-081) include the Delayed Response, the Standing Request, the Synchronization and the Publish-Subscribe.
The Simple Async mechanism proposed as an OGC API – Common extension (https://github.com/opengeospatial/ogcapi-common/tree/master/proposals/simple-async).
The Geosynchronization mechanism specified in the OGC OWS 7 Engineering Report — Geosynchronization service (OGC 10-069r2) describing the Subscriptions, Topics, and Publishers resources and related operations.
The Publish/Subscribe Interface Standard (OGC 13-131r1) that supports the core components and concepts of the Publish/Subscribe message exchange pattern with OGC Web Services.
The OGC Testbed-13 Asynchronous Services ER (OGC 17-028) that essentially describes the Publish-Subscribe and the status polling of the legacy OGC Web Processing Service interface.
As a starting point, the OGC API — Processes Callback approach was adapted to the API Records context as follows.
The behavior model is extended to support a subscriber requesting continuous update notifications about new catalog records.
The subscriber must provide a notification expiration time to avoid flooding a subscriber with too many callback notifications.
The Dismiss operation must support the cancellation of the subscription.
The content of the notification may either include the (updated) records or a link to these records.
While the callback could be specified in HTTP GET Catalog request, the Testbed participants reached a consensus to design a blank solution and handle the subscription creation from a dedicated HTTP POST on the resource endpoint.
5.3. Proposed Interface Design
The following subsections propose a OGC Subscription requirement class for the OGC API-Records draft standard. The proposed interface relies on subscription resources. A subscription is a job that delivers notifications when a client subscribes to resources updates (i.e., new records or modified records).
The following flow applies to a subscription and the resulting notifications.
The Catalog Client (on the behalf of a signed user) submits a subscription request to the Catalog server and provides the URL to the subscribed resources and the delivery options (delivery method, expiration, schedule).
The Catalog server registers the subscription and returns HTTP code 201 along with the link to the created subscription.
Each time the server schedules a check on the subscribed records, a notification is prepared and sent to the configured receiver.
Figure 5 — Asynchronous Pattern for API Records
The interface provides operations to create, read, update, and delete subscriptions. The resource definition diagram below summarizes the applicable HTTP methods and the paths for each of the resources.
Figure 6 — Subscriptions Resources API Definition
5.3.1. Subscription Resource Schema
A subscription is represented as the following set of properties.
Resources-uri: Identifier of the resources to which the user subscribes (typically a URL to catalog records).
Delivery: Method and target for notification deliveries formatted as protocol:address[,additional parameters] (e.g., mailto:you@ogc.org).
Expires: Seconds the subscription is valid (or ISO 8601 date to be discussed)/
Schedule: Defines the notification schedule using a cron-like format (e.g., “0 0 * * 0”).
Status: Indicates the state of a created subscription (e.g., started, completed, cancelled).
Deliveries: List the URL links to the resources that have already been delivered (in a notification).
Additional DCS properties (public-key, wrapped-dek) are detailed further.
The OpenAPI 3.0 schema subscription.yaml is represented on the class diagram below.
Figure 7 — Subscription Schema
5.3.2. Create a Subscription
A client can create a subscription by identifying the resources for which update notifications should be sent and indicating the delivery options.
Requirement 10 | |
---|---|
Label | /req/subscriptions/create |
Statement | The server shall support the HTTP POST operation at the path /subscriptions. The request shall be based on the SubscriptionRequest class of the subscription.yaml schema. |
Requirement 11 | |
---|---|
Label | /req/subscriptions/create-success |
Statement | A successful execution of the operation shall be reported as a response with a HTTP status code 201. The header of the response shall return the HTTP Location header that contains a link to the newly created subscription. |
The example below illustrates a typical subscription request.
{
"resources-uri": "http://server.com/records/items?param=value",
"delivery": "http://server.com/callbackURI",
"expiry": "2025-12-10T",
"schedule": "0 0 * * 0"
}
Figure 8 — Subscription Request Example
See also Annex A Example 5.1.
Alternatively, a subscription could be requested directly when retrieving a list of catalog records. This could be achieved by extending the HTTP GET request with the relevant parameters (such as the OGC API Processes callbacks). However, the Testbed participants agreed to focus on the specific subscription endpoint in the context of the OGC API Records.
5.3.3. Receive subscription notifications
If the subscriber provides a delivery method, then the results are communicated to the delivery endpoint in accordance with the delivery options (expiry, schedule, etc.). Also, the subscriber can specify preferences about the notification content (updated records or a link to those records) using the HTTP Prefer header as detailed below.
Requirement 12 | |
---|---|
Label | /req/subscription/notification |
Statement | The server shall deliver notifications when subscribed resources (identified in resources-uri) are updated (new resources or modified resources). If the request is accompanied with the HTTP Prefer header then the server SHOULD honor that preference. |
A | The notification must contain a link to the resources if the subscription request is provided with the Prefer header with value ‘return=minimal’ or if the header is not present. |
B | The notification must contain the list of resources if the request is accompanied with the HTTP Prefer header asserting a return=representation preference. |
Requirement 13 | |
---|---|
Label | /req/subscriptions/notification-delivery |
Statement | The server shall send update notifications only if a delivery method is provided in the subscription. If provided, the server shall deliver notifications using the method and protocol provided in the delivery property (e.g., mailto:you@ogc.org) |
Requirement 14 | |
---|---|
Label | /req/subscriptions/notification-expires |
Statement | If the expires property is provided, the server shall stop deliver notification starting at the indicated expiration date. |
Requirement 15 | |
---|---|
Label | /req/subscriptions/notification-schedule |
Statement | If the schedule property is provided, the server shall deliver notification following the provided UNIX cron schedule. |
5.3.4. Retrieve a Subscription
A subscription can be retrieved to monitor the subscription status (e.g., started, completed, cancelled) and get links to the updated resources clusters that were reported by the server.
When no delivery method is specified, the subscription plays the same role as the job status document defined in OGC API Processes: The subscription can be polled for discovering updated resources.
Requirement 16 | |
---|---|
Label | /req/subscriptions/subscription-get |
Statement | The server shall support the HTTP GET operation at the path /subscriptions/{sub_id} to retrieve an existing subscription. |
Requirement 17 | |
---|---|
Label | /req/subscriptions/subscription-get-response |
Statement | A successful execution of the operation shall be reported as a response with a HTTP status code 200. The content of that response shall be based upon the Subscription class of the OpenAPI 3.0 schema subscription.yaml. The deliveries array provide links to delivery units (i.e., a set of updated resources that have been prepared by the server). |
Recommendation 16 | |
---|---|
Statement | The catalog should prepare the delivery units following the frequency specified in the schedule property. If an update is not detected, then no delivery unit should be prepared, and no link should be added to the deliveries array. |
The example below illustrates the response of the HTTP GET request.
Figure 9 — Get Subscription Response Example
5.3.5. Update and Delete Subscription
A subscription might be deleted using HTTP Delete or can be updated using HTTP Patch for editing any of the subscription property (e.g., delivery, schedule, public-key).
Note that the possibility to update the status of the subscription (e.g., paused) has been raised but not implemented in the scope of the project.
See also Annex A Example 5.6.
Requirement 18 | |
---|---|
Label | /req/subscriptions/subscription-patch |
Statement | The server shall support the HTTP PATCH operation at the path /subscriptions/{sub_id}. The request shall be based on the SubscriptionRequest class of the subscription.yaml schema, and the delivery process should be updated accordingly. The response of a successful PATCH request is 204: Done. |
Requirement 19 | |
---|---|
Label | /req/subscriptions/subscription-delete |
Statement | The server shall support the HTTP DELETE operation at the path /subscriptions/{sub_id}. The corresponding subscription should be removed and can no longer be retrieved. The response of a successful DELETE request is 204: Done |
5.3.6. Subscription States
A tailoring of the OGC Subscription requirement was implemented for requesting an explicit subscription status update. The approach extends the existing status (started, completed, cancelled) with additional values, and proposes providing the PATCH operation to update the status of a subscription.
The subscription states as shown on diagram below include the following.
created: The subscription has been submitted by the client.
approved: The subscription endpoint has been approved (with the security code).
ready: The target resources (uri) are provided.
started: The subscription is manually started.
stopped: The subscription is manually stopped.
deleted: The subscription is deleted.
See also Annex A Example 5.4 and Example 5.5.
Figure 10 — Subscription State Diagram
The diagram reflects only explicit operations, but automated status changes might be relevant (e.g., automatically starting the subscription). Moreover, alternative flows and states can be considered such as completed for an expired subscription.
6. Application of Data Centric Security
6.1. Introduction
Applying Data Centric Security can be applied to the following interactions.
Synchronous Search Responses
Asynchronous Responses
Metadata Insertions/Updates in the Catalog
6.2. Main Use Cases and Requirements
The table below summarizes the main use cases.
Table 4 — User Stories — Data Centric Security
User Story | As a … | I want to … | So that I can … |
11 | Metadata Publisher | upload plain text metadata records in the catalog. | make them discoverable for metadata consumers. |
12 | Metadata Publisher | upload signed metadata records in the catalog. | ensure integrity. |
13 | Metadata Publisher | upload encrypted metadata records in the catalog. | ensure confidentiality and make it available to only selected metadata consumers. |
14 | Metadata Publisher | upload metadata records in the catalog combined with corresponding access rules. | ensure appropriate access rights. |
15 | Metadata Consumer | choose whether to receive metadata records in search responses as plain records, signed or encrypted assuming I have the appropriate access rights. | select the appropriate security level. |
16 | Metadata Consumer | verify the signature of a metadata record part of a search response. | check integrity and authenticity. |
17 | Metadata Consumer | decrypt an encrypted metadata record which is part of a search response. | process, display, etc. the metadata record content. |
6.2.1. Synchronous Responses With DCS
The API endpoints /collections/{id}/items (for item search), /collections/{id}/items/{id} (for collection search) etc.) that are subject to encrypted payloads or responses can vary. Clients can discover this through the media types supported for a specific resource (i.e. application/dcs+geo or application/jose).
In the context of an OGC API – Records implementation, the application of DCS has many similarities to the second scenario described in “Testbed-17: Data Centric Security ER” (21-020r1), which depicts the exchange of DCS-protected content from an OGC API — Features implementation. The same ER describes which metadata fields in a response allow a client to successfully decrypt the information.
6.2.1.1. Application/DCS+GEO
According to clause 4.1 of 21-020r1, for OGC API – Features, the DCS data format can be applied as an extension to XML and JSON. Although the ISO19115 tailoring of OGC API – Records may decide to also use XML formats (see above), the focus was on a JSON approach. The response formats proposed for OGC API – Features correspond to the encrypted features in a JSON container (clause 5.2.2 of 21-020r1), based on the schema illustrated below.
Figure 11 — API Features JOSE Based Containers JSON Schema (dcs+geo)
The potentially sensitive information in the data_description element can be requested with three levels of security (plain, integrity, or confidentiality) depending on the requested media type profile for application/dcs+geo. The catalog server detects that a client wants an encrypted response when it receives a request (via content negotiation) for the application/dcs+geo media type.
When provided in a JSON Web Encryption (JWE) token, the data_description element (see schema above) is encrypted with the public key of the user (i.e., client) providing the public Key Encryption Key (KEK) id previously registered at the Key Management Service (KMS).
The data is always encrypted in a JWE token using a Data Encryption Key (DEK). The kid and kurl of the DEK are included the JWE header. The kurl is a custom header parameter providing the URL to the KMS to retrieve the DEK. The definition of the DCS container in JSON is provided in clause 8 of OGC 20-021r2. The responses from an OGC API Records request (assuming the GeoJSON conformance class) encrypted in a DCS container contain “metadata” (optional housekeeping information) and “data”, with “data” representing the encrypted original OGC API Records response.
The following Data Centric Security (DCS) flow applies for synchronous search (and subscription) requests.
[1] The Catalog Client D114 (on the behalf of a signed in user) submits a request to the Catalog server (e.g. search request) and provides the DCS media type (f parameter), the access token, the key challenge (PIN), and the key challenge method.
[2] The Catalog validates the access_token, applies access control based on the bearer token, and retrieves the username and client_id associated with the user token.
[3] The Catalog server creates a Data Encryption Key (DEK) and then encrypts the response items using the relevant key (multiple keys might be required in case various confidentiality levels are associated to the response items).
[4] The Catalog registers the DEK along the client id (aud parameter), the access token, and the key_challenge to Key Management Service D115 (KMS).
[5] The Catalog response (DCS container) is returned to the Client.
[6] The client extracts the DEK kid and kurl to request the DEK. Optionally, the client might provide the kek_id of a previously registered user public key (Key Encryption Key) to request the encryption of the key.
[7] The Key Management Service (KMS) returns the DEK key optionally encrypted with the user private key (KEK).
[8] The Catalog Client decrypts the DCS container and displays the records to the user.
Figure 12 — Synchronous Responses with DCS
See Annex A Example 2.1 (/items) and Example 3.1 (/items/{item-id}) for detailed Jupyter Notebook examples using the application/dcs+geo media type.
6.2.1.2. Application/JOSE
Instead of the above approach where the catalog server chooses the encryption key and communicates the key to the client via a reference (kid) to the KMS, a client may choose to use its own public encryption key and pass that key to the catalog server. The KMS is not used in this scenario. When the response (JOSE format) is received, the client can decrypt the response with its own private (encryption) key.
See Annex A Example 3.2 for a detailed Jupyter Notebook example using the application/jose media type defined in [RFC 7515].
The current assumption is that the /collections/{collection-id}/items and /collections/{collection-id}/items/{record-id} responses are in-scope for the above encryption. The same approach can be applied to /collections and /collections/{collection-id} if appropriate, with encrypted JSON instead of GeoJSON representations. Clients can discover which resources (URL) accept requests for the application/dcs+geo or application/jose media types as this should be advertised by the server in the OpenAPI definition of the interface or even in an OpenSearch OSDD document. This allows for a flexible use of such encrypted response capabilities by a (Catalog).
6.2.2. Asynchronous Communication with DCS
When the notification includes links to the subscribed resources, the nominal Data Centric Security process can be applied when the resources are retrieved by the subscriber depending on the catalog implementation.
In the case where the notification includes the records, participants explored the following models for encrypting the data.
Using the KMS for retrieving the DEK generated by the catalog. However, Testbed participants were concerned about persisting user information on the catalog side and/or key permissions for the receiver endpoint which are not necessarily the same as the subscriber client.
Providing a client public key to encrypt DEK generated by the catalog.
Providing a DEK to the catalog generated by the client using the catalog private key.
Further recommendations are proposed to enforce DCS on the resource data when they are requested in the notification content.
Requirement 20 | |
---|---|
Label | /req/subscription/dcs |
Statement | If the subscriber requests resources in the notifications (HTTP Prefer header asserting a return=representation preference), then data centric security shall be applied (i.e., resources are encrypted) if the resource-uri specifies the dcs+geo format (f parameter). |
A | The catalog shall encrypt the data using the DEK provided by the client and return the DEK identifier (if wrapped_dek property is provided). |
B | The catalog shall generate a DEK to encrypt the data and return the DEK encrypted using the client public key (if public-key property is provided). |
6.2.3. Record Insertions With DCS
According to clause 2.3.1 of the CFP, publishers shall be able to send new or updated content to the catalog server with encrypted content that fulfills DCS principles. This implies that the catalog server acts as a (DCS) client receiving DCS encrypted content and must implement the steps a client typically applies as described in OGC 21-020r1.
6.3. Proposed Interface Design
6.3.1. Synchronous Responses With DCS (Encryption)
The diagram below is the proposed resource definition diagram for an OGC API-Records implementation with support for DCS (encryption).
Figure 13 — Resource Definition Diagram for OGC API-Records With DCS (Synchronous Responses)
Figure 14 — Resource Diagram /Collections/{collectionId}/Items
6.3.2. Asynchronous Responses With DCS
As mentioned earlier, when notifications are requested for including the records (with the return-representation preference), the content must be encrypted for applying Data Centric Security.
The following flow extends the OGC API-Records asynchronous flow with DCS.
The Catalog Client (on the behalf of a signed user) submits a subscription request to the Catalog server (with the return-representation preference). The request includes either the public-key or wrapped-dek property (detailed further).
The Catalog server registers the subscription and returns HTTP code 201 along the link to the created subscription.
Each time the server prepares a notification, the records are encrypted depending on the selected security approach.
Figure 15 — DCS Async Sequence Diagram
6.3.2.1. Subscriber Submits a DEK
The subscriber might submit a DEK generated locally then used by the catalog to return the resources encrypted in the notifications. The notification content is encoded in a JWE token with a header mentioning the kid (client DEK identifier) for decrypting the notification payload. The major drawback of this method is the reuse of the same encryption key for all notifications, potentially for years.
In the request, the subscriber provides the wrapped-dek property which holds the JWE token that includes the encrypted JWK encoding of the client DEK. The client DEK is encrypted with the catalog public key advertised on /.well-known/jwks.json with the attribute use set to enc.
The following subscription flow applies to a notification encryption based on a DEK generated by the client.
The catalog client (on the behalf of a signed user) retrieves the catalog server public key.
The catalog client generates the DEK and encrypts the DEK using the catalog public key.
The catalog client submits a subscription request to the catalog server and provides the encrypted DEK in the wrapped_dek property.
The catalog server decrypts the DEK with the private key.
For each notification, the catalog server encrypts the data records with the DEK.
The receiver service of the catalog client decrypts the data with the DEK.
Figure 16 — Notifications With DCS (Client Sends the DEK) Sequence Diagram
6.3.2.2. Subscriber Submits Public Keys
The subscriber might submit a public key used to return the DEK that will be created by the catalog. The subscriber provides the public_key property which consists of a JWK public key.
In the notifications, the resources are encoded in a JWE token which includes the DEK encoded with the public key.
The following subscription flow applies to a notification encrypted based on a DEK generated by the catalog server.
The catalog client submits a subscription request to the Catalog server and provides a public key in the public_key property.
For each notification, the catalog server generates a DEK and sends the encrypted notification along with the JWE token holding the DEK encrypted with the client public key.
The receiver service of the catalog client decrypts the DEK with the private key, then decrypts the notification content with the DEK.
Figure 17 — Notifications with DCS (Catalog Generates the DEK) Sequence Diagram
As the solution also has be implemented using an HTTP GET operation, the recommendation below applies for the alternative operation.
Recommendation 17 | |
---|---|
Statement | When provided in an HTTP GET request, the public key used to return the DEK should be encoded using the deepObject style as per OpenAPI 3.0 – simple non-nested objects are serialized as paramName[prop1]=value1¶mName[prop2]=value2&… |
6.3.2.3. Callback Endpoint Security Concerns
The notification endpoints (email address or HTTP(S) URL) must be validated by the service for the following reasons:
to prevent unsolicited content for existing endpoints; and
to avoid spamming servers for invalid endpoints.
Recommendation 18 | |
---|---|
Statement | The server SHOULD only deliver notifications to an email delivery endpoint if a link containing a secret code and delivered to the target email address has ben clicked by the receiver (to confirm the subscription). |
Recommendation 19 | |
---|---|
Statement | The server SHOULD only deliver notifications to an HTTP(s) delivery endpoint if a TBD. |
6.3.3. Record Insertions With DCS
Publishers need to send new or updated content to the catalog server so that the interested parties can be notified as elaborated in the asynchronous communication related sections of this ER.
DCS principles might be applied to encrypt the content submitted on the catalog. This implies that the catalog server acts as a DCS client receiving DCS encrypted content, and is required to implement the steps a client typically applied as described in the Testbed-17: Data Centric Security ER (OGC 21-020r1).
For applying DCS to the OGC API-Records insert operation, Testbed participants proposed relying on the private key of the catalog. The public asynchronous encryption key can be advertised in /.well-known/jwks.json.
Recommendation 20 | |
---|---|
Statement | The records inserted in a catalog should be encoded using the catalog public key provided in the /.well-known/jwks.json endpoint (with key entry provided with attribute use set with value ‘enc’). |
The cty (content type) attribute of the Javascript Object Signing and Encryption (JOSE) header (i.e., first part of the JWE) should be set to the media type of the metadata record to be inserted in the catalog. For example, the value “geo+json” corresponds to “application/geo+json”, while “vnd.iso.19139+xml” corresponds to “application/vnd.iso.19139+xml”. This allows the receiving catalog to know what it should obtain after decryption.
The sequence required for applying DCS to a catalog record is illustrated on the diagram below and includes the following steps.
The catalog client (publisher) retrieves the JSON Web Key Set (JWKS) containing the public key required for encrypting published content. The relevant key is the key item holding the ‘enc’ value (for encoding) in the use attribute.
The catalog client encrypts the content with the catalog public key and submits the request to the catalog server.
Typically, in an isolated secured runtime environment behind the catalog server, the submitted encrypted records are decrypted with the private key.
Once the decryption is achieved, the record is added to the catalog database and the catalog client receives the confirmation response.
Figure 18 — Publisher with DCS sequence diagram
See Annex A Example 3.4 for a detailed Jupyter Notebook example using the POST operation and application/jose media type for publishing a metadata record.
The above sequence can be combined with asynchronous communication as illustrated in the diagram below.
The catalog client (publisher) retrieves the JSON Web Key Set (JWKS) containing the public key required for encrypting published content. The relevant key is the key item holding the ‘enc’ value (for encoding) in the use attribute.
The catalog client receives confirmation of the processing job handling the request.
The catalog client encrypts the content with the catalog public key and submits the request to the catalog server.
Typically, in an isolated secured runtime environment behind the catalog server, the submitted encrypted records are decrypted with the private key.
Once the decryption is performed, the record is added to the catalog database and the callback endpoint submitted by the catalog client receives a notification.
Figure 19 — Publisher with DCS sequence diagram + Subscriber
6.3.4. Synchronous Responses With DCS (Signatures)
To address the integrity and authenticity requirements, metadata records or catalog responses can be encoded, returned, or made available in the JWS format [RFC 7515]. The structure of the JWS token (in Compact Serialization) is a special case of a JWT token [RFC 7519].
It contains three logical parts:
JOSE Header
JWS Payload
JWS Signature
These are the main header properties:
Table 5 — JWS header parameter names
Property | Meaning | Reference |
typ | Type — declares the IANA media type of this complete JWS. The values JOSE and JOSE+JSON are defined in the JWS specification and apply to both JWS and JWE tokens. | JWT [RFC 7519] |
cty | Content Type — declares the IANA media type of the secured content (the payload). | JWT [RFC 7519] |
jwk | JSON Web Key | JWS [RFC 7515] |
jku | JWK Set URL | JWS [RFC 7515] |
alg | Algorithm | JWS [RFC 7515] |
kid | Key ID — indication or a hint about the key, which is used to sign the message. | JWS [RFC 7515] |
See Annex A Example 3.5 for an example using the JWS (Compact Serialization) format. This example uses the public key included in the response to validate the signature.
To ensure that the public key is actually the expected sender’s, the signature can also be validated with the public key advertised by the sender as shown in Annex A Example 3.6.
JWS can also be serialized as JSON using the “JWS JSON Serialization”. This serialization can represent multiple signatures which is not possible with the “Compact Serialization”.
For use cases where the base64url encoding of the payload (metadata record or response) is not desired, the use of “JSON Web Signature (JWS) Unencoded Payload Option” [RFC 7797] can be considered. This option is to be further explored as future work.
A simpler approach “JWS Clear Text JSON Signature Option (JWS/CT)” [7] preserves the original JSON representation of a metadata record entirely and adds a signature key in the root of the JSON object with the value of the JWS (Compact Serialization) string (first and third part). Before computing the JWS string, the JSON object is made canonical using JCS [RFC 8785]). This option is attractive for static catalogs where metadata files are put as JSON files on cloud storage (S3). This permits the full readability of the original metadata record. This approach can for instance be applied to the following.
OGC API-Records metadata records and crawlable catalogs
OGC 17-003r2 metadata records
STAC item metadata records
This option is only applicable to JSON-encoded metadata records (or responses) and will be further explored in future work. Signature creation and verification for JWS/CT is shown in Annex A Example 3.7 and Example 3.8.
7. Software Design
7.1. Software Static Architecture
The diagram below shows the original allocation of components to the different Testbed participants.
Figure 20 — Component allocation
As part of the Testbed-18 Secure, Asynchronous Catalogs task, the following client and server-side components were deployed and used for integration testing.
7.2. Interfaces Context
The figure below shows the interactions between the various components and the interfaces that were used.
Figure 21 — Component Diagram
7.2.1. I/F KMS — Interface with Key Management System
The interface with the Key Management System (KMS) is of particular importance as most components need to interact with the KMS. The interface is defined in detail in the corresponding Engineering Report OGC 22-014. The diagrams below give an overview of this RESTful interface in terms of its different resources.
Figure 22 — Resource Diagram (/dek)
Figure 23 — Resource Diagram (/dek/{key_id})
Figure 24 — Resource Diagram (/kek)
Figure 25 — Resource Diagram (/kek/{key_id})
7.3. Software Components Design
7.3.1. D112 — OGC CSW Catalog Server
Endpoint: https://cat.csiss.gmu.edu/ows18
Client Partner guide: https://cat.csiss.gmu.edu/CSW_Client-Guide.pdf
The OGC CSW Standard stipulates the interfaces for catalog services. The interfaces are divided into three categories: OGC service interface, CSW discovery interface, and CSW manager interface. Specifically, the GetCapabilities operation is the OGC service interface that provides summary information of the CSISS CSW catalog. The operations in the CSW discovery interface include GetRecords, GetRecordById, DescribeRecord, and GetDomain. The operations in the CSW manager interface include Transaction and Harvest. Asynchronous processing is supported for GetRecords and Harvest requests (via csw:ResponseHandler). The CSW server supports three modes of the Transaction operation (Insert, Update, Delete).
Unlike many other agencies that rely on commercial on-demand cloud infrastructure such as Amazon Web Service (AWS), the Center for Spatial Information Science and Systems (CSISS) developed a private cloud to provide services for EO data. The private cloud was developed using Apache Cloud stack and provides virtual machines to multiple operational services hosted by CSISS (including the CSISS CSW server in Testbed 18). Currently, there are more than 300 GPU cores, over 500GB RAM, and more than 500 TB storage, as well as a cluster of NVIDIA Tesla K80 GPUs on the server. The resources available continue to expand. To ensure the safety and reliability of operational services, all machines are hosted at the CSISS Data Center, George Mason University. Thanks to the Center’s state-of-the-art UPS systems, the data center can provide continuous power support during a power interruption. Also, the Center is monitored 24 hours a day, 7 days a week to prevent any potential risk.
Figure 26 — CSISS CSW Server System Architecture
7.3.2. D113 — OGC API-Records Catalog Server
Endpoint: https://ogc.demo.secure-dimensions.de/pycsw
Software: https://github.com/securedimensions/pycsw/tree/tb18
Figure 27 — D113 - OGC API-Records Catalog User Interface
For Testbed 18, the OGC API-Records implementation provided by pyCSW (https://github.com/geopython/pycsw) was extended with the following specific functionalities.
Publishing of records via HTTP POST and PUT with support for different content types: application/json, application/jose (JWE format).
Requesting records in different DCS formats: application/jose (JWS and JWE), application/dcs+geo.
Support for HTTP header “Preference” to trigger asynchronous responses via the generic parameter “subscription.”
The Catalog Service user interface and OpenAPI contain additional functionalities that allow the different DCS formats to be requested. The responses “links” section was extended with the DCS formats.
The Catalog Service has implemented RFC 6750 behavior (Bearer access token use) when requesting DCS formats or when publishing a record.
For development support, the additional functionality is available via OpenAPI.
One of the biggest challenges was how to extend an existing open source implementation (pyCSW) so that it supports DCS without changing the original code. This was nearly achieved. Most of the functionality was included in the flask wrapper using Python decorator and additional routes (POST and PUT). Only a few changes were actually required in the “ogc/api/records.py” file, mainly to support the rendering of additional links in the link section
The implementation of the record publishing (HTTP POST and PUT) is considered a prototype for demonstration only. The implementation DOES NOT check the uploaded data for malicious / dangerous code. So, DO NOT USE IN PRODUCTION!
The actual overhead associated with producing JWE or JWS is very minimal, because a record is only a few kilobytes in size. Because of the expected record size as a few kB, all cryptographic operations take place in main memory. This approach is fine for processing a single record but already may consume noticeable main memory and produce processing latency when requesting a JWS or JWE for a collection of records. So, DO NOT USE IN PRODUCTION.
The catalog server is hosted on Gunicorn (Python WSGI server) behind NGINX on Ubuntu 22.04.
The catalog service implementation interacts with the Key Management Service to register symmetric encryption keys for producing DCS responses.
The catalog service implementation is used by the Subscription Management Service to execute triggers for created subscriptions.
7.3.3. D114 — Catalog Client, Subscriber, Publisher
The Catalog client is a web client built using React. The client uses the oidc-client package to handle user authentication with the Authenix server and store the all-important bearer token. Users can login with the button in the top right of the header if they require access to the Records server or Records subscriptions.
The client enables users to pull documents from both the OGC API-Records and CSW implementations using a variety of formats and security schemes. Since CSW only offers the ISO format unencrypted, this is the only format the client supports for CSW implementation instances. For OGC API-Records, the user can choose between JWE and XML formats. For the JWE format, they can specify either direct or key wrap encryption.
Figure 28 — React Client Endpoints
The metadata is visualized via a Leaflet map and a table which can be used to edit the Title of the metadata. Further work could be done to implement a more complete data editing/interaction system depending on the required use case, for example visualizing quicklook images, etc.
Figure 29 — React Client Metadata View
The JWE security functionality is enabled by the Jose NPM library. This library provides the functionality to handle the JWKs that the KMS returns when direct encryption is requested. It also deals with the asymmetric keys submitted when the user requests using key wrap. As these keys are currently hardcoded into the demo, a full implementation of this system would need to safely store those keys on a user’s device. Keys could be generated per session, but when using this encryption method the user would not be allowed to logout and then return to the session.
The resource card row enables the user to view, store, and upload stored documents to either a CSW or an API-Records instance via the upload form.
Figure 30 — React Client Upload Form
The client also provides a form for creating subscriptions to the API-Records server. This currently only allows the user to subscribe to email notifications at a fixed interval, but could be extended further in future.
Figure 31 — React Client Full Page
7.3.5. D115.2 — Key Management Server
The Key Management Server in the OGC Testbed 18 is identical to the Testbed 17 implementation. The details of the KMS can be found in section 5.4 of the OGC 21-020r1
7.3.6. Jupyter Notebook Client
This client is implemented as a Jupyter Notebook. When run locally, such as using with VS-Code as depicted below, the Notebook interfaces with the Authorization & Identity Management System (D115) authenticating the user and retrieving the user’s access_token.
Figure 32 — Jupyter Notebook Client interaction with D115
In addition, the client demonstrates how ISO19139 Earth Observation metadata records describing series and dataset retrieved from the ESA FedEO server (EOVOC), can be inserted for use in the OGC API Server without modification. See also Example 3.4.
Figure 33 — Jupyter Notebook Client
The Notebook can be run in the Google Colaboratory environment as well as it is depicted below.
Figure 34 — Jupyter Notebook Client running in Google Colab
The source code of the Jupyter Notebook is included as Annex A. The Notebook code acts as a client to many of the server components as shown below.
Figure 35 — Component Diagram Jupyter Notebook
8. Future Work
8.1. Asynchronous Communication
8.1.1. Include Reference to Subscription Endpoint
Possibly use rel=’monitor’ link as defined by RFC 5989 to the /subscriptions/{subscription-id} endpoint which monitors the HTTP resource (i.e., search request) which produced the search result(s) in the search response (FeatureCollection).
Similarly, a subscription endpoint available for an OGC API-Records service should be discoverable in the landing page of the OGC API-Records service (in addition to being described in its OpenAPI definition) to allow clients to choose between the synchronous or the asynchronous interfaces.
8.1.2. OGC API-Notification Service
Propose Webhooks for an OGC API-Notification Service specification for other services besides Records which should work with the PubSub SWG.
8.1.3. Notification Content
The subscription prototype backend performs a periodic check as to whether the response corresponding to the resources-uri in the subscription object is identical or not to the original response. If not, then the same resources-uri is sent to the subscriber according to the delivery mechanism that was selected.
If the resources-uri corresponds to a single item (e.g., /items/{item-id}), then this means that the record content has changed. If the resources-uri corresponds to a search request (e.g., /items?…), then this means that the (first result page) of the response has changed.
A number of improvements are possible.
In the case of a search request, changes should be detected that affect not only the first result page (e.g., first n results and information about total number of hits). A deletion followed by an insertion, keeping the total number of results identical, may not be detected.
In case resources-uri corresponds to a search request, the client should have the option to receive the actual changes, instead of a repetition of the full set of results. This is particularly useful for very large collections or searches with many results. A mechanism to receive information about deleted records is required in particular when the notification mechanism would be applied for supporting incremental harvesting. A mechanism similar to the Atom deleted-entry Element [RFC-6721] might be applied. The Open Archive Initiative Protocol for Metadata Harvesting [OAI-PMH], which is still widely used, has support for deleted records.
When a resource-uri corresponds to a search result, e.g., “all records with datetime overlapping with date-1 and date-2”, it might be useful to indicate in a subscription that the dates are to be interpreted as relative with respect to the actual time the subscription check is executed, instead of interpreting dates always as absolute dates.
8.1.4. Asynchronous Patterns for OGC API Common
A significant topic for future activities should be exploring how asynchronous communications can be addressed at the OGC API Common level. In the context of other APIs, asynchronous communications must address a wider range of concerns than for OGC API Records, as show in the following examples.
A server might handle requests asynchronously for preparing the results (single response), or in response to certain events (multiple responses).
A client should specify the preferred behavior for retrieving the delayed response(s) either actively (polling pattern) or passively (push pattern requiring a listener endpoint).
The next subsections propose patterns to address general OGC API concerns related to asynchronous communications.
The asynchronous pattern for delayed response provides a simple solution to query (poll) a URL until the response is ready.
The callback pattern for delayed response complements the asynchronous pattern for specifying an endpoint for receiving (push) the response(s).
The OGC API Common Asynchronous requirement class is a draft that generalizes the API records asynchronous solution relying on jobs resources.
8.1.4.1. Asynchronous Pattern for Delayed Response
Implementations of OGC APIs typically use a communication protocol pattern based on a single socket pair for sending and receiving an HTTP(S) request / response. The handling of slowly resolved queries that are not ready within the regular HTTP time out (i.e., roughly 30 seconds) can be addressed using a simple communication pattern (not implying the subscription resources solution detailed earlier).
The proposed standard RFC 7240 “Prefer Header for HTTP” recommends using the ‘Prefer’ header to indicate the server behavior preferred by the client. As already adopted by OGC API Processes, the “respond-async” preference indicates that the client prefers the server to respond asynchronously to a response. In addition, the value respond-async, wait=10 is a hint to the server that the client expects a maximum of 10 seconds to return the response following the traditional synchronous pattern.
RFC 7240 mentions that the server honoring the “respond-async” preference should return a 202 (Accepted) response as per HTTP 1.1 (RFC 7231). However, the actual behavior is unspecified, and little guidance is provided by code 202 (“The representation sent with this response ought to describe the request’s current status and point to (or embed) a status monitor that can provide the user with an estimate of when the request will be fulfilled”). For the above reason, some Testbed participants also proposed considering the alternative code 303: See Others. “See Other” is a way to redirect web applications to a new URI, particularly after a HTTP POST has been performed.
Independent of the response code, the server should return a Location header (and an optional Retry-After header) holding a link to the target requested resources. The link to the target resources can monitor the status of the previous request until the resources are available. The structure of the monitor response is custom as it needs to fit the purpose. But, to ensure that the caller is not too proactive, the server may throttle the caller via 429 (too many requests: Retry-after).
Figure 36 — Asynchronous Pattern for Delayed Response
8.1.4.2. Callback Pattern for Delayed Response
Complementary to the asynchronous pattern described above, the request might be extended to submit an endpoint URI for receiving callback messages that contain the delayed response of the server. Indeed, as adopted by OGC API Processes, OpenAPI 3.0 provides a callback (push-based) mechanism where a subscriber-URL is passed to the API in the request. Once the resources are available, the result response is sent to the specified URL.
OpenAPI supports specifying the placeholders of the callback URI’s (potentially for a set of defined events) submitted in the request, and to define the schemas of the callback messages which must be specified in the callbacks property of the related definition of the OpenAPI operation. An example is shown below.
callbacks:
completed:
'{$request.header.Prefer}/callbackURI':
post: # Method
requestBody: # Contents of the callback message
…
responses: # Expected responses
…
Figure 37 — Generic OpenAPI Definition of the callback
For expressing the callback endpoint (and options), Testbed participants highlighted one simple approach taking advantage of the Prefer header. The header might be extended with a callback token holding the (single) endpoint for callback messages. Also, in case of multiple results (based on particular events), the frequency preference can be provided in a schedule token holding a unix-cron value.
8.1.4.3. OGC API Common Asynchronous Requirement Class
The proposed approach for a generic asynchronous requirement class relies upon the typical use of HTTP code 202. A job resource is created to monitor the execution of the request. Note that the approach is very similar and reuses most concepts from the OGC API Processes.
Recommendation 21 | |
---|---|
Label | /rec/core/process-execute-honor-prefer |
A | If a request is accompanied with the HTTP Prefer header asserting a respond-async preference, then the server should honor that preference and response asynchronously. |
B | If a request is accompanied with the HTTP Prefer header asserting a wait preference, then the server should honor that preference in the decision to execute the process asynchronously. |
C | If a request is accompanied with the HTTP Prefer header, then in the response, servers should include the HTTP Preference-Applied response header as an indication as to which ‘Prefer` tokens were honored by the server. |
Recommendation 22 | |
---|---|
Label | /req/async/response |
A | If a request is executed asynchronously, the server should respond with an HTTP status code of 202. The server should return a Location header (and an optional Retry-After header) holding a link to the job monitoring the processing of the request. |
Requirement 21 | |
---|---|
Label | /req/async/job |
A | The server shall support the HTTP GET operation for retrieving a long-running asynchronous job at the path /jobs/{jobID}. |
B | A successful execution of the operation shall be reported as a response with a HTTP status code 200. The content of that response shall be based upon the OpenAPI 3.0 schema jobStatus.yaml. |
The jobStatus schema is illustrated on the class diagram below.
Figure 38 — JobStatus Schema
Recommendation 23 | |
---|---|
Label | /req/async/prefer-callback |
A | If a request is accompanied with the HTTP Prefer header asserting a callback preference (endpoint URI), then the potential asynchronous response(s) should be pushed as a callback message delivered to the provided callback endpoint URI. |
B | If a request is accompanied with the HTTP Prefer header asserting a callback preference and a schedule UNIX-cron value, then the potential asynchronous response(s) should be pushed in respect to the submitted schedule. |
The resulting sequence diagram is provided below.
Figure 39 — Generic Asynchronous Job Sequence Diagram
The status values defined in OGC API Processes are clarified below in the context of sequential results updates (on purpose) managed by the asynchronous job.
Requirement 22 | |
---|---|
Label | /req/async/job-status |
A | The status of a job shall be accepted if the asynchronous job request is valid and has been queued for execution. |
B | The status of a job shall be running if the provided start time has been reached. |
C | The status of a job shall be failed if the asynchronous job request is not valid or if the processing of the request raised an error that prevented its completion. |
D | The status of a job shall be dismissed if the asynchronous job has been dismissed through a HTTP DELETE request. |
E | The status of a job shall be successful if the asynchronous job has completed or the end time has been reached. |
8.2. Data Centric Security
8.2.1. Request for Specific Encrypted Media Type
The application/dcs+geo (JSON-based) media type as currently defined contains a data object and a metadata object. In the current document, the data object carries the encrypted payload, i.e., an encrypted catalog /items response (GeoJSON FeatureCollection) or /items/{item-id} response (GeoJSON Feature). The content of the metadata object is use-case specific and not required for decryption purposes.
While the current document assumes that the catalog responses (after decryption) are GeojSON objects, this can be generalized to allow the encrypted payload to be used to carry the encrypted representation of other metadata formats including ISO19139, ISO19139-2, ISO19115-3, etc. The cty (content type) attribute in the JOSE header of the JWE already allows the specification of the media type (omitting “application/” when no additional “/” appears) that will result after decryption.
Similarly, it should be possible for a catalog client to request an application/dcs+geo or application/jose response and additionally specify the expected content-type (e.g., ../items?cty=vnd.iso.19139+xml) the client expects to obtain after decrypting the data object included in the application/dcs+geo or the application/jose response.
8.2.2. Generic Approach for Any OGC API
Future work should define how to apply DCS to all OGC APIs, with a JSON or XML-based container. Homogeneous solutions are preferred, allowing the use of XML or JSON encodings for all responses generated by the resources of the RESTful interface, avoiding the need to mix technologies and related tools.
8.2.3. DCS for XML via STANAG
While the above approach would allow for returning (and encrypting) XML-based responses with the JSON-based API, organizations may want to avoid mixing XML and JSON and may prefer having XML responses for all resources of the RESTful API, using an XML container (media type) for carrying encrypted XML payloads, etc., while adopting the OGC API-Records API. The STANAG 4778 container format proposed in OGC 19-016r1 may be reused for this.
8.4. DCS and Streaming
During previous OGC Testbeds, Data Centric Security was applied to different OGC APIs and Data Encoding Standards. The synchronous characteristics of OGC APIs introduce the requirement that the maximum latency of responses is limited by the socket timeout or by the acceptance to wait by the user. To keep the response waiting time short (before the first response byte is sent to the client) it is important that the data encoding can be streamed. Streaming a resource has the advantage that the first byte is more or less sent to the client immediately after the request has been received by the server. The full response is then transferred using chunk encoding. This technique reduces the burden on the server, as memory and disk space does not limit the total size of the data to be processed.
Work in previous testbeds determined that data encoding using the OGC GeoPackage Standard cannot be streamed as the underlying SQLite file format requires that the GeoPackage is processed on the server in full before the first byte is transferred to the client. However, there are other encodings that can be streamed: A GeoJSON feature collection, for example, can be produced and transferred using chunk encoding.
The research question should be addressed in the context of DCS in which geospatial data encoding is streaming-ready and can be used in combination with DCS. For example, is it possible to produce a JWS or JWE containing a feature collection in chunks to minimize the burden on the server’s memory and disk space? Is it possible to create a STANAG 4774/4778 response in XML or JSON based on chunks? Is it possible to use a similar protocol like HLS (RFC 8216) to stream large volumes of encrypted data? Is it possible to support streams and byte ranges for encrypted data?
So a future task could be to study OGC Encoding Standards and determine their streaming capabilities and recommend their use with and without DCS applied based on prototype implementations.
8.5. DCS in Production
Both previous Testbeds and this one introduced DCS building blocks that extend the typical geodata infrastructure architectures with specific services: Authentication, Key Management, and the Subscription Service. The latter was introduced as a generic solution to handle synchronous to asynchronous communication bridging supporting WebPush and Web Callback including security and email.
To operate the architecture and APIs in a production environment, it is important to not only have covered the green flow of information. Software engineers also should consider the red flow: Which vulnerabilities exist in the protocols, APIs, and implementations that may enable an adversary to attack certain parts of the system.
For example, the use of (simple) Bearer access tokens on the Key Management System introduces the vulnerable to token replay attacks. An attacker, in possession of an active access token from another user could obtain all keys of that the user. Even worse, perhaps, delete existing keys. Other vulnerabilities may be introduced by implementations that support the user’s ability to upload data. In these cases, implementation vulnerabilities like SQL or XSS code injection may exist that can cause data or key breach.
The research question would be to determine what vulnerabilities exist in the current Testbed DCS architecture and in existing open-source implementations by applying security best practices from the IETF (e.g., 6819), W3C, and others. For example the security recommendation for using Bearer access tokens (draft RFC ‘OAuth 2.0 Security Best Current Practice’) introduce various attack vectors. Can these attack vectors be applied to the DCS architecture and what harm would they do if successfully executed?
Another research question is related to performance and scalability. The ultimate aspect for scalability is to keep the server side (upstream applications) stateless and to reduce burden on the resources to the minimum. Can that be achieved with the current DCS architecture? Which limitations and implications to scalability and performance exist?
8.6. Demonstrating Proof of Possession Access Token
The use of bearer access tokens is widely adopted but vulnerabilities to misuse stolen access tokens introduce a threat to DCS: Once a user has gotten an access token, it can be used with no further proof. So for example, a stolen active access token can be used for obtaining sensitive (encrypted) information and data encryption keys. This jeopardizes all efforts put into DCS.
The use of OAuth 2.0 Demonstrating Proof-of-Possession at the Application Layer (DPoP) as defined in the IETF draft standard1 thwarts the successful use of stolen access tokens.
Future work should concentrate on studying the principles for using DPoP access (and refresh) tokens on a DCS architecture as outlined in Testbed 18. In particular, the use of DPoP access tokens bound to a resource URI or tagged for one time use should be studied and implemented with the DCS Server and the KMS to demonstrate the improvement over the use of bearer access tokens. This may require operating two infrastructures in parallel; one that operates bearer access tokens and one that operates DPoP access tokens. Successfully executed attacks with bearer access tokens should not be possible with the infrastructure that is based on DPoP.
8.7. My-(OGC) API
Leveraging DCS, it is possible to manage sensitive data (features) and metadata (records). Any publishing of records or features should be associated with a user. That user would have the authority over how to preserve continuous sensitivity / integrity. So, the end-to-end sensitivity / authenticity should be supported via OGC APIs.
Is it possible to introduce the concept of ownership for OGC APIs? Should the owner of a resource have the authority over the resource’s protection? Furthermore, queries for “my” resources and “Jane’s resources” would be possible. This would be an important step towards the use of OGC APIs in Citizen Science.
What would be required to apply the “my” characteristics to OGC APIs and, in particular, DCS extensions?
Annex A
(informative)
Notebook Secure Catalog
By Y. Coene, C. Noel (Spacebel s.a.), A. Matheus (Secure Dimensions GmbH), 21 October 2022
%pip install pyjwt
%pip install folium
%pip install jsonpath-ng
%pip install jcs
import json, requests, xml
from xml.dom import minidom
from xml.etree import ElementTree
from IPython.display import Markdown as md
import folium
# Verification of SSL certificate.
verify_ssl = True
endpoint_csw = 'https://cat.csiss.gmu.edu/ows18/csw'
endpoint_api_records = 'https://ogc.demo.secure-dimensions.de/pycsw'
endpoint_collection = endpoint_api_records + '/collections/metadata:main'
endpoint_items = endpoint_collection + '/items'
endpoint_queryables = endpoint_collection + '/queryables'
# URL to an item inserted in the catalog before.
endpoint_item = endpoint_items + '/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001'
endpoint_subscriptions = 'https://ogc.demo.secure-dimensions.de/sms/subscriptions'
def add_feature_to_map( m, fdata ):
# fdata is JSON dictionary representing a Feature
# modifies the map 'm'
key = 'geometry'
if key in fdata:
c = fdata[key]['coordinates']
# create string with coordinates without separators
polygon=str(c).translate(str.maketrans('','','[],'))
list1 = polygon.split()
points = []
for i in range(0,len(list1),2):
points = points + [ (float(list1[i+1]), float(list1[i])) ]
folium.FitBounds(points, padding=(100,100)).add_to(m)
folium.Polygon(points, popup=str(fdata), tooltip=fdata['id']).add_to(m)
return
def show_on_map( data ):
# data is JSON dictionary representing a FeatureCollection or Feature
center = [38.128, 2.588]
m = folium.Map(location=center,zoom_start=2)
folium.LayerControl().add_to(m)
key = 'geometry'
if key in data:
add_feature_to_map(m, data)
return m
# contains featurecollection or feature
key = 'features'
if key in data:
n = len(data[key])
if (len(data[key])<1) : return m
key = 'geometry'
j=0
while (j<n):
fdata = data['features'][j] # use current feature of collection
add_feature_to_map(m, fdata)
j=j+1
return m
Figure A.1
Requirement already satisfied: pyjwt in c:\users\yvesc\appdata\local\programs\python\python38\lib\site-packages (2.4.0) [notice] A new release of pip available: 22.1.2 -> 22.3 [notice] To update, run: python.exe -m pip install --upgrade pip Note: you may need to restart the kernel to use updated packages. Requirement already satisfied: folium in c:\users\yvesc\appdata\local\programs\python\python38\lib\site-packages (0.12.1.post1) Requirement already satisfied: jinja2>=2.9 in c:\users\yvesc\appdata\local\programs\python\python38\lib\site-packages (from folium) (3.1.2) Requirement already satisfied: numpy in c:\users\yvesc\appdata\local\programs\python\python38\lib\site-packages (from folium) (1.21.4) Requirement already satisfied: branca>=0.3.0 in c:\users\yvesc\appdata\local\programs\python\python38\lib\site-packages (from folium) (0.5.0) Requirement already satisfied: requests in c:\users\yvesc\appdata\local\programs\python\python38\lib\site-packages (from folium) (2.26.0) Requirement already satisfied: MarkupSafe>=2.0 in c:\users\yvesc\appdata\local\programs\python\python38\lib\site-packages (from jinja2>=2.9->folium) (2.1.1) Requirement already satisfied: idna<4,>=2.5 in c:\users\yvesc\appdata\local\programs\python\python38\lib\site-packages (from requests->folium) (2.10) Requirement already satisfied: urllib3<1.27,>=1.21.1 in c:\users\yvesc\appdata\local\programs\python\python38\lib\site-packages (from requests->folium) (1.25.10)Note: you may need to restart the kernel to use updated packages. Requirement already satisfied: certifi>=2017.4.17 in c:\users\yvesc\appdata\local\programs\python\python38\lib\site-packages (from requests->folium) (2020.6.20) Requirement already satisfied: charset-normalizer~=2.0.0 in c:\users\yvesc\appdata\local\programs\python\python38\lib\site-packages (from requests->folium) (2.0.7) [notice] A new release of pip available: 22.1.2 -> 22.3 [notice] To update, run: python.exe -m pip install --upgrade pip Requirement already satisfied: jsonpath-ng in c:\users\yvesc\appdata\local\programs\python\python38\lib\site-packages (1.5.3) Requirement already satisfied: six in c:\users\yvesc\appdata\roaming\python\python38\site-packages (from jsonpath-ng) (1.15.0) Requirement already satisfied: ply in c:\users\yvesc\appdata\local\programs\python\python38\lib\site-packages (from jsonpath-ng) (3.11) Requirement already satisfied: decorator in c:\users\yvesc\appdata\roaming\python\python38\site-packages (from jsonpath-ng) (4.4.2) [notice] A new release of pip available: 22.1.2 -> 22.3 [notice] To update, run: python.exe -m pip install --upgrade pip Note: you may need to restart the kernel to use updated packages. Requirement already satisfied: jcs in c:\users\yvesc\appdata\local\programs\python\python38\lib\site-packages (0.2.1) [notice] A new release of pip available: 22.1.2 -> 22.3 [notice] To update, run: python.exe -m pip install --upgrade pip Note: you may need to restart the kernel to use updated packages.
Figure A.2
A.1. D115 (Identity Mgt System) authentication
if 'google.colab' in str(get_ipython()):
# Running in Google Colab
access_token = input("Enter access token obtained from https://ogc.demo.secure-dimensions.de/token-app/ :")
else:
# Not running in Google Colab
# Authenticate via Notebook from Secure Dimensions to obtain the "access_token".
%run ./authenix.ipynb
Figure A.3
Random string of length 4 is: jghh Listening on port 8008 ... GET /?code=9dfdd77a5e8936aea35c99995ec4918d43344e45&state=None HTTP/1.1 Host: 127.0.0.1:8008 Connection: keep-alive Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Sec-Fetch-Site: none Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Sec-Fetch-Dest: document sec-ch-ua: "Chromium";v="106", "Google Chrome";v="106", "Not;A=Brand";v="99" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "Windows" Accept-Encoding: gzip, deflate, br Accept-Language: en-GB,en-US;q=0.9,en;q=0.8 Warning: state does not match! 9dfdd77a5e8936aea35c99995ec4918d43344e45
Figure A.4
A.1.1. D115 (Identity Mgt System) Get access token
access_token
Figure A.5
'4e6e701e0eb6a7d13e76b33da136fa07a2c4d7fc'
Figure A.6
A.2. D113 (OGC API-Records) without DCS
A.2.1. D113 GET /items without DCS (GeoJSON)
Example: 1.1
> Access the OGC API-Records D113 /items without DCS (GeoJSON)
response = requests.get(endpoint_items + '?limit=2&offset=8',
verify=bool(verify_ssl),
headers={'Accept': 'application/geo+json'})
data = json.loads(response.text)
jstr = json.dumps(data, indent=3)
md("```json\n" + jstr + "\n```\n")
Figure A.7
{
"type": "FeatureCollection",
"features": [
{
"id": "9d075d6f-a85a-18fa-1f51-ced8-ef7c-5bce-a91eee54",
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
2.52,
50.64
],
[
2.52,
51.51
],
[
5.94,
51.51
],
[
5.94,
50.64
],
[
2.52,
50.64
]
]
]
},
"properties": {
"externalId": "9d075d6f-a85a-18fa-1f51-ced8-ef7c-5bce-a91eee54",
"datetime": "2022-07-01",
"start_datetime": null,
"end_datetime": null,
"recordUpdated": "2022-07-21T22:40:13Z",
"type": "service",
"created": "2013-05-27",
"updated": "2022-07-01",
"title": "WMS Vlaamse Landmaatschappij",
"description": "Web Map Service met data van de Vlaamse Landmaatschappij.",
"keywords": [
"OGC:WMS",
"bodemeenheid",
"bodemkaart",
"gegeneraliseerde bodemkaart voor Vlaanderen",
"infiltratiekenmerk",
"kwel",
"kwetsbaarheid",
"landinrichting",
"landschapseenheid",
"plattelandsbeleid",
"reli\u00ebf",
"ruimtelijke structuren in Vlaanderen",
"inrichtingsproject",
"landinrichtingsplan",
"landinrichtingsproject",
"onderzoek",
"planprogramma",
"vastgesteld",
"afbakening",
"planbegeleidingsgroep",
"inrichtingsnota",
"recht van voorkoop",
"rvv",
"voorkoopgebied",
"voorkooprecht",
"blokgrens",
"kavelplan",
"landeigendom",
"ruilverkaveling",
"ruilverkavelingsproject",
"sectie",
"gebruiksruil",
"infrastructuurwerken",
"natuurbehoud",
"natuurinrichting",
"natuurinrichtingsproject",
"gebied met recht van voorkoop",
"focusgebied",
"grondwater",
"mestdecreet",
"mestactieplan",
"nitraat",
"nitraatconcentratie",
"nitraatresidu",
"nitraatresidudrempelwaarde",
"nitraatresidustaal",
"oppervlaktewater",
"overschrijding",
"waterkwaliteit",
"beheerovereenkomst",
"agromilieu-klimaatmaatregel",
"ecosysteemdienst",
"plattelandsontwikkeling",
"landbouwbeleid",
"PDPO",
"GLB",
"agrobiodiveristeit",
"gebiedstype"
],
"associations": [
{
"href": "https://geoservices.informatievlaanderen.be/raadpleegdiensten/VLM/wms?service=WMS&request=getcapabilities",
"name": "Capabilities van de webdienst WMS Vlaamse Landmaatschappij",
"description": null,
"type": "OGC:WMS",
"rel": "OGC:WMS"
},
{
"href": "https://geoservices.informatievlaanderen.be/raadpleegdiensten/VLM/wms",
"name": null,
"description": null,
"type": null,
"rel": null
},
{
"href": "https://geoservices.informatievlaanderen.be/raadpleegdiensten/VLM/wms",
"name": null,
"description": null,
"type": null,
"rel": null
},
{
"href": "https://geoservices.informatievlaanderen.be/raadpleegdiensten/VLM/wms",
"name": null,
"description": null,
"type": null,
"rel": null
}
],
"extent": {
"spatial": {
"bbox": [
[
2.52,
50.64,
5.94,
51.51
]
],
"crs": "http://www.opengis.net/def/crs/OGC/1.3/CRS84"
}
}
},
"links": [
{
"rel": "via",
"type": "application/xml",
"title": "This document as XML",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/9d075d6f-a85a-18fa-1f51-ced8-ef7c-5bce-a91eee54?f=xml",
"hreflang": "en-US"
}
],
"assets": {}
},
{
"id": "PR1_OPER_CHR_MO1_1P_20181005T134600_N51-350_E003-170_0001",
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
3.07,
51.29
],
[
3.07,
51.39
],
[
3.28,
51.39
],
[
3.28,
51.29
],
[
3.07,
51.29
]
]
]
},
"properties": {
"externalId": "PR1_OPER_CHR_MO1_1P_20181005T134600_N51-350_E003-170_0001",
"datetime": "2022-06-30T14:09:50",
"start_datetime": "2018-10-05T13:46:00Z",
"end_datetime": "2018-10-05T13:50:00Z",
"recordUpdated": "2022-07-21T22:40:13Z",
"type": "dataset",
"created": "2019-05-22",
"updated": "2022-06-30T14:09:50",
"title": "Proba CHRIS Level 1A",
"description": "CHRIS acquires a set of up to five images of each target during each acquisition sequence, these images are acquired when Proba-1 is pointing at distinct angles with respect to the target. CHRIS Level 1A products (supplied in HDF data files, version 4.1r3) include five formal CHRIS imaging modes, classified as modes 1 to 5: \u2022 MODE 1: Full swath width, 62 spectral bands, 773nm / 1036nm, nadir ground sampling distance 34m @ 556km \u2022 MODE 2 WATER BANDS: Full swath width, 18 spectral bands, nadir ground sampling distance 17m @ 556km \u2022 MODE 3 LAND CHANNELS: Full swath width, 18 spectral bands, nadir ground sampling distance 17m @ 556km \u2022 MODE 4 CHLOROPHYL BAND SET: Full swath width, 18 spectral bands, nadir ground sampling distance 17m @ 556km \u2022 MODE 5 LAND CHANNELS: Half swath width, 37 spectral bands, nadir ground sampling distance 17m @ 556km All Proba-1 passes are systematically acquired according to the current acquisition plan, CHRIS data are processed every day to Level 1A and made available to ESA users. Observation over a new specific area can be performed by submitting the request to add a new site to the acquisition plan.",
"associations": [
{
"href": "https://tpm-ds.eo.esa.int/oads/data/PROBA1-CHRIS/PR1_OPER_CHR_MO1_1P_20181005T134600_N51-350_E003-170_0001.SIP.ZIP",
"name": "Download",
"description": null,
"type": "WWW:DOWNLOAD",
"rel": "WWW:DOWNLOAD"
},
{
"href": "http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/browse/PR1_OPER_CHR_MO1_1P_20181005T134600_N51-350_E003-170_0001.SIP.ZIP_BID.PNG",
"name": "QUICKLOOK",
"description": null,
"type": null,
"rel": null
},
{
"href": "http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/thumbnail/PR1_OPER_CHR_MO1_1P_20181005T134600_N51-350_E003-170_0001.SIP.ZIP_TIMG.jpg",
"name": "THUMBNAIL",
"description": null,
"type": null,
"rel": null
}
],
"extent": {
"spatial": {
"bbox": [
[
3.07,
51.29,
3.28,
51.39
]
],
"crs": "http://www.opengis.net/def/crs/OGC/1.3/CRS84"
}
}
},
"links": [
{
"rel": "via",
"type": "application/xml",
"title": "This document as XML",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20181005T134600_N51-350_E003-170_0001?f=xml",
"hreflang": "en-US"
}
],
"assets": {}
}
],
"links": [
{
"rel": "alternate",
"type": "application/dcs+geo",
"title": "This document as DCS + GeoJSON",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items?limit=2&offset=8&f=dcs+geo",
"hreflang": "en-US"
},
{
"rel": "alternate",
"type": "application/jose",
"title": "This document as JOSE + GeoJSON",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items?limit=2&offset=8&f=jose",
"hreflang": "en-US"
},
{
"rel": "alternate",
"type": "application/jose;profile=jws",
"title": "This document as JWS",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items?limit=2&offset=8&f=jws",
"hreflang": "en-US"
},
{
"rel": "self",
"type": "application/geo+json",
"title": "This document as GeoJSON",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20181005T134600_N51-350_E003-170_0001?f=json",
"hreflang": "en-US"
},
{
"rel": "alternate",
"type": "text/html",
"title": "This document as HTML",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20181005T134600_N51-350_E003-170_0001?f=html",
"hreflang": "en-US"
},
{
"rel": "collection",
"type": "application/json",
"title": "Collection URL",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main",
"hreflang": "en-US"
},
{
"type": "application/geo+json",
"rel": "prev",
"title": "items (prev)",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20181005T134600_N51-350_E003-170_0001?offset=6",
"hreflang": "en-US"
},
{
"rel": "next",
"type": "application/geo+json",
"title": "items (next)",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20181005T134600_N51-350_E003-170_0001?offset=10",
"hreflang": "en-US"
}
],
"numberMatched": 39,
"numberReturned": 2,
"bbox": [
2.52,
50.64,
5.94,
51.51
]
}
Figure A.8
show_on_map(data)
Figure A.9
Make this Notebook Trusted to load map: File → Trust Notebook
A.2.2. D113 GET /items without DCS (XML)
Example: 1.2
> Access the OGC API-Records D113 /items without DCS (XML) is not
supported.
response = requests.get(endpoint_items + '?f=xml',
verify=bool(verify_ssl),
headers={})
# headers={'Accept': 'application/xml'})
response.text
# xmlstr = minidom.parseString(response.text).toprettyxml(indent=' ',newl='')
# md("```xml\n" + xmlstr + "\n```\n")
Figure A.10
'{"type": "FeatureCollection", "features": [{"id": "05f9e795-b1ab-4ff7-9d5b-96c8c6d19d99", "type": "Feature", "geometry": {"type": "Polygon", "coordinates": [[[2.53, 50.67], [2.53, 51.51], [5.92, 51.51], [5.92, 50.67], [2.53, 50.67]]]}, "properties": {"externalId": "05f9e795-b1ab-4ff7-9d5b-96c8c6d19d99", "datetime": "2022-04-12", "start_datetime": "2013-11-28", "end_datetime": "1900-01-01", "recordUpdated": "2022-07-21T22:40:13Z", "type": "series", "created": "2021-09-15", "updated": "2022-04-12", "title": "Interessante plaatsen (POI)", "description": "Datasetreeks van datasets met interessante plaatsen", "associations": [{"href": "https://geoservices.informatievlaanderen.be/overdrachtdiensten/POI/wfs?service=WFS&version=2.0.0&request=GetCapabilities", "name": null, "description": "WFS Interessante plaatsen", "type": "OGC:WFS-2.0.0-http-get-capabilities", "rel": "OGC:WFS-2.0.0-http-get-capabilities"}, {"href": "https://geoservices.informatievlaanderen.be/overdrachtdiensten/POI/wfs?request=GetFeature&version=2.0.0&typename=POI:POI&count=1", "name": "POI:POI", "description": "Points of Interest", "type": "OGC:WFS-2.0.0-http-get-feature", "rel": "OGC:WFS-2.0.0-http-get-feature"}], "extent": {"spatial": {"bbox": [[2.53, 50.67, 5.92, 51.51]], "crs": "http://www.opengis.net/def/crs/OGC/1.3/CRS84"}}}, "links": [{"rel": "via", "type": "application/xml", "title": "This document as XML", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/05f9e795-b1ab-4ff7-9d5b-96c8c6d19d99?f=xml", "hreflang": "en-US"}], "assets": {}}, {"id": "240cc7bc-21c0-442d-aa9a-03530e3bcd08", "type": "Feature", "geometry": {"type": "Polygon", "coordinates": [[[2.53, 50.67], [2.53, 51.51], [5.92, 51.51], [5.92, 50.67], [2.53, 50.67]]]}, "properties": {"externalId": "240cc7bc-21c0-442d-aa9a-03530e3bcd08", "datetime": "2022-04-12", "start_datetime": "2018-06-27", "end_datetime": "2018-07-19", "recordUpdated": "2022-07-21T22:40:13Z", "type": "dataset", "created": "2015-07-01", "updated": "2022-04-12", "title": "Orthobeeldvorming - OMZ", "description": "Dit product is de moza\\u00efek van de zomerluchtopnamen 2018 (17 juni tot en met 1 juli 2018) zoals bedoeld in het INSPIRE thema Orthobeeldvorming.\\n\\nDe orthofotomoza\\u00efek is beschikbaar onder de vorm van een echte kleurencomposiet (RGB), een kleur-infraroodcomposiet (CIR) en een panchromatisch beeld (PAN).", "keywords": ["ORTHOFOTO", "VLAAMSE GEWEST", "ORTHOFOTO\'S", "KLEURENORTHOFOTO\'S", "KLEURENORTHO\'S", "AGIV-PRODUCT", "ORTHO\'S", "DIGITALE ORTHOFOTO\'S", "ORTHOFOTOBEDEKKING", "LUCHTOPNAMEN", "ORTHOFOTOPRODUCTIE", "ORTHOFOTOPLANS", "ORTHO", "KLEURENORTHOFOTOMOZA\\u00cfEK", "ORTHOFOTOMOZA\\u00cfEK"], "associations": [{"href": "https://inspire.informatievlaanderen.be/raadpleegdiensten/oi/wms?REQUEST=GetCapabilities&SERVICE=WMS&VERSION=1.3.0", "name": "Orthobeeldvorming", "description": "INSPIRE-compatibele raadpleegdienst (Initial Operating Capability) met lagen uit INSPIRE Annex II Thema Orthobeeldvorming (geharmoniseerde data).", "type": "OGC:WMS-1.3.0-http-get-capabilities", "rel": "OGC:WMS-1.3.0-http-get-capabilities"}, {"href": "https://inspire.informatievlaanderen.be/raadpleegdiensten/oi/wms?SERVICE=WMS&REQUEST=GetMap&FORMAT=image/png&TRANSPARENT=TRUE&STYLES=default&VERSION=1.3.0&LAYERS=OI.OrthoimageCoverage.OMZ.RGB&WIDTH=1920&HEIGHT=816&CRS=EPSG:3857&BBOX=399007.9156516319,6577502.008692471,399581.1933637719,6577745.651720131", "name": "OI.OrthoimageCoverage.OMZ.RGB", "description": "Orthofotomoza\\u00efek, middenschalig, zomeropnamen, kleur, 2018, Vlaanderen", "type": "OGC:WMS-1.3.0-http-get-map", "rel": "OGC:WMS-1.3.0-http-get-map"}, {"href": "https://inspire.informatievlaanderen.be/raadpleegdiensten/oi/wms?SERVICE=WMS&REQUEST=GetMap&FORMAT=image/png&TRANSPARENT=TRUE&STYLES=default&VERSION=1.3.0&LAYERS=OI.OrthoimageCoverage.OMZ.PAN&WIDTH=1920&HEIGHT=816&CRS=EPSG:3857&BBOX=399007.9156516319,6577502.008692471,399581.1933637719,6577745.651720131", "name": "OI.OrthoimageCoverage.OMZ.PAN", "description": "Orthofotomoza\\u00efek, middenschalig, zomeropnamen, panchromatisch, 2018, Vlaanderen", "type": "OGC:WMS-1.3.0-http-get-map", "rel": "OGC:WMS-1.3.0-http-get-map"}, {"href": "https://inspire.informatievlaanderen.be/raadpleegdiensten/oi/wms?SERVICE=WMS&REQUEST=GetMap&FORMAT=image/png&TRANSPARENT=TRUE&STYLES=default&VERSION=1.3.0&LAYERS=OI.OrthoimageCoverage.OMZ.CIR&WIDTH=1920&HEIGHT=816&CRS=EPSG:3857&BBOX=399007.9156516319,6577502.008692471,399581.1933637719,6577745.651720131", "name": "OI.OrthoimageCoverage.OMZ.CIR", "description": "Orthofotomoza\\u00efek, middenschalig, zomeropnamen, kleur-infrarood, 2018, Vlaanderen", "type": "OGC:WMS-1.3.0-http-get-map", "rel": "OGC:WMS-1.3.0-http-get-map"}, {"href": "https://inspire.informatievlaanderen.be/overdrachtdiensten/oi-omz/wcs?service=WCS&version=2.0.1&request=GetCapabilities", "name": "Orthobeeldvorming - OMZ", "description": "INSPIRE-compatibele overdrachtdienst (Initial Operating Capability) met zomerluchtopnamen uit INSPIRE Annex II Thema Orthobeeldvorming (geharmoniseerde data).", "type": "OGC:WCS-2.0.1-http-get-capabilities", "rel": "OGC:WCS-2.0.1-http-get-capabilities"}, {"href": "https://inspire.informatievlaanderen.be/overdrachtdiensten/oi-omz/wcs?SERVICE=WCS&VERSION=2.0.1&request=GetCoverage&CRS=EPSG:4258&subset=y,http://www.opengis.net/def/crs/EPSG/0/4258(50.7461,50.9108)&subset=x,http://www.opengis.net/def/crs/EPSG/0/4258(4.2548,4.5418)&scalefactor=50&COVERAGEID=OI.OrthoimageCoverage.OMZ.RGB&FORMAT=image/tiff&RESPONSE_CRS=EPSG:31370", "name": "OI.OrthoimageCoverage.OMZ.RGB", "description": "Orthofotomoza\\u00efek, middenschalig, zomeropnamen, kleur, 2018, Vlaanderen", "type": "OGC:WCS-2.0.1-http-get-coverage", "rel": "OGC:WCS-2.0.1-http-get-coverage"}, {"href": "https://inspire.informatievlaanderen.be/overdrachtdiensten/oi-omz/wcs?SERVICE=WCS&VERSION=2.0.1&request=GetCoverage&CRS=EPSG:4258&subset=y,http://www.opengis.net/def/crs/EPSG/0/4258(50.7461,50.9108)&subset=x,http://www.opengis.net/def/crs/EPSG/0/4258(4.2548,4.5418)&scalefactor=50&COVERAGEID=OI.OrthoimageCoverage.OMZ.PAN&FORMAT=image/tiff&RESPONSE_CRS=EPSG:31370", "name": "OI.OrthoimageCoverage.OMZ.PAN", "description": "Orthofotomoza\\u00efek, middenschalig, zomeropnamen, panchromatisch, 2018, Vlaanderen", "type": "OGC:WCS-2.0.1-http-get-coverage", "rel": "OGC:WCS-2.0.1-http-get-coverage"}, {"href": "https://inspire.informatievlaanderen.be/overdrachtdiensten/oi-omz/wcs?SERVICE=WCS&VERSION=2.0.1&request=GetCoverage&CRS=EPSG:4258&subset=y,http://www.opengis.net/def/crs/EPSG/0/4258(50.7461,50.9108)&subset=x,http://www.opengis.net/def/crs/EPSG/0/4258(4.2548,4.5418)&scalefactor=50&COVERAGEID=OI.OrthoimageCoverage.OMZ.CIR&FORMAT=image/tiff&RESPONSE_CRS=EPSG:31370", "name": "OI.OrthoimageCoverage.OMZ.CIR", "description": "Orthofotomoza\\u00efek, middenschalig, zomeropnamen, kleur-infrarood, 2018, Vlaanderen", "type": "OGC:WCS-2.0.1-http-get-coverage", "rel": "OGC:WCS-2.0.1-http-get-coverage"}], "extent": {"spatial": {"bbox": [[2.53, 50.67, 5.92, 51.51]], "crs": "http://www.opengis.net/def/crs/OGC/1.3/CRS84"}}}, "links": [{"rel": "via", "type": "application/xml", "title": "This document as XML", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/240cc7bc-21c0-442d-aa9a-03530e3bcd08?f=xml", "hreflang": "en-US"}], "assets": {}}, {"id": "6cc019a5-0a3d-41c5-b4d9-86917fb0eefc", "type": "Feature", "geometry": {"type": "Polygon", "coordinates": [[[-180.0, -90.0], [-180.0, 90.0], [180.0, 90.0], [180.0, -90.0], [-180.0, -90.0]]]}, "properties": {"externalId": "6cc019a5-0a3d-41c5-b4d9-86917fb0eefc", "datetime": "2011-05-17", "start_datetime": null, "end_datetime": null, "recordUpdated": "2022-07-21T22:40:13Z", "type": "dataset", "updated": "2011-05-17", "title": "pycsw record", "description": "Sample metadata record", "extent": {"spatial": {"bbox": [[-180.0, -90.0, 180.0, 90.0]], "crs": "http://www.opengis.net/def/crs/OGC/1.3/CRS84"}}}, "links": [{"rel": "via", "type": "application/xml", "title": "This document as XML", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/6cc019a5-0a3d-41c5-b4d9-86917fb0eefc?f=xml", "hreflang": "en-US"}], "assets": {}}, {"id": "70c663ac-ff3e-4b9a-9867-bb22bbdfcf6d", "type": "Feature", "geometry": {"type": "Polygon", "coordinates": [[[2.53, 50.67], [2.53, 51.51], [5.92, 51.51], [5.92, 50.67], [2.53, 50.67]]]}, "properties": {"externalId": "70c663ac-ff3e-4b9a-9867-bb22bbdfcf6d", "datetime": "2022-04-12", "start_datetime": "2009-05-29", "end_datetime": "1900-01-01", "recordUpdated": "2022-07-21T22:40:13Z", "type": "series", "created": "2016-08-03", "updated": "2022-04-12", "title": "Groenkaart Vlaanderen", "description": "Bundeling van de datasets die een overzicht geven van het groen in Vlaanderen voor bepaalde jaren.", "keywords": ["stedelijk groen", " landbouwgebruiksperceel", " boswijzer", " landbouw"], "associations": [{"href": "http://www.geopunt.be/download?container=groenkaart&title=Groenkaart%20Vlaanderen", "name": "Groenkaart Vlaanderen", "description": null, "type": "WWW:DOWNLOAD-1.0-http--download", "rel": "WWW:DOWNLOAD-1.0-http--download"}], "extent": {"spatial": {"bbox": [[2.53, 50.67, 5.92, 51.51]], "crs": "http://www.opengis.net/def/crs/OGC/1.3/CRS84"}}}, "links": [{"rel": "via", "type": "application/xml", "title": "This document as XML", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/70c663ac-ff3e-4b9a-9867-bb22bbdfcf6d?f=xml", "hreflang": "en-US"}], "assets": {}}, {"id": "PR1_OPER_CHR_MO1_1P_20030920T110000_N51-028_E002-088_0001", "type": "Feature", "geometry": {"type": "Polygon", "coordinates": [[[2.78, 51.22], [2.78, 51.32], [2.99, 51.32], [2.99, 51.22], [2.78, 51.22]]]}, "properties": {"externalId": "PR1_OPER_CHR_MO1_1P_20030920T110000_N51-028_E002-088_0001", "datetime": "2022-06-30T14:10:28", "start_datetime": "2003-09-20T11:00:00Z", "end_datetime": "2003-09-20T11:04:00Z", "recordUpdated": "2022-07-21T22:40:13Z", "type": "dataset", "created": "2019-05-22", "updated": "2022-06-30T14:10:28", "title": "Proba CHRIS Level 1A", "description": "CHRIS acquires a set of up to five images of each target during each acquisition sequence, these images are acquired when Proba-1 is pointing at distinct angles with respect to the target. CHRIS Level 1A products (supplied in HDF data files, version 4.1r3) include five formal CHRIS imaging modes, classified as modes 1 to 5: \\u2022 MODE 1: Full swath width, 62 spectral bands, 773nm / 1036nm, nadir ground sampling distance 34m @ 556km \\u2022 MODE 2 WATER BANDS: Full swath width, 18 spectral bands, nadir ground sampling distance 17m @ 556km \\u2022 MODE 3 LAND CHANNELS: Full swath width, 18 spectral bands, nadir ground sampling distance 17m @ 556km \\u2022 MODE 4 CHLOROPHYL BAND SET: Full swath width, 18 spectral bands, nadir ground sampling distance 17m @ 556km \\u2022 MODE 5 LAND CHANNELS: Half swath width, 37 spectral bands, nadir ground sampling distance 17m @ 556km All Proba-1 passes are systematically acquired according to the current acquisition plan, CHRIS data are processed every day to Level 1A and made available to ESA users. Observation over a new specific area can be performed by submitting the request to add a new site to the acquisition plan.", "associations": [{"href": "https://tpm-ds.eo.esa.int/oads/data/PROBA1-CHRIS/PR1_OPER_CHR_MO1_1P_20030920T110000_N51-028_E002-088_0001.SIP.ZIP", "name": "Download", "description": null, "type": "WWW:DOWNLOAD", "rel": "WWW:DOWNLOAD"}, {"href": "http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/browse/PR1_OPER_CHR_MO1_1P_20030920T110000_N51-028_E002-088_0001.SIP.ZIP_BID.PNG", "name": "QUICKLOOK", "description": null, "type": null, "rel": null}, {"href": "http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/thumbnail/PR1_OPER_CHR_MO1_1P_20030920T110000_N51-028_E002-088_0001.SIP.ZIP_TIMG.jpg", "name": "THUMBNAIL", "description": null, "type": null, "rel": null}], "extent": {"spatial": {"bbox": [[2.78, 51.22, 2.99, 51.32]], "crs": "http://www.opengis.net/def/crs/OGC/1.3/CRS84"}}}, "links": [{"rel": "via", "type": "application/xml", "title": "This document as XML", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20030920T110000_N51-028_E002-088_0001?f=xml", "hreflang": "en-US"}], "assets": {}}, {"id": "PR1_OPER_CHR_MO1_1P_20190401T134300_N51-240_E002-920_0001", "type": "Feature", "geometry": {"type": "Polygon", "coordinates": [[[2.83, 51.18], [2.83, 51.28], [3.03, 51.28], [3.03, 51.18], [2.83, 51.18]]]}, "properties": {"externalId": "PR1_OPER_CHR_MO1_1P_20190401T134300_N51-240_E002-920_0001", "datetime": "2022-06-30T14:10:17", "start_datetime": "2019-04-01T13:43:00Z", "end_datetime": "2019-04-01T13:47:00Z", "recordUpdated": "2022-07-21T22:40:13Z", "type": "dataset", "created": "2019-05-22", "updated": "2022-06-30T14:10:17", "title": "Proba CHRIS Level 1A", "description": "CHRIS acquires a set of up to five images of each target during each acquisition sequence, these images are acquired when Proba-1 is pointing at distinct angles with respect to the target. CHRIS Level 1A products (supplied in HDF data files, version 4.1r3) include five formal CHRIS imaging modes, classified as modes 1 to 5: \\u2022 MODE 1: Full swath width, 62 spectral bands, 773nm / 1036nm, nadir ground sampling distance 34m @ 556km \\u2022 MODE 2 WATER BANDS: Full swath width, 18 spectral bands, nadir ground sampling distance 17m @ 556km \\u2022 MODE 3 LAND CHANNELS: Full swath width, 18 spectral bands, nadir ground sampling distance 17m @ 556km \\u2022 MODE 4 CHLOROPHYL BAND SET: Full swath width, 18 spectral bands, nadir ground sampling distance 17m @ 556km \\u2022 MODE 5 LAND CHANNELS: Half swath width, 37 spectral bands, nadir ground sampling distance 17m @ 556km All Proba-1 passes are systematically acquired according to the current acquisition plan, CHRIS data are processed every day to Level 1A and made available to ESA users. Observation over a new specific area can be performed by submitting the request to add a new site to the acquisition plan.", "associations": [{"href": "https://tpm-ds.eo.esa.int/oads/data/PROBA1-CHRIS/PR1_OPER_CHR_MO1_1P_20190401T134300_N51-240_E002-920_0001.SIP.ZIP", "name": "Download", "description": null, "type": "WWW:DOWNLOAD", "rel": "WWW:DOWNLOAD"}, {"href": "http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/browse/PR1_OPER_CHR_MO1_1P_20190401T134300_N51-240_E002-920_0001.SIP.ZIP_BID.PNG", "name": "QUICKLOOK", "description": null, "type": null, "rel": null}, {"href": "http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/thumbnail/PR1_OPER_CHR_MO1_1P_20190401T134300_N51-240_E002-920_0001.SIP.ZIP_TIMG.jpg", "name": "THUMBNAIL", "description": null, "type": null, "rel": null}], "extent": {"spatial": {"bbox": [[2.83, 51.18, 3.03, 51.28]], "crs": "http://www.opengis.net/def/crs/OGC/1.3/CRS84"}}}, "links": [{"rel": "via", "type": "application/xml", "title": "This document as XML", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20190401T134300_N51-240_E002-920_0001?f=xml", "hreflang": "en-US"}], "assets": {}}, {"id": "PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001", "type": "Feature", "geometry": {"type": "Polygon", "coordinates": [[[2.83, 51.18], [2.83, 51.28], [3.02, 51.28], [3.02, 51.18], [2.83, 51.18]]]}, "properties": {"externalId": "PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001", "datetime": "2022-06-30T14:16:24", "start_datetime": "2022-03-07T14:02:00Z", "end_datetime": "2022-03-07T14:06:00Z", "recordUpdated": "2022-07-21T22:40:13Z", "type": "dataset", "created": "2019-05-22", "updated": "2022-06-30T14:16:24", "title": "Proba CHRIS Level 1A", "description": "CHRIS acquires a set of up to five images of each target during\\n each acquisition sequence, these images are acquired when Proba-1 is pointing at\\n distinct angles with respect to the target. CHRIS Level 1A products (supplied in\\n HDF data files, version 4.1r3) include five formal CHRIS imaging modes,\\n classified as modes 1 to 5: \\u2022 MODE 1: Full swath width, 62 spectral bands, 773nm\\n / 1036nm, nadir ground sampling distance 34m @ 556km \\u2022 MODE 2 WATER BANDS: Full\\n swath width, 18 spectral bands, nadir ground sampling distance 17m @ 556km \\u2022\\n MODE 3 LAND CHANNELS: Full swath width, 18 spectral bands, nadir ground sampling\\n distance 17m @ 556km \\u2022 MODE 4 CHLOROPHYL BAND SET: Full swath width, 18 spectral\\n bands, nadir ground sampling distance 17m @ 556km \\u2022 MODE 5 LAND CHANNELS: Half\\n swath width, 37 spectral bands, nadir ground sampling distance 17m @ 556km All\\n Proba-1 passes are systematically acquired according to the current acquisition\\n plan, CHRIS data are processed every day to Level 1A and made available to ESA\\n users. Observation over a new specific area can be performed by submitting the\\n request to add a new site to the acquisition plan.", "associations": [{"href": "https://tpm-ds.eo.esa.int/oads/data/PROBA1-CHRIS/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP", "name": "Download", "description": null, "type": "WWW:DOWNLOAD", "rel": "WWW:DOWNLOAD"}, {"href": "http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/browse/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP_BID.PNG", "name": "QUICKLOOK", "description": null, "type": null, "rel": null}, {"href": "http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/thumbnail/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP_TIMG.jpg", "name": "THUMBNAIL", "description": null, "type": null, "rel": null}], "extent": {"spatial": {"bbox": [[2.83, 51.18, 3.02, 51.28]], "crs": "http://www.opengis.net/def/crs/OGC/1.3/CRS84"}}}, "links": [{"rel": "via", "type": "application/xml", "title": "This document as XML", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=xml", "hreflang": "en-US"}], "assets": {}}, {"id": "e17fe655-987c-4c5f-bbae-b10dcd4fccc3", "type": "Feature", "geometry": {"type": "Polygon", "coordinates": [[[2.53, 50.67], [2.53, 51.51], [5.92, 51.51], [5.92, 50.67], [2.53, 50.67]]]}, "properties": {"externalId": "e17fe655-987c-4c5f-bbae-b10dcd4fccc3", "datetime": "2022-04-12", "start_datetime": "1997-01-01", "end_datetime": "2020-07-01", "recordUpdated": "2022-07-21T22:40:13Z", "type": "dataset", "updated": "2022-04-12", "title": "Biologische Waarderingskaart en Natura 2000 Habitatkaart - Toestand 2020", "description": "De Biologische Waarderingskaart (BWK) is een uniforme inventarisatie en evaluatie van het gehele Vlaamse grondgebied aan de hand van een set karteringseenheden die staan voor vegetaties, bodembedekking en kleine landschapselementen (lijn- en puntvormige elementen). Ook met de aanwezigheid van belangrijke fauna-elementen is er rekening gehouden. De vernieuwde BWK, versie 2, probeert, in vergelijking met de versie 1, aan meer vereisten en noden te voldoen, zowel inhoudelijk als op het gebied van nauwkeurigheid.\\nIn deze versie van de BWK zijn ook de Natura 2000 habitattypen opgenomen. In Vlaanderen komen actueel 47 Natura 2000 habitattypen van de Bijlage I van de Habitatrichtlijn voor. Daarnaast zijn er in Vlaanderen ook 15 regionaal belangrijke biotopen gedefinieerd. Dit zijn biotopen die naar biologische waarden en belang voor de biodiversiteit vergelijkbaar zijn met habitattypen, maar die op Europees niveau minder bedreigd zijn.\\nDeze kaart geeft de best beschikbare informatie anno 2020 over de verspreiding van de Natura 2000 habitattypen, de regionaal belangrijke biotopen en de karteringseenheden van de Biologische Waarderingskaart. Dit kan een vereenvoudiging zijn van de werkelijkheid op terrein. Ten allen tijde geldt de re\\u00eble situatie op terrein voor toepassing t.b.v. het beleidsmatig en wettelijk kader.", "keywords": ["biodiversiteit", "biologische waardering", "biologische waarderingskaart", "biotoop", "biotoopinformatie", "biotoopzeldzaamheid", "diversiteit", "ecotopen", "fauna", "faunistisch belangrijk gebied", "habitat", "habitattype", "landschapselement", "natuurbehoud", "natuurbeleid", "natuurwaarde", "zeldzame diersoorten", "bodembedekking", "bwk", "ecotoop", "flora", "kwetsbaarheid", "landschapselementen", "Natura 2000 habitat", "plantensoorten", "vegetatietypen", "zeldzame soorten", "plantengemeenschap", "habitat 3260", "karteringseenheid"], "associations": [{"href": "http://www.geopunt.be/catalogus/applicationfolder/biologische-waarderingskaart", "name": "Geopunt-applicatie Biologische waarderingskaart", "description": null, "type": "WWW:LINK-1.0-http--related", "rel": "WWW:LINK-1.0-http--related"}, {"href": "https://geoservices.informatievlaanderen.be/raadpleegdiensten/inbo/wms?request=GetCapabilities&version=1.3.0&service=wms", "name": "BWK2Zone", "description": "BWK 2 - Zone", "type": "OGC:WMS-1.3.0-http-get-capabilities", "rel": "OGC:WMS-1.3.0-http-get-capabilities"}, {"href": "https://geoservices.informatievlaanderen.be/raadpleegdiensten/inbo/wms?request=GetMap&version=1.3.0&service=wms&FORMAT=image/png&TRANSPARENT=TRUE&STYLES=default&LAYERS=BWK2Zone&WIDTH=2048&HEIGHT=721&CRS=EPSG:3857&BBOX=274321.207589895,6600657.3523665415,641218.9433588814,6710879.547153807", "name": "BWK2Zone", "description": "BWK 2 - Zone", "type": "OGC:WMS-1.3.0-http-get-map", "rel": "OGC:WMS-1.3.0-http-get-map"}, {"href": "https://geoservices.informatievlaanderen.be/raadpleegdiensten/inbo/wms?request=GetCapabilities&version=1.3.0&service=wms", "name": "BWK2Fauna", "description": "BWK 2 - Faunistisch belangrijk gebied", "type": "OGC:WMS-1.3.0-http-get-capabilities", "rel": "OGC:WMS-1.3.0-http-get-capabilities"}, {"href": "https://geoservices.informatievlaanderen.be/raadpleegdiensten/inbo/wms?request=GetMap&version=1.3.0&service=wms&FORMAT=image/png&TRANSPARENT=TRUE&STYLES=default&LAYERS=BWK2Fauna&WIDTH=2048&HEIGHT=721&CRS=EPSG:3857&BBOX=274321.207589895,6600657.3523665415,641218.9433588814,6710879.547153807", "name": "BWK2Fauna", "description": "BWK 2 - Faunistisch belangrijk gebied", "type": "OGC:WMS-1.3.0-http-get-map", "rel": "OGC:WMS-1.3.0-http-get-map"}, {"href": "https://geoservices.informatievlaanderen.be/raadpleegdiensten/inbo/wms?request=GetCapabilities&version=1.3.0&service=wms", "name": "BWK2Hab", "description": "BWK 2 - Natura 2000 Habitat", "type": "OGC:WMS-1.3.0-http-get-capabilities", "rel": "OGC:WMS-1.3.0-http-get-capabilities"}, {"href": "https://geoservices.informatievlaanderen.be/raadpleegdiensten/inbo/wms?request=GetMap&version=1.3.0&service=wms&FORMAT=image/png&TRANSPARENT=TRUE&STYLES=default&LAYERS=BWK2Hab&WIDTH=2048&HEIGHT=721&CRS=EPSG:3857&BBOX=274321.207589895,6600657.3523665415,641218.9433588814,6710879.547153807", "name": "BWK2Hab", "description": "BWK 2 - Natura 2000 Habitat", "type": "OGC:WMS-1.3.0-http-get-map", "rel": "OGC:WMS-1.3.0-http-get-map"}, {"href": "https://geoservices.informatievlaanderen.be/raadpleegdiensten/inbo/wms?request=GetCapabilities&version=1.3.0&service=wms", "name": "BWK2Hab3260", "description": "BWK 2 - Habitattype 3260", "type": "OGC:WMS-1.3.0-http-get-capabilities", "rel": "OGC:WMS-1.3.0-http-get-capabilities"}, {"href": "https://geoservices.informatievlaanderen.be/raadpleegdiensten/inbo/wms?request=GetMap&version=1.3.0&service=wms&FORMAT=image/png&TRANSPARENT=TRUE&STYLES=default&LAYERS=BWK2Hab3260&WIDTH=2048&HEIGHT=721&CRS=EPSG:3857&BBOX=274321.207589895,6600657.3523665415,641218.9433588814,6710879.547153807", "name": "BWK2Hab3260", "description": "BWK 2 - Habitattype 3260", "type": "OGC:WMS-1.3.0-http-get-map", "rel": "OGC:WMS-1.3.0-http-get-map"}, {"href": "https://geoservices.informatievlaanderen.be/raadpleegdiensten/inbo/wms?request=GetCapabilities&version=1.3.0&service=wms", "name": "BWK2ZoneLabel", "description": "Kaartlabel BWK-karteringseenheden", "type": "OGC:WMS-1.3.0-http-get-capabilities", "rel": "OGC:WMS-1.3.0-http-get-capabilities"}, {"href": "https://geoservices.informatievlaanderen.be/raadpleegdiensten/inbo/wms?request=GetMap&version=1.3.0&service=wms&FORMAT=image/png&TRANSPARENT=TRUE&STYLES=default&LAYERS=BWK2ZoneLabel&WIDTH=2048&HEIGHT=721&CRS=EPSG:3857&BBOX=274321.207589895,6600657.3523665415,641218.9433588814,6710879.547153807", "name": "BWK2ZoneLabel", "description": "Kaartlabel BWK-karteringseenheden", "type": "OGC:WMS-1.3.0-http-get-map", "rel": "OGC:WMS-1.3.0-http-get-map"}, {"href": "https://geoservices.informatievlaanderen.be/raadpleegdiensten/inbo/wms?request=GetCapabilities&version=1.3.0&service=wms", "name": "BWK2HabLabel", "description": "Kaartlabel Habitattype", "type": "OGC:WMS-1.3.0-http-get-capabilities", "rel": "OGC:WMS-1.3.0-http-get-capabilities"}, {"href": "https://geoservices.informatievlaanderen.be/raadpleegdiensten/inbo/wms?request=GetMap&version=1.3.0&service=wms&FORMAT=image/png&TRANSPARENT=TRUE&STYLES=default&LAYERS=BWK2HabLabel&WIDTH=2048&HEIGHT=721&CRS=EPSG:3857&BBOX=274321.207589895,6600657.3523665415,641218.9433588814,6710879.547153807", "name": "BWK2HabLabel", "description": "Kaartlabel Habitattype", "type": "OGC:WMS-1.3.0-http-get-map", "rel": "OGC:WMS-1.3.0-http-get-map"}, {"href": "https://geoservices.informatievlaanderen.be/overdrachtdiensten/BWK/wfs?service=WFS&version=1.1.0&request=GetCapabilities&typename=BWK:Bwkhab", "name": "BWK:Bwkhab", "description": "BWK 2 - BWK-zone en Natura 2000 Habitat", "type": "OGC:WFS-1.1.0-http-get-capabilities", "rel": "OGC:WFS-1.1.0-http-get-capabilities"}, {"href": "https://geoservices.informatievlaanderen.be/overdrachtdiensten/BWK/wfs?service=WFS&version=1.1.0&request=GetFeature&typeName=BWK:Bwkhab&outputFormat=application/json&maxFeatures=1&srsName=epsg:3857", "name": "BWK:Bwkhab", "description": "BWK 2 - BWK-zone en Natura 2000 Habitat", "type": "OGC:WFS-1.1.0-http-get-feature", "rel": "OGC:WFS-1.1.0-http-get-feature"}, {"href": "https://geoservices.informatievlaanderen.be/overdrachtdiensten/BWK/wfs?service=WFS&version=1.1.0&request=GetCapabilities&typename=BWK:Bwkfauna", "name": "BWK:Bwkfauna", "description": "BWK 2 - Faunistisch belangrijke gebieden", "type": "OGC:WFS-1.1.0-http-get-capabilities", "rel": "OGC:WFS-1.1.0-http-get-capabilities"}, {"href": "https://geoservices.informatievlaanderen.be/overdrachtdiensten/BWK/wfs?service=WFS&version=1.1.0&request=GetFeature&typeName=BWK:Bwkfauna&outputFormat=application/json&maxFeatures=1&srsName=epsg:3857", "name": "BWK:Bwkfauna", "description": "BWK 2 - Faunistisch belangrijke gebieden", "type": "OGC:WFS-1.1.0-http-get-feature", "rel": "OGC:WFS-1.1.0-http-get-feature"}, {"href": "https://geoservices.informatievlaanderen.be/overdrachtdiensten/BWK/wfs?service=WFS&version=1.1.0&request=GetCapabilities&typename=BWK:Hab3260", "name": "BWK:Hab3260", "description": "BWK 2 - Habitattype 3260", "type": "OGC:WFS-1.1.0-http-get-capabilities", "rel": "OGC:WFS-1.1.0-http-get-capabilities"}, {"href": "https://geoservices.informatievlaanderen.be/overdrachtdiensten/BWK/wfs?service=WFS&version=1.1.0&request=GetFeature&typeName=BWK:Hab3260&outputFormat=application/json&maxFeatures=1&srsName=epsg:3857", "name": "BWK:Hab3260", "description": "BWK 2 - Habitattype 3260", "type": "OGC:WFS-1.1.0-http-get-feature", "rel": "OGC:WFS-1.1.0-http-get-feature"}, {"href": "http://www.geopunt.be/download?container=bwk2\\\\2020&title=Biologische%20waarderingskaart%20-%20Natura%202000%20Habitatkaart", "name": "Biologische waarderingskaart en Natura 2000 Habitatkaart, uitgave 2020", "description": null, "type": "WWW:DOWNLOAD-1.0-http--download", "rel": "WWW:DOWNLOAD-1.0-http--download"}], "extent": {"spatial": {"bbox": [[2.53, 50.67, 5.92, 51.51]], "crs": "http://www.opengis.net/def/crs/OGC/1.3/CRS84"}}}, "links": [{"rel": "via", "type": "application/xml", "title": "This document as XML", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/e17fe655-987c-4c5f-bbae-b10dcd4fccc3?f=xml", "hreflang": "en-US"}], "assets": {}}, {"id": "9d075d6f-a85a-18fa-1f51-ced8-ef7c-5bce-a91eee54", "type": "Feature", "geometry": {"type": "Polygon", "coordinates": [[[2.52, 50.64], [2.52, 51.51], [5.94, 51.51], [5.94, 50.64], [2.52, 50.64]]]}, "properties": {"externalId": "9d075d6f-a85a-18fa-1f51-ced8-ef7c-5bce-a91eee54", "datetime": "2022-07-01", "start_datetime": null, "end_datetime": null, "recordUpdated": "2022-07-21T22:40:13Z", "type": "service", "created": "2013-05-27", "updated": "2022-07-01", "title": "WMS Vlaamse Landmaatschappij", "description": "Web Map Service met data van de Vlaamse Landmaatschappij.", "keywords": ["OGC:WMS", "bodemeenheid", "bodemkaart", "gegeneraliseerde bodemkaart voor Vlaanderen", "infiltratiekenmerk", "kwel", "kwetsbaarheid", "landinrichting", "landschapseenheid", "plattelandsbeleid", "reli\\u00ebf", "ruimtelijke structuren in Vlaanderen", "inrichtingsproject", "landinrichtingsplan", "landinrichtingsproject", "onderzoek", "planprogramma", "vastgesteld", "afbakening", "planbegeleidingsgroep", "inrichtingsnota", "recht van voorkoop", "rvv", "voorkoopgebied", "voorkooprecht", "blokgrens", "kavelplan", "landeigendom", "ruilverkaveling", "ruilverkavelingsproject", "sectie", "gebruiksruil", "infrastructuurwerken", "natuurbehoud", "natuurinrichting", "natuurinrichtingsproject", "gebied met recht van voorkoop", "focusgebied", "grondwater", "mestdecreet", "mestactieplan", "nitraat", "nitraatconcentratie", "nitraatresidu", "nitraatresidudrempelwaarde", "nitraatresidustaal", "oppervlaktewater", "overschrijding", "waterkwaliteit", "beheerovereenkomst", "agromilieu-klimaatmaatregel", "ecosysteemdienst", "plattelandsontwikkeling", "landbouwbeleid", "PDPO", "GLB", "agrobiodiveristeit", "gebiedstype"], "associations": [{"href": "https://geoservices.informatievlaanderen.be/raadpleegdiensten/VLM/wms?service=WMS&request=getcapabilities", "name": "Capabilities van de webdienst WMS Vlaamse Landmaatschappij", "description": null, "type": "OGC:WMS", "rel": "OGC:WMS"}, {"href": "https://geoservices.informatievlaanderen.be/raadpleegdiensten/VLM/wms", "name": null, "description": null, "type": null, "rel": null}, {"href": "https://geoservices.informatievlaanderen.be/raadpleegdiensten/VLM/wms", "name": null, "description": null, "type": null, "rel": null}, {"href": "https://geoservices.informatievlaanderen.be/raadpleegdiensten/VLM/wms", "name": null, "description": null, "type": null, "rel": null}], "extent": {"spatial": {"bbox": [[2.52, 50.64, 5.94, 51.51]], "crs": "http://www.opengis.net/def/crs/OGC/1.3/CRS84"}}}, "links": [{"rel": "via", "type": "application/xml", "title": "This document as XML", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/9d075d6f-a85a-18fa-1f51-ced8-ef7c-5bce-a91eee54?f=xml", "hreflang": "en-US"}], "assets": {}}, {"id": "PR1_OPER_CHR_MO1_1P_20181005T134600_N51-350_E003-170_0001", "type": "Feature", "geometry": {"type": "Polygon", "coordinates": [[[3.07, 51.29], [3.07, 51.39], [3.28, 51.39], [3.28, 51.29], [3.07, 51.29]]]}, "properties": {"externalId": "PR1_OPER_CHR_MO1_1P_20181005T134600_N51-350_E003-170_0001", "datetime": "2022-06-30T14:09:50", "start_datetime": "2018-10-05T13:46:00Z", "end_datetime": "2018-10-05T13:50:00Z", "recordUpdated": "2022-07-21T22:40:13Z", "type": "dataset", "created": "2019-05-22", "updated": "2022-06-30T14:09:50", "title": "Proba CHRIS Level 1A", "description": "CHRIS acquires a set of up to five images of each target during each acquisition sequence, these images are acquired when Proba-1 is pointing at distinct angles with respect to the target. CHRIS Level 1A products (supplied in HDF data files, version 4.1r3) include five formal CHRIS imaging modes, classified as modes 1 to 5: \\u2022 MODE 1: Full swath width, 62 spectral bands, 773nm / 1036nm, nadir ground sampling distance 34m @ 556km \\u2022 MODE 2 WATER BANDS: Full swath width, 18 spectral bands, nadir ground sampling distance 17m @ 556km \\u2022 MODE 3 LAND CHANNELS: Full swath width, 18 spectral bands, nadir ground sampling distance 17m @ 556km \\u2022 MODE 4 CHLOROPHYL BAND SET: Full swath width, 18 spectral bands, nadir ground sampling distance 17m @ 556km \\u2022 MODE 5 LAND CHANNELS: Half swath width, 37 spectral bands, nadir ground sampling distance 17m @ 556km All Proba-1 passes are systematically acquired according to the current acquisition plan, CHRIS data are processed every day to Level 1A and made available to ESA users. Observation over a new specific area can be performed by submitting the request to add a new site to the acquisition plan.", "associations": [{"href": "https://tpm-ds.eo.esa.int/oads/data/PROBA1-CHRIS/PR1_OPER_CHR_MO1_1P_20181005T134600_N51-350_E003-170_0001.SIP.ZIP", "name": "Download", "description": null, "type": "WWW:DOWNLOAD", "rel": "WWW:DOWNLOAD"}, {"href": "http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/browse/PR1_OPER_CHR_MO1_1P_20181005T134600_N51-350_E003-170_0001.SIP.ZIP_BID.PNG", "name": "QUICKLOOK", "description": null, "type": null, "rel": null}, {"href": "http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/thumbnail/PR1_OPER_CHR_MO1_1P_20181005T134600_N51-350_E003-170_0001.SIP.ZIP_TIMG.jpg", "name": "THUMBNAIL", "description": null, "type": null, "rel": null}], "extent": {"spatial": {"bbox": [[3.07, 51.29, 3.28, 51.39]], "crs": "http://www.opengis.net/def/crs/OGC/1.3/CRS84"}}}, "links": [{"rel": "via", "type": "application/xml", "title": "This document as XML", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20181005T134600_N51-350_E003-170_0001?f=xml", "hreflang": "en-US"}], "assets": {}}], "links": [{"rel": "alternate", "type": "application/dcs+geo", "title": "This document as DCS + GeoJSON", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items?f=dcs+geo", "hreflang": "en-US"}, {"rel": "alternate", "type": "application/jose", "title": "This document as JOSE + GeoJSON", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items?f=jose", "hreflang": "en-US"}, {"rel": "alternate", "type": "application/jose;profile=jws", "title": "This document as JWS", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items?f=jws", "hreflang": "en-US"}, {"rel": "alternate", "type": "application/geo+json", "title": "This document as GeoJSON", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20181005T134600_N51-350_E003-170_0001?f=json", "hreflang": "en-US"}, {"rel": "alternate", "type": "text/html", "title": "This document as HTML", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20181005T134600_N51-350_E003-170_0001?f=html", "hreflang": "en-US"}, {"rel": "collection", "type": "application/json", "title": "Collection URL", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main", "hreflang": "en-US"}], "numberMatched": 39, "numberReturned": 10, "bbox": [-180.0, -90.0, 180.0, 90.0]}'
Figure A.11
A.2.3. D113 GET /items/{itemId} without DCS (GeoJSON)
Example: 1.3
> Access the OGC API-Records D113 /items/{itemId} without DCS (GeoJSON)
response = requests.get(endpoint_item ,
verify=bool(verify_ssl),
headers={'Accept': 'application/geo+json'})
data = json.loads(response.text)
jstr = json.dumps(data, indent=3)
md("```json\n" + jstr + "\n```\n")
Figure A.12
{
"id": "PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001",
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
2.83,
51.18
],
[
2.83,
51.28
],
[
3.02,
51.28
],
[
3.02,
51.18
],
[
2.83,
51.18
]
]
]
},
"properties": {
"externalId": "PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001",
"datetime": "2022-06-30T14:16:24",
"start_datetime": "2022-03-07T14:02:00Z",
"end_datetime": "2022-03-07T14:06:00Z",
"recordUpdated": "2022-07-21T22:40:13Z",
"type": "dataset",
"created": "2019-05-22",
"updated": "2022-06-30T14:16:24",
"title": "Proba CHRIS Level 1A",
"description": "CHRIS acquires a set of up to five images of each target during\n each acquisition sequence, these images are acquired when Proba-1 is pointing at\n distinct angles with respect to the target. CHRIS Level 1A products (supplied in\n HDF data files, version 4.1r3) include five formal CHRIS imaging modes,\n classified as modes 1 to 5: \u2022 MODE 1: Full swath width, 62 spectral bands, 773nm\n / 1036nm, nadir ground sampling distance 34m @ 556km \u2022 MODE 2 WATER BANDS: Full\n swath width, 18 spectral bands, nadir ground sampling distance 17m @ 556km \u2022\n MODE 3 LAND CHANNELS: Full swath width, 18 spectral bands, nadir ground sampling\n distance 17m @ 556km \u2022 MODE 4 CHLOROPHYL BAND SET: Full swath width, 18 spectral\n bands, nadir ground sampling distance 17m @ 556km \u2022 MODE 5 LAND CHANNELS: Half\n swath width, 37 spectral bands, nadir ground sampling distance 17m @ 556km All\n Proba-1 passes are systematically acquired according to the current acquisition\n plan, CHRIS data are processed every day to Level 1A and made available to ESA\n users. Observation over a new specific area can be performed by submitting the\n request to add a new site to the acquisition plan.",
"associations": [
{
"href": "https://tpm-ds.eo.esa.int/oads/data/PROBA1-CHRIS/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP",
"name": "Download",
"description": null,
"type": "WWW:DOWNLOAD",
"rel": "WWW:DOWNLOAD"
},
{
"href": "http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/browse/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP_BID.PNG",
"name": "QUICKLOOK",
"description": null,
"type": null,
"rel": null
},
{
"href": "http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/thumbnail/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP_TIMG.jpg",
"name": "THUMBNAIL",
"description": null,
"type": null,
"rel": null
}
],
"extent": {
"spatial": {
"bbox": [
[
2.83,
51.18,
3.02,
51.28
]
],
"crs": "http://www.opengis.net/def/crs/OGC/1.3/CRS84"
}
}
},
"links": [
{
"rel": "alternate",
"type": "application/dcs+geo",
"title": "This document as DCS + GeoJSON",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=dcs+geo",
"hreflang": "en-US"
},
{
"rel": "alternate",
"type": "application/jose",
"title": "This document as JOSE + GeoJSON",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=jose",
"hreflang": "en-US"
},
{
"rel": "alternate",
"type": "application/jose;profile=jws",
"title": "This document as JWS",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=jws",
"hreflang": "en-US"
},
{
"rel": "self",
"type": "application/geo+json",
"title": "This document as GeoJSON",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=json",
"hreflang": "en-US"
},
{
"rel": "alternate",
"type": "text/html",
"title": "This document as HTML",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=html",
"hreflang": "en-US"
},
{
"rel": "collection",
"type": "application/json",
"title": "Collection URL",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main",
"hreflang": "en-US"
},
{
"rel": "via",
"type": "application/xml",
"title": "This document as XML",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=xml",
"hreflang": "en-US"
}
],
"assets": {}
}
Figure A.13
The ISO metadata record is available via the via link at JSONPath $.links[?(@.rel==`via’)].
from jsonpath_ng.ext import parse
expression = parse("$.links[?(@.rel == 'via')].href")
r = expression.find(data)
r[0].value
Figure A.14
'https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=xml'
Figure A.15
show_on_map(data)
Figure A.16
Make this Notebook Trusted to load map: File → Trust Notebook
A.2.4. D113 GET /queryables without DCS (JSON)
Example: 1.4
> Access the OGC API-Records D113
/collections/{collection-id}/queryables without DCS to retrieve the
available search parameters.
response = requests.get(endpoint_queryables ,
verify=bool(verify_ssl),
headers={'Accept': 'application/json'})
data = json.loads(response.text)
jstr = json.dumps(data, indent=3)
md("```json\n" + jstr + "\n```\n")
Figure A.17
{
"id": "metadata:main",
"type": "object",
"title": "OGC Testbed 18 Geospatial Catalogue",
"properties": {
"geometry": {
"$ref": "https://geojson.org/schema/Polygon.json"
},
"type": {
"title": "type",
"type": "string"
},
"title": {
"title": "title",
"type": "string"
},
"keywords": {
"title": "keywords",
"type": "string"
},
"parentidentifier": {
"title": "parentidentifier",
"type": "string"
},
"time_begin": {
"title": "time_begin",
"type": "string"
},
"time_end": {
"title": "time_end",
"type": "string"
},
"date": {
"title": "date",
"type": "string"
},
"platform": {
"title": "platform",
"type": "string"
},
"instrument": {
"title": "instrument",
"type": "string"
},
"sensortype": {
"title": "sensortype",
"type": "string"
}
},
"$schema": "http://json-schema.org/draft/2019-09/schema",
"$id": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/queryables"
}
Figure A.18
A.2.5. D113 GET /items/{itemId} without DCS (XML)
Example: 1.5
> Access the OGC API-Records D113 /items/{itemId} without DCS (XML) to
retrieve an ISO19139 metadata record.
response = requests.get(endpoint_item + '?f=xml',
verify=bool(verify_ssl),
headers={})
# headers={'Accept': 'application/xml'})
xmlstr = minidom.parseString(response.text).toprettyxml(indent=' ',newl='')
md("```xml\n" + xmlstr + "\n```\n")
Figure A.19
<?xml version="1.0" ?><gmd:MD_Metadata xmlns:gmd="http://www.isotc211.org/2005/gmd" xmlns:gco="http://www.isotc211.org/2005/gco" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:gmx="http://www.isotc211.org/2005/gmx" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.isotc211.org/2005/gmd ./apiso-inspire.xsd">
<gmd:fileIdentifier>
<gco:CharacterString>PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001</gco:CharacterString>
</gmd:fileIdentifier>
<gmd:language>
<gmd:LanguageCode codeList="http://id.loc.gov/vocabulary/iso639-2" codeListValue="eng">eng</gmd:LanguageCode>
</gmd:language>
<gmd:parentIdentifier>
<gmx:Anchor xlink:href="https://eovoc.spacebel.be/collections/series/items/PROBA.CHRIS.1A">PROBA.CHRIS.1A</gmx:Anchor>
</gmd:parentIdentifier>
<gmd:hierarchyLevel>
<gmd:MD_ScopeCode codeList="http://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_19139_Schemas/resources/codelist/ML_gmxCodelists.xml#MD_ScopeCode" codeListValue="dataset"/>
</gmd:hierarchyLevel>
<gmd:contact xmlns:gmd="http://www.isotc211.org/2005/gmd">
<gmd:CI_ResponsibleParty>
<gmd:organisationName>
<gco:CharacterString>ESA/ESRIN</gco:CharacterString>
</gmd:organisationName>
<gmd:positionName>
<gco:CharacterString>ESRIN Earth Observation Help Desk</gco:CharacterString>
</gmd:positionName>
<gmd:contactInfo>
<gmd:CI_Contact>
<gmd:phone>
<gmd:CI_Telephone>
<gmd:voice>
<gco:CharacterString>+3906941801</gco:CharacterString>
</gmd:voice>
<gmd:facsimile>
<gco:CharacterString>+390694180280</gco:CharacterString>
</gmd:facsimile>
</gmd:CI_Telephone>
</gmd:phone>
<gmd:address>
<gmd:CI_Address>
<gmd:deliveryPoint>
<gco:CharacterString>Largo Galileo Galilei 1</gco:CharacterString>
</gmd:deliveryPoint>
<gmd:city>
<gco:CharacterString>Frascati (Roma)</gco:CharacterString>
</gmd:city>
<gmd:postalCode>
<gco:CharacterString>00044</gco:CharacterString>
</gmd:postalCode>
<gmd:country>
<gco:CharacterString>Italy</gco:CharacterString>
</gmd:country>
<gmd:electronicMailAddress>
<gco:CharacterString>eohelp@esa.int</gco:CharacterString>
</gmd:electronicMailAddress>
</gmd:CI_Address>
</gmd:address>
<gmd:onlineResource>
<gmd:CI_OnlineResource>
<gmd:linkage>
<gmd:URL>http://www.esa.int</gmd:URL>
</gmd:linkage>
</gmd:CI_OnlineResource>
</gmd:onlineResource>
</gmd:CI_Contact>
</gmd:contactInfo>
<role xmlns="http://www.isotc211.org/2005/gmd">
<gmd:CI_RoleCode codeList="http://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_19139_Schemas/resources/codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="pointOfContact">pointOfContact</gmd:CI_RoleCode>
</role>
</gmd:CI_ResponsibleParty>
</gmd:contact>
<gmd:dateStamp>
<gco:DateTime>2022-06-30T14:16:24</gco:DateTime>
</gmd:dateStamp>
<gmd:metadataStandardName>
<gco:CharacterString>ISO19115</gco:CharacterString>
</gmd:metadataStandardName>
<gmd:metadataStandardVersion>
<gco:CharacterString>2005/Cor.1:2006</gco:CharacterString>
</gmd:metadataStandardVersion>
<gmd:referenceSystemInfo>
<gmd:MD_ReferenceSystem>
<gmd:referenceSystemIdentifier>
<gmd:RS_Identifier>
<gmd:code>
<gmx:Anchor xlink:href="http://www.opengis.net/def/crs/EPSG/0/4326">EPSG:4326</gmx:Anchor>
</gmd:code>
</gmd:RS_Identifier>
</gmd:referenceSystemIdentifier>
</gmd:MD_ReferenceSystem>
</gmd:referenceSystemInfo>
<gmd:identificationInfo>
<gmd:MD_DataIdentification>
<gmd:citation>
<gmd:CI_Citation>
<gmd:title>
<gco:CharacterString>Proba CHRIS Level 1A</gco:CharacterString>
</gmd:title>
<gmd:date>
<gmd:CI_Date>
<!-- Metadata Identification Creation Date (MI_CD)-->
<gmd:date>
<gco:Date>2019-05-22</gco:Date>
</gmd:date>
<gmd:dateType>
<gmd:CI_DateTypeCode codeList="http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#CI_DateTypeCode" codeListValue="creation"/>
</gmd:dateType>
</gmd:CI_Date>
</gmd:date>
<gmd:identifier>
<gmd:MD_Identifier>
<gmd:code>
<gmx:Anchor xlink:href="https://eovoc.spacebel.be/collections/datasets/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001"/>
</gmd:code>
</gmd:MD_Identifier>
</gmd:identifier>
</gmd:CI_Citation>
</gmd:citation>
<gmd:abstract>
<gco:CharacterString>CHRIS acquires a set of up to five images of each target during
each acquisition sequence, these images are acquired when Proba-1 is pointing at
distinct angles with respect to the target. CHRIS Level 1A products (supplied in
HDF data files, version 4.1r3) include five formal CHRIS imaging modes,
classified as modes 1 to 5: • MODE 1: Full swath width, 62 spectral bands, 773nm
/ 1036nm, nadir ground sampling distance 34m @ 556km • MODE 2 WATER BANDS: Full
swath width, 18 spectral bands, nadir ground sampling distance 17m @ 556km •
MODE 3 LAND CHANNELS: Full swath width, 18 spectral bands, nadir ground sampling
distance 17m @ 556km • MODE 4 CHLOROPHYL BAND SET: Full swath width, 18 spectral
bands, nadir ground sampling distance 17m @ 556km • MODE 5 LAND CHANNELS: Half
swath width, 37 spectral bands, nadir ground sampling distance 17m @ 556km All
Proba-1 passes are systematically acquired according to the current acquisition
plan, CHRIS data are processed every day to Level 1A and made available to ESA
users. Observation over a new specific area can be performed by submitting the
request to add a new site to the acquisition plan.</gco:CharacterString>
</gmd:abstract>
<gmd:pointOfContact>
<gmd:CI_ResponsibleParty>
<gmd:organisationName>
<gco:CharacterString>ESA/ESRIN</gco:CharacterString>
</gmd:organisationName>
<gmd:positionName>
<gco:CharacterString>Earth Observation helpdesk</gco:CharacterString>
</gmd:positionName>
<gmd:contactInfo>
<gmd:CI_Contact>
<gmd:phone>
<gmd:CI_Telephone>
<gmd:voice>
<gco:CharacterString>+3906941801</gco:CharacterString>
</gmd:voice>
<gmd:facsimile>
<gco:CharacterString>+390694180280</gco:CharacterString>
</gmd:facsimile>
</gmd:CI_Telephone>
</gmd:phone>
<gmd:address>
<gmd:CI_Address>
<gmd:deliveryPoint>
<gco:CharacterString>Largo Galileo Galilei
1</gco:CharacterString>
</gmd:deliveryPoint>
<gmd:city>
<gco:CharacterString>Frascati (Roma)</gco:CharacterString>
</gmd:city>
<gmd:postalCode>
<gco:CharacterString>00044</gco:CharacterString>
</gmd:postalCode>
<gmd:country>
<gco:CharacterString>Italy</gco:CharacterString>
</gmd:country>
<gmd:electronicMailAddress>
<gco:CharacterString>eohelp@esa.int</gco:CharacterString>
</gmd:electronicMailAddress>
</gmd:CI_Address>
</gmd:address>
<gmd:onlineResource>
<gmd:CI_OnlineResource>
<gmd:linkage>
<gmd:URL>http://www.esa.int</gmd:URL>
</gmd:linkage>
</gmd:CI_OnlineResource>
</gmd:onlineResource>
</gmd:CI_Contact>
</gmd:contactInfo>
<gmd:role>
<gmd:CI_RoleCode codeList="http://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_19139_Schemas/resources/codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="originator">originator</gmd:CI_RoleCode>
</gmd:role>
</gmd:CI_ResponsibleParty>
</gmd:pointOfContact>
<gmd:graphicOverview>
<gmd:MD_BrowseGraphic>
<gmd:fileName>
<gco:CharacterString>http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/browse/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP_BID.PNG</gco:CharacterString>
</gmd:fileName>
</gmd:MD_BrowseGraphic>
</gmd:graphicOverview>
<gmd:descriptiveKeywords>
<gmd:MD_Keywords>
<gmd:keyword>
<gmx:Anchor xlink:href="http://inspire.ec.europa.eu/theme/lc">Land
cover</gmx:Anchor>
</gmd:keyword>
<gmd:thesaurusName>
<gmd:CI_Citation>
<gmd:title>
<gmx:Anchor xlink:href="http://www.eionet.europa.eu/gemet/inspire_themes">GEMET - INSPIRE themes, version 1.0</gmx:Anchor>
</gmd:title>
<gmd:date>
<gmd:CI_Date>
<gmd:date>
<gco:Date>2008-06-01</gco:Date>
</gmd:date>
<gmd:dateType>
<gmd:CI_DateTypeCode codeList="http://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_19139_Schemas/resources/codelist/ML_gmxCodelists.xml#CI_DateTypeCode" codeListValue="publication">publication</gmd:CI_DateTypeCode>
</gmd:dateType>
</gmd:CI_Date>
</gmd:date>
</gmd:CI_Citation>
</gmd:thesaurusName>
</gmd:MD_Keywords>
</gmd:descriptiveKeywords>
<gmd:descriptiveKeywords>
<gmd:MD_Keywords>
<gmd:keyword>
<gmx:Anchor xlink:href="https://gcmd.earthdata.nasa.gov/kms/concept/46e4aaa4-349c-4049-a910-035391360010">EARTH SCIENCE > BIOSPHERE > ECOSYSTEMS > TERRESTRIAL
ECOSYSTEMS</gmx:Anchor>
</gmd:keyword>
<gmd:keyword>
<gmx:Anchor xlink:href="https://gcmd.earthdata.nasa.gov/kms/concept/c7b5c02c-724d-4a19-b824-98180f3900c9">EARTH SCIENCE > BIOSPHERE > VEGETATION</gmx:Anchor>
</gmd:keyword>
<gmd:keyword>
<gmx:Anchor xlink:href="https://gcmd.earthdata.nasa.gov/kms/concept/5debb283-51e4-435e-b2a2-e8e2a977220d">EARTH SCIENCE > TERRESTRIAL HYDROSPHERE > SURFACE
WATER</gmx:Anchor>
</gmd:keyword>
<gmd:keyword>
<gmx:Anchor xlink:href="https://gcmd.earthdata.nasa.gov/kms/concept/91697b7d-8f2b-4954-850e-61d5f61c867d">EARTH SCIENCE > OCEANS</gmx:Anchor>
</gmd:keyword>
<gmd:type>
<gmd:MD_KeywordTypeCode codeList="theme" codeListValue="http://www.isotc211.org/2005/resources/codeList.xml#MD_KeywordTypeCode"/>
</gmd:type>
<gmd:thesaurusName>
<gmd:CI_Citation>
<gmd:title>
<gmx:Anchor xlink:href="https://gcmd.earthdata.nasa.gov/kms/concepts/concept_scheme/sciencekeywords">NASA/Global Change Master Directory (GCMD) Earth Science
Keywords. Version 8.6</gmx:Anchor>
</gmd:title>
<gmd:date>
<gmd:CI_Date>
<gmd:date>
<gco:Date>2018</gco:Date>
</gmd:date>
<gmd:dateType>
<gmd:CI_DateTypeCode codeList="http://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_19139_Schemas/resources/codelist/ML_gmxCodelists.xml#CI_DateTypeCode" codeListValue="publication">publication</gmd:CI_DateTypeCode>
</gmd:dateType>
</gmd:CI_Date>
</gmd:date>
<gmd:identifier>
<gmd:MD_Identifier>
<gmd:code>
<gco:CharacterString>http://idn.ceos.org/</gco:CharacterString>
</gmd:code>
</gmd:MD_Identifier>
</gmd:identifier>
</gmd:CI_Citation>
</gmd:thesaurusName>
</gmd:MD_Keywords>
</gmd:descriptiveKeywords>
<gmd:descriptiveKeywords>
<gmd:MD_Keywords>
<!-- (K_ET_U) (K_ET) -->
<gmd:keyword>
<gmx:Anchor xlink:href="https://earth.esa.int/concept/forestry">Forestry</gmx:Anchor>
</gmd:keyword>
<gmd:keyword>
<gmx:Anchor xlink:href="https://earth.esa.int/concept/vegetation">Vegetation</gmx:Anchor>
</gmd:keyword>
<gmd:keyword>
<gmx:Anchor xlink:href="https://earth.esa.int/concept/surface-water">Surface
Water</gmx:Anchor>
</gmd:keyword>
<gmd:keyword>
<gmx:Anchor xlink:href="https://earth.esa.int/concept/oceans">Oceans</gmx:Anchor>
</gmd:keyword>
<gmd:thesaurusName>
<gmd:CI_Citation>
<gmd:title>
<gmx:Anchor xlink:href="https://earth.esa.int/concepts/concept_scheme/earth-topics">EO Parameter Code List - Earth Topics</gmx:Anchor>
</gmd:title>
<gmd:date>
<gmd:CI_Date>
<gmd:date>
<gco:Date>2018</gco:Date>
</gmd:date>
<gmd:dateType>
<gmd:CI_DateTypeCode codeList="http://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_19139_Schemas/resources/codelist/ML_gmxCodelists.xml#CI_DateTypeCode" codeListValue="publication">publication</gmd:CI_DateTypeCode>
</gmd:dateType>
</gmd:CI_Date>
</gmd:date>
</gmd:CI_Citation>
</gmd:thesaurusName>
</gmd:MD_Keywords>
</gmd:descriptiveKeywords>
<gmd:descriptiveKeywords>
<gmd:MD_Keywords>
<!-- (I_E_T_U) (I_E_T) -->
<gmd:keyword>
<gmx:Anchor xlink:href="https://earth.esa.int/concept/p-imaging-spectrometers-radiometers">Imaging Spectrometers/Radiometers</gmx:Anchor>
</gmd:keyword>
<gmd:type>
<gmd:MD_KeywordTypeCode codeList="http://www.isotc211.org/2005/resources/codeList.xml#MD_KeywordTypeCode" codeListValue="theme"/>
</gmd:type>
<gmd:thesaurusName>
<gmd:CI_Citation>
<gmd:title>
<gmx:Anchor xlink:href="https://earth.esa.int/concepts/concept_scheme/instruments">EO Parameter Code List - Instruments</gmx:Anchor>
</gmd:title>
<gmd:date>
<gmd:CI_Date>
<gmd:date>
<gco:Date>2018</gco:Date>
</gmd:date>
<gmd:dateType>
<gmd:CI_DateTypeCode codeList="http://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_19139_Schemas/resources/codelist/ML_gmxCodelists.xml#CI_DateTypeCode" codeListValue="publication">publication</gmd:CI_DateTypeCode>
</gmd:dateType>
</gmd:CI_Date>
</gmd:date>
</gmd:CI_Citation>
</gmd:thesaurusName>
</gmd:MD_Keywords>
</gmd:descriptiveKeywords>
<gmd:resourceConstraints>
<gmd:MD_LegalConstraints>
<gmd:accessConstraints>
<gmd:MD_RestrictionCode codeList="http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#MD_RestrictionCode" codeListValue="otherRestrictions"/>
</gmd:accessConstraints>
<gmd:otherConstraints>
<gmx:Anchor xlink:href="http://inspire.ec.europa.eu/metadata-codelist/LimitationsOnPublicAccess/noLimitations"/>
</gmd:otherConstraints>
</gmd:MD_LegalConstraints>
</gmd:resourceConstraints>
<gmd:resourceConstraints>
<gmd:MD_LegalConstraints>
<gmd:accessConstraints>
<gmd:MD_RestrictionCode codeList="http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#MD_RestrictionCode" codeListValue="otherRestrictions"/>
</gmd:accessConstraints>
<gmd:otherConstraints>
<gmx:Anchor xlink:href="http://inspire.ec.europa.eu/metadata-codelist/ConditionsApplyingToAccessAndUse/conditionsUnknown"/>
</gmd:otherConstraints>
<gmd:otherConstraints>
<gmx:Anchor xlink:href="https://earth.esa.int/eogateway/documents/20142/1560778/ESA-Third-Party-Missions-Terms-and-Conditions.pdf">Utilisation of this data is subject to ESA's Earth Observation Terms
and Conditions </gmx:Anchor>
</gmd:otherConstraints>
</gmd:MD_LegalConstraints>
</gmd:resourceConstraints>
<gmd:spatialRepresentationType>
<gmd:MD_SpatialRepresentationTypeCode codeList="http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#MD_SpatialRepresentationTypeCode" codeListValue="grid"/>
</gmd:spatialRepresentationType>
<gmd:language>
<gmd:LanguageCode codeList="http://id.loc.gov/vocabulary/iso639-2" codeListValue="eng">eng</gmd:LanguageCode>
</gmd:language>
<gmd:topicCategory>
<gmd:MD_TopicCategoryCode>imageryBaseMapsEarthCover</gmd:MD_TopicCategoryCode>
</gmd:topicCategory>
<gmd:extent>
<gmd:EX_Extent>
<gmd:temporalElement>
<gmd:EX_TemporalExtent>
<gmd:extent>
<gml:TimePeriod gml:id="timeperiod1">
<gml:beginPosition>2022-03-07T14:02:00Z</gml:beginPosition>
<gml:endPosition>2022-03-07T14:06:00Z</gml:endPosition>
</gml:TimePeriod>
</gmd:extent>
</gmd:EX_TemporalExtent>
</gmd:temporalElement>
</gmd:EX_Extent>
</gmd:extent>
<gmd:extent>
<gmd:EX_Extent>
<gmd:geographicElement>
<gmd:EX_GeographicBoundingBox>
<gmd:westBoundLongitude>
<gco:Decimal>2.83</gco:Decimal>
</gmd:westBoundLongitude>
<gmd:eastBoundLongitude>
<gco:Decimal>3.02</gco:Decimal>
</gmd:eastBoundLongitude>
<gmd:southBoundLatitude>
<gco:Decimal>51.18</gco:Decimal>
</gmd:southBoundLatitude>
<gmd:northBoundLatitude>
<gco:Decimal>51.28</gco:Decimal>
</gmd:northBoundLatitude>
</gmd:EX_GeographicBoundingBox>
</gmd:geographicElement>
</gmd:EX_Extent>
</gmd:extent>
</gmd:MD_DataIdentification>
</gmd:identificationInfo>
<gmd:distributionInfo>
<gmd:MD_Distribution>
<gmd:distributionFormat>
<gmd:MD_Format>
<gmd:name>
<gmx:Anchor xlink:href="http://inspire.ec.europa.eu/media-types/application/x-binary">application/x-binary</gmx:Anchor>
</gmd:name>
<gmd:version gco:nilReason="unknown"/>
</gmd:MD_Format>
</gmd:distributionFormat>
<gmd:transferOptions>
<gmd:MD_DigitalTransferOptions>
<gmd:onLine>
<gmd:CI_OnlineResource>
<gmd:linkage>
<gmd:URL>https://tpm-ds.eo.esa.int/oads/data/PROBA1-CHRIS/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP</gmd:URL>
</gmd:linkage>
<gmd:protocol>
<gmx:Anchor xlink:href="https://www.iana.org/assignments/media-types/application/x-binary">application/x-binary</gmx:Anchor>
</gmd:protocol>
<gmd:applicationProfile>
<gco:CharacterString>application/x-binary</gco:CharacterString>
</gmd:applicationProfile>
<gmd:name>
<gco:CharacterString>Download</gco:CharacterString>
</gmd:name>
<gmd:description>
<gmx:Anchor xlink:href="http://inspire.ec.europa.eu/metadata-codelist/OnLineDescriptionCode/endPoint">endPoint</gmx:Anchor>
</gmd:description>
<gmd:function>
<gmd:CI_OnLineFunctionCode codeList="http://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_19139_Schemas/resources/codelist/ML_gmxCodelists.xml#CI_OnLineFunctionCode" codeListValue="information"/>
</gmd:function>
</gmd:CI_OnlineResource>
</gmd:onLine>
<gmd:onLine>
<gmd:CI_OnlineResource>
<gmd:linkage>
<gmd:URL>http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/browse/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP_BID.PNG</gmd:URL>
</gmd:linkage>
<gmd:protocol>
<gmx:Anchor xlink:href="https://www.iana.org/assignments/media-types/image/png">png</gmx:Anchor>
</gmd:protocol>
<gmd:applicationProfile>
<gco:CharacterString>image/png</gco:CharacterString>
</gmd:applicationProfile>
<gmd:name>
<gco:CharacterString>QUICKLOOK</gco:CharacterString>
</gmd:name>
<gmd:description>
<gmx:Anchor xlink:href="http://inspire.ec.europa.eu/metadata-codelist/OnLineDescriptionCode/endPoint">endPoint</gmx:Anchor>
</gmd:description>
<gmd:function>
<gmd:CI_OnLineFunctionCode codeList="http://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_19139_Schemas/resources/codelist/ML_gmxCodelists.xml#CI_OnLineFunctionCode" codeListValue="information"/>
</gmd:function>
</gmd:CI_OnlineResource>
</gmd:onLine>
<gmd:onLine>
<gmd:CI_OnlineResource>
<gmd:linkage>
<gmd:URL>http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/thumbnail/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP_TIMG.jpg</gmd:URL>
</gmd:linkage>
<gmd:protocol>
<gmx:Anchor xlink:href="https://www.iana.org/assignments/media-types/image/jpeg">jpeg</gmx:Anchor>
</gmd:protocol>
<gmd:applicationProfile>
<gco:CharacterString>image/jpeg</gco:CharacterString>
</gmd:applicationProfile>
<gmd:name>
<gco:CharacterString>THUMBNAIL</gco:CharacterString>
</gmd:name>
<gmd:description>
<gmx:Anchor xlink:href="http://inspire.ec.europa.eu/metadata-codelist/OnLineDescriptionCode/endPoint">endPoint</gmx:Anchor>
</gmd:description>
<gmd:function>
<gmd:CI_OnLineFunctionCode codeList="http://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_19139_Schemas/resources/codelist/ML_gmxCodelists.xml#CI_OnLineFunctionCode" codeListValue="information"/>
</gmd:function>
</gmd:CI_OnlineResource>
</gmd:onLine>
</gmd:MD_DigitalTransferOptions>
</gmd:transferOptions>
</gmd:MD_Distribution>
</gmd:distributionInfo>
<gmd:dataQualityInfo>
<gmd:DQ_DataQuality>
<gmd:scope>
<gmd:DQ_Scope>
<gmd:level>
<gmd:MD_ScopeCode codeList="http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#MD_ScopeCode" codeListValue="dataset"/>
</gmd:level>
<gmd:levelDescription>
<gmd:MD_ScopeDescription>
<gmd:other>
<gco:CharacterString>Dataset</gco:CharacterString>
</gmd:other>
</gmd:MD_ScopeDescription>
</gmd:levelDescription>
</gmd:DQ_Scope>
</gmd:scope>
<gmd:report>
<gmd:DQ_DomainConsistency>
<gmd:result>
<gmd:DQ_ConformanceResult>
<gmd:specification>
<gmd:CI_Citation>
<gmd:title>
<gmx:Anchor xlink:href="http://data.europa.eu/eli/reg/2010/1089">COMMISSION REGULATION (EU) No 1089/2010 of 23 November
2010 implementing Directive 2007/2/EC of the European
Parliament and of the Council as regards
interoperability of spatial data sets and
services</gmx:Anchor>
</gmd:title>
<gmd:date>
<gmd:CI_Date>
<gmd:date>
<gco:Date>2010-12-08</gco:Date>
</gmd:date>
<gmd:dateType>
<gmd:CI_DateTypeCode codeList="http://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_19139_Schemas/resources/codelist/ML_gmxCodelists.xml#CI_DateTypeCode" codeListValue="publication">publication</gmd:CI_DateTypeCode>
</gmd:dateType>
</gmd:CI_Date>
</gmd:date>
</gmd:CI_Citation>
</gmd:specification>
<gmd:explanation>
<gco:CharacterString>This data set is conformant with the INSPIRE
Implementing Rules for the interoperability of spatial data sets
and services</gco:CharacterString>
</gmd:explanation>
<gmd:pass>
<gco:Boolean>false</gco:Boolean>
</gmd:pass>
</gmd:DQ_ConformanceResult>
</gmd:result>
</gmd:DQ_DomainConsistency>
</gmd:report>
<gmd:lineage>
<gmd:LI_Lineage>
<gmd:statement>
<gco:CharacterString>source data: PROBA platform</gco:CharacterString>
</gmd:statement>
</gmd:LI_Lineage>
</gmd:lineage>
</gmd:DQ_DataQuality>
</gmd:dataQualityInfo>
</gmd:MD_Metadata>
Figure A.20
A.3. D113 GET /items with DCS (KMS)
Example: 2.1
> Access the OGC API-Records D113 /items with DCS (application/dcs+geo)
# Get the access token from https://ogc.demo.secure-dimensions.de/token-app/
# access_token = '4572e42da2c093012606449ba29da41fad2d599b'
# response = requests.get(endpoint_items + '?key_challenge=123&limit=1&access_token='+access_token,
response = requests.get(endpoint_items + '?key_challenge=123&limit=1&type=series',
verify=bool(verify_ssl),
headers={'Accept': 'application/dcs+geo', 'Authorization': 'Bearer ' + access_token})
response
Figure A.21
<Response [200]>
Figure A.22
A.3.1. JWT
Catalogue response corresponds to a JWT. The complete response is a JWE. The syntax is defined at https://openid.net/specs/draft-jones-json-web-encryption-02.html Contains 3 parts separated by dots…
token = response.text
token
Figure A.23
'{"type": "dcs+geo", "timestamp": "2022-10-21T17:25:39+02:00", "objects": [{"metadata": {"confidentiality_information": {"policy_identifier": "TB18", "classification": "unclassified"}, "creation_data_time": "2022-10-21T17:25:39+02:00", "number_matched": 4, "number_returned": 1, "bbox": [], "links": [{"rel": "self", "type": "application/dcs+geo", "title": "This document as DCS + GeoJSON", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items?key_challenge=123&limit=1&type=series&f=dcs+geo", "hreflang": "en-US"}, {"rel": "alternate", "type": "application/jose", "title": "This document as JOSE + GeoJSON", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items?key_challenge=123&limit=1&type=series&f=jose", "hreflang": "en-US"}, {"rel": "alternate", "type": "application/jose;profile=jws", "title": "This document as JWS", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items?key_challenge=123&limit=1&type=series&f=jws", "hreflang": "en-US"}, {"rel": "alternate", "type": "application/geo+json", "title": "This document as GeoJSON", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/05f9e795-b1ab-4ff7-9d5b-96c8c6d19d99?f=json", "hreflang": "en-US"}, {"rel": "alternate", "type": "text/html", "title": "This document as HTML", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/05f9e795-b1ab-4ff7-9d5b-96c8c6d19d99?f=html", "hreflang": "en-US"}, {"rel": "collection", "type": "application/json", "title": "Collection URL", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main", "hreflang": "en-US"}, {"rel": "next", "type": "application/dcs+geo", "title": "items (next)", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items?key_challenge=123&limit=1&type=series&f=dcs+geo&offset=1", "hreflang": "en-US"}]}, "data": "eyJhbGciOiJkaXIiLCJjcml0IjpbImt1cmwiXSwiY3R5IjoiYXBwbGljYXRpb24vZ2VvK2pzb24iLCJlbmMiOiJBMjU2R0NNIiwia2lkIjoiMWI1MDZlMmYtZjU3Ni00YTlhLTk1NzAtNWY0MDY5OTFjZGIyIiwia3VybCI6Imh0dHBzOi8vb2djLmRlbW8uc2VjdXJlLWRpbWVuc2lvbnMuZGUva21zL2Rlay8xYjUwNmUyZi1mNTc2LTRhOWEtOTU3MC01ZjQwNjk5MWNkYjIifQ..YK40tObj6xY4jnkT.ai5wxo9uiLPZ0STOnnqmPMuBtZMu0qxbA3JYWzl_8cUPYogcWLrLLXhPP1FnqKnfews_EjJHt0XJuKoyhsXa3oQiGHadt3I6gGIlKDNNzSaB5bwTU31em8MSVmzm2m-O6ahKozMrjSoIwKvFh8X4Rgh7Tk-3GlglrBXJzw5qiznQDXGwz3ukGmHB0AVB78z12jJFmLcw7PsMOI5T3cTg5sGbTcySFgDxaFaV8pHRx-qbWVeKNb9aFcnIOLT1QWsA41p34nc7h8JwWy9779CU2PiBr9bmqE8aobDp_6JX8zRIeJgmcK0szi0LtK1TYAHzMYus5In2Z1ywsJeDACitr-TDQ1Pj8BjKzVVFVmOhdl9KnWhvLq8LvuLdijuR9T61anauWE4cLYgl6AYa4QDV2FVcgwn5G35yfrgSyvJi7_fZVeQhMesj2GbeslfvOciE9qfikoMjJ68g0NC8TbL8M7u_XIx6TQuJX1aXAXI1JgQrSlEX9KH9uBdeTqbzM9gmCDL9qy3WZgBPRzorSEi-H1hIObByfbysCG3JBh8nE4bnfuDBGcVlH-uCENOcZ98L1puXtBp57sscXFMb9mw2BrE-kJRBgzx-k_pO0jkVIo-4TIiz0Jo_SGTjDBHPMgyQswjy6C-l_RYBZFmF7MUBGuvT3kZYQyV2RVZBayMT2WFEFagrH6pTjGsqoDQC__oODkXJyufZBIpaBLiPj3SbhTmh_r0c0Q2-JS9XOBvt94pSe5j2PO1sBteoZ2dFjeM9URmwoScgTme478VqZErCHbN03KgguOWPp6InwnQUcI1yNTdCWju6EB4RaSwKzmN3caFNmwiEIiN4kutZy9Rr4TTSvels6u6waYQZYXAVh_yATOSfgXw3aWuITJGpq9xozNBuHLlZ6iJhGGGSeyRJe20swM_W-6OrPHML2Qu__tda_j2wt2_PO_stH0BW9K5s_wFDUfERbzw1-wKnbwYo-NIsm1fFUeHmNJrjiebPWUQfb5u3kMlV7U7_Qe6XUst7ZhEwDN_NYp4nZo5pCjuM1Cnp3eEoKwunRWsERI82oLTSFsYZi13xy-980NMpqCJNuvaSVHtCdBu2up7Z3tiNHZ-RrXlTa0QyfxEVABeX4L42zF0c57RLk0sb1jqKE30qsCjAz7LTW8ebSVp6Ef033pPC_Dk02zgLe9AK0xbDNPWTFHRaud3MC1zZsFHEcjfryKdBxdK51rU5q6s6EZcpL-_mkXrKkodTnagiEVYN9Nt-GMggR2xDvskjB5iqi28FTyLbHg0xc-tH2RGn7QeMYr4LK-KzPv2Ctsu3-x0mCwmHRaORqAecGt-t8PIXSy8emsveQqqFcD4_euh5M6cHLydipldKdTqroKqo6M-tiYsbWtcosc6_izapy7LGI8qP5E38P4jmA8ksjWiWFDSCIGbLTDamy3iN5owwkGGkQCg2lxgldrz1OVc9K2gecV1rNPtL_aTJ1Y_7OZpxiq9KNXpvwiUGdIhQbCkQW8csOkx9wKP4P0Kg9zdKcVUCCT9rc0yQxno82tm7U3H09HQHZx1SUB9xAly8umv0_RMDWLGAnhGI1xlNKT8rUhuhpsxBWQTgkFUyN_IRhKpvu3Q3pGXQzBvRnyYFk-VRS84aJjqjhEN3qChxYvF1voE5v0sS8b9zk2Vs0iwTa33D61zGk1ZZtygYN6hkfQCRCAzDdAqp6YPs1nXJ9iP4LEeXB9G9jqMg4vTf-ipwTnaYeW0FqS_MRLgj1ZOr3dBKEsb2cq7dPXv8JndfXL8WDKK1tdoHMhECdo_j_Lw7AXGjIg8Cs6zKG4GT1WO9wgbUQDKWhyUXRHMyowMJshm9_l-uVLCddupGilmUVSPCgV1iR2y0-eNtMgqtUG8eWhoLkbNc5Icbdbcc72JwF8TatKPJv0Z_YjAVo5s1pDGDwnaIDK9LgJ1t5nCOCsQR5FC2859QAwzg8HOkIByJvlJRKRJNxqmP-coBLuUw3wbnBm2rddUWEj7YhML9kqe0g0UhmOfdW93p1K8o8ojYBWcrNUXTbXThG1cfEhNb2BvCgve3EF-bub5P-TfL-iwQKn9vxrUWGyroTZZRXIhhm8PhzThg43nCLFik6dGOG27OoqsIm5d_sGs_sl7WgAc6aiENrtIoCFqPFJdvbyTAjIs5OZLWkZSEilRv3wnKSvrCnB6yz4OIqoO56jbDZumhV9gIrjztKc_c-4dH8ZB1AqEt1w7BIdh-mOG1yWNEn1ZsreLijlepeaDiBsRMtZO2xR7nJ0DOYUN_XGd5TtdgxTpgpgn_WR8uUmW8U_WBythu9oOHTXxDHwutv1nAu55AlT4Mrj2tYIWRBoFiCV6GgN65Od3tCTg7pKr-6FJI8Z-YHL-Q9Zzd0CDFnjhl-bGHOez7B8sXwD8u0PIqjnKjFl6qAfTWBcE2XJ0MiR7GC2xbSqDXXrQeFrz4G08MTS4_Vmv5c8h5pukaHSYvVU7wZmC9yBj_rBKxlQyVOnKkUPIbvwz3gQFA9mafrc6MvqRp5sys6eshcWTiFpA0fTAtnqtILdKP68a13kaXNPEZlPJcefFrW5djliMHoMMBYzqGqisv0EXUnmB5SVnMzbW5L_lG9Fr9Hu_0uUv589TgwCY89q1dpjDnZ0yzi0hUsOIf7dZ5xG-wktQwtBDqggvFKFxog717GjOaWOSz8B6IwQ333xaKBYzXLF3zW6xo_4u0edXBM5xhRuQkhZ-GMbTwFKzv0DSYwlEOkT-FOgTNpQE9CXH4ZzZwoXNLkehQmOsWmeJELKIymW3GFt7iczfysNa4jn20_3nIHGoyPG3pCtf0OAeMmGeIK9jPM0BcC90LIVxWfVwZ8RtrmB-pCLuCH40ikIRJR4zG5G0cs5KZg-k5xtcVdTTVDt4PVSu8OvU8ggV04-JNQwx73wY_bVUkMGLMpOhrrMXT-Wnv3Ck7uVwnTjmSflQtAU8F5YEUYC8tuTcgo5phTZsDIRacoI7dngCVxXtNGSyFWS0u-yWnmq9eHzHcmiL16B3tY2oLPVzCmvrlLPHjD2rCPCcXY1OUngV0vPvRugSaA8-FdVUbUNSybceqFzT9qoZFXTaJWrPgk84ydDpefbEWIf9SzfET1nzrtMd5QB8tVMKeS3y9IoUJXyGii3-PVMklJ05hRUCx90q-Lyt2_Bl0FKAqISzyCRZE4VmHpaPVt09JApBCwZ2UH6L0zrju-7hDhsoOIh50-zECrs6w6c1Bp9aMJsFHwW9onBNFK3L3TgLUqWy-_DEILvKJiBy3vonHVoso8gp81mCpsH6EY_YFAvrFmHyK6rQYNKIACGH37dbhiSkPiozibtay3NpMCRFikBskHPwCnamZ5EFMu36Zine4R0TtEMueTJPRkzjqEXG-uh4af5QijFNvmxqUchI2PHHs_HhrVAXBKgwQx_0k8fxcF7dKvkcRx38U6DbduLOLDoDm60lkNh8sdYY9UIX0U-DSD9nyn6OOgDlOlL1hLsTXi9lt7npWQOMyfL8qa_7a-BJDJ9Kq-DrOI6eWmGwRPnuvbbDmdvxHfplJXyEr_ap7K5GSp-FpaQwcaK5sQlTSBuzepG0-p9465aWl9z3Ulg6ywINjxGx7TIeEklMQVUdzUEhtqNlY27-fFpXKgLp4aY03o2NnB6bQHoeOy7Ulxpsfy3PDaLMiLxMw1RHVIkf-irmSiwNg13Nj7kxpkyac6ZyfhI0BP5l9IWKdfULKpkF0AqhKEbJDO_GDN67GnMQMnDsFOOwUJ32P-hKBu8IB1ohNNEzGy-bW2VvM5g3a2GzP9xyfLPolDoW8oO1J6UPWWY8Pk75hc176w5Ixozfu9ezQW5utcOxZOI5CA77bI25eoGGsXolwNwJmuTyd5pxTK2UNhcKGyh6c4CWreWn5PZWvd3COYTOP1w3vhUv3aiABvjkVzrhxAWXBKs_UoRVixpd0bn9sEr97BX5R7jPsQzgtKWdsYe4YZ3Qv2ReQMURlMZ9WGsUXoB9Ylh8PpEnpUXeAqHHcaLarsu96sEovh1PP2YGMbWd2l4L93ZwQQqOs6Jjs_evfphC8jsQ3-wo466BzTdbmW8fZZDWAUP6zW-uGCaBlxJnYTjaYAxbdXOJCEyutz1vtcWprCEj65Y8ePundDBaYviRfVsYIC3K_MgFjwnfM6J1KeoJj_sEoaurCZ0PIlwXE2NwQd19G8xvjkwP_rZ-6HtT-0HCJb0UMmNJfhpR7gAYL2xq4OGGHw6NzuNTHndzi5FNFRoIZeEqY8aKURcgPA8NGgKhinXCg9nWhel1oIxvkhBaozkkCS0hKb3xI1yGZjoxHf7CSc6133CFb1UnhmLd9PbvcchLDbpG-TYf8QZ_0mxTm_0rUuR6C-GE.2QtrrXOZGq6FRXYNaQZnTA"}]}'
Figure A.24
A.3.2. Decode the JWT
See https://stackoverflow.com/questions/64616462/decode-jwt-header-python
test = json.loads(token)
obj = test['objects']
encdata = obj[0]['data']
encdata
Figure A.25
'eyJhbGciOiJkaXIiLCJjcml0IjpbImt1cmwiXSwiY3R5IjoiYXBwbGljYXRpb24vZ2VvK2pzb24iLCJlbmMiOiJBMjU2R0NNIiwia2lkIjoiMWI1MDZlMmYtZjU3Ni00YTlhLTk1NzAtNWY0MDY5OTFjZGIyIiwia3VybCI6Imh0dHBzOi8vb2djLmRlbW8uc2VjdXJlLWRpbWVuc2lvbnMuZGUva21zL2Rlay8xYjUwNmUyZi1mNTc2LTRhOWEtOTU3MC01ZjQwNjk5MWNkYjIifQ..YK40tObj6xY4jnkT.ai5wxo9uiLPZ0STOnnqmPMuBtZMu0qxbA3JYWzl_8cUPYogcWLrLLXhPP1FnqKnfews_EjJHt0XJuKoyhsXa3oQiGHadt3I6gGIlKDNNzSaB5bwTU31em8MSVmzm2m-O6ahKozMrjSoIwKvFh8X4Rgh7Tk-3GlglrBXJzw5qiznQDXGwz3ukGmHB0AVB78z12jJFmLcw7PsMOI5T3cTg5sGbTcySFgDxaFaV8pHRx-qbWVeKNb9aFcnIOLT1QWsA41p34nc7h8JwWy9779CU2PiBr9bmqE8aobDp_6JX8zRIeJgmcK0szi0LtK1TYAHzMYus5In2Z1ywsJeDACitr-TDQ1Pj8BjKzVVFVmOhdl9KnWhvLq8LvuLdijuR9T61anauWE4cLYgl6AYa4QDV2FVcgwn5G35yfrgSyvJi7_fZVeQhMesj2GbeslfvOciE9qfikoMjJ68g0NC8TbL8M7u_XIx6TQuJX1aXAXI1JgQrSlEX9KH9uBdeTqbzM9gmCDL9qy3WZgBPRzorSEi-H1hIObByfbysCG3JBh8nE4bnfuDBGcVlH-uCENOcZ98L1puXtBp57sscXFMb9mw2BrE-kJRBgzx-k_pO0jkVIo-4TIiz0Jo_SGTjDBHPMgyQswjy6C-l_RYBZFmF7MUBGuvT3kZYQyV2RVZBayMT2WFEFagrH6pTjGsqoDQC__oODkXJyufZBIpaBLiPj3SbhTmh_r0c0Q2-JS9XOBvt94pSe5j2PO1sBteoZ2dFjeM9URmwoScgTme478VqZErCHbN03KgguOWPp6InwnQUcI1yNTdCWju6EB4RaSwKzmN3caFNmwiEIiN4kutZy9Rr4TTSvels6u6waYQZYXAVh_yATOSfgXw3aWuITJGpq9xozNBuHLlZ6iJhGGGSeyRJe20swM_W-6OrPHML2Qu__tda_j2wt2_PO_stH0BW9K5s_wFDUfERbzw1-wKnbwYo-NIsm1fFUeHmNJrjiebPWUQfb5u3kMlV7U7_Qe6XUst7ZhEwDN_NYp4nZo5pCjuM1Cnp3eEoKwunRWsERI82oLTSFsYZi13xy-980NMpqCJNuvaSVHtCdBu2up7Z3tiNHZ-RrXlTa0QyfxEVABeX4L42zF0c57RLk0sb1jqKE30qsCjAz7LTW8ebSVp6Ef033pPC_Dk02zgLe9AK0xbDNPWTFHRaud3MC1zZsFHEcjfryKdBxdK51rU5q6s6EZcpL-_mkXrKkodTnagiEVYN9Nt-GMggR2xDvskjB5iqi28FTyLbHg0xc-tH2RGn7QeMYr4LK-KzPv2Ctsu3-x0mCwmHRaORqAecGt-t8PIXSy8emsveQqqFcD4_euh5M6cHLydipldKdTqroKqo6M-tiYsbWtcosc6_izapy7LGI8qP5E38P4jmA8ksjWiWFDSCIGbLTDamy3iN5owwkGGkQCg2lxgldrz1OVc9K2gecV1rNPtL_aTJ1Y_7OZpxiq9KNXpvwiUGdIhQbCkQW8csOkx9wKP4P0Kg9zdKcVUCCT9rc0yQxno82tm7U3H09HQHZx1SUB9xAly8umv0_RMDWLGAnhGI1xlNKT8rUhuhpsxBWQTgkFUyN_IRhKpvu3Q3pGXQzBvRnyYFk-VRS84aJjqjhEN3qChxYvF1voE5v0sS8b9zk2Vs0iwTa33D61zGk1ZZtygYN6hkfQCRCAzDdAqp6YPs1nXJ9iP4LEeXB9G9jqMg4vTf-ipwTnaYeW0FqS_MRLgj1ZOr3dBKEsb2cq7dPXv8JndfXL8WDKK1tdoHMhECdo_j_Lw7AXGjIg8Cs6zKG4GT1WO9wgbUQDKWhyUXRHMyowMJshm9_l-uVLCddupGilmUVSPCgV1iR2y0-eNtMgqtUG8eWhoLkbNc5Icbdbcc72JwF8TatKPJv0Z_YjAVo5s1pDGDwnaIDK9LgJ1t5nCOCsQR5FC2859QAwzg8HOkIByJvlJRKRJNxqmP-coBLuUw3wbnBm2rddUWEj7YhML9kqe0g0UhmOfdW93p1K8o8ojYBWcrNUXTbXThG1cfEhNb2BvCgve3EF-bub5P-TfL-iwQKn9vxrUWGyroTZZRXIhhm8PhzThg43nCLFik6dGOG27OoqsIm5d_sGs_sl7WgAc6aiENrtIoCFqPFJdvbyTAjIs5OZLWkZSEilRv3wnKSvrCnB6yz4OIqoO56jbDZumhV9gIrjztKc_c-4dH8ZB1AqEt1w7BIdh-mOG1yWNEn1ZsreLijlepeaDiBsRMtZO2xR7nJ0DOYUN_XGd5TtdgxTpgpgn_WR8uUmW8U_WBythu9oOHTXxDHwutv1nAu55AlT4Mrj2tYIWRBoFiCV6GgN65Od3tCTg7pKr-6FJI8Z-YHL-Q9Zzd0CDFnjhl-bGHOez7B8sXwD8u0PIqjnKjFl6qAfTWBcE2XJ0MiR7GC2xbSqDXXrQeFrz4G08MTS4_Vmv5c8h5pukaHSYvVU7wZmC9yBj_rBKxlQyVOnKkUPIbvwz3gQFA9mafrc6MvqRp5sys6eshcWTiFpA0fTAtnqtILdKP68a13kaXNPEZlPJcefFrW5djliMHoMMBYzqGqisv0EXUnmB5SVnMzbW5L_lG9Fr9Hu_0uUv589TgwCY89q1dpjDnZ0yzi0hUsOIf7dZ5xG-wktQwtBDqggvFKFxog717GjOaWOSz8B6IwQ333xaKBYzXLF3zW6xo_4u0edXBM5xhRuQkhZ-GMbTwFKzv0DSYwlEOkT-FOgTNpQE9CXH4ZzZwoXNLkehQmOsWmeJELKIymW3GFt7iczfysNa4jn20_3nIHGoyPG3pCtf0OAeMmGeIK9jPM0BcC90LIVxWfVwZ8RtrmB-pCLuCH40ikIRJR4zG5G0cs5KZg-k5xtcVdTTVDt4PVSu8OvU8ggV04-JNQwx73wY_bVUkMGLMpOhrrMXT-Wnv3Ck7uVwnTjmSflQtAU8F5YEUYC8tuTcgo5phTZsDIRacoI7dngCVxXtNGSyFWS0u-yWnmq9eHzHcmiL16B3tY2oLPVzCmvrlLPHjD2rCPCcXY1OUngV0vPvRugSaA8-FdVUbUNSybceqFzT9qoZFXTaJWrPgk84ydDpefbEWIf9SzfET1nzrtMd5QB8tVMKeS3y9IoUJXyGii3-PVMklJ05hRUCx90q-Lyt2_Bl0FKAqISzyCRZE4VmHpaPVt09JApBCwZ2UH6L0zrju-7hDhsoOIh50-zECrs6w6c1Bp9aMJsFHwW9onBNFK3L3TgLUqWy-_DEILvKJiBy3vonHVoso8gp81mCpsH6EY_YFAvrFmHyK6rQYNKIACGH37dbhiSkPiozibtay3NpMCRFikBskHPwCnamZ5EFMu36Zine4R0TtEMueTJPRkzjqEXG-uh4af5QijFNvmxqUchI2PHHs_HhrVAXBKgwQx_0k8fxcF7dKvkcRx38U6DbduLOLDoDm60lkNh8sdYY9UIX0U-DSD9nyn6OOgDlOlL1hLsTXi9lt7npWQOMyfL8qa_7a-BJDJ9Kq-DrOI6eWmGwRPnuvbbDmdvxHfplJXyEr_ap7K5GSp-FpaQwcaK5sQlTSBuzepG0-p9465aWl9z3Ulg6ywINjxGx7TIeEklMQVUdzUEhtqNlY27-fFpXKgLp4aY03o2NnB6bQHoeOy7Ulxpsfy3PDaLMiLxMw1RHVIkf-irmSiwNg13Nj7kxpkyac6ZyfhI0BP5l9IWKdfULKpkF0AqhKEbJDO_GDN67GnMQMnDsFOOwUJ32P-hKBu8IB1ohNNEzGy-bW2VvM5g3a2GzP9xyfLPolDoW8oO1J6UPWWY8Pk75hc176w5Ixozfu9ezQW5utcOxZOI5CA77bI25eoGGsXolwNwJmuTyd5pxTK2UNhcKGyh6c4CWreWn5PZWvd3COYTOP1w3vhUv3aiABvjkVzrhxAWXBKs_UoRVixpd0bn9sEr97BX5R7jPsQzgtKWdsYe4YZ3Qv2ReQMURlMZ9WGsUXoB9Ylh8PpEnpUXeAqHHcaLarsu96sEovh1PP2YGMbWd2l4L93ZwQQqOs6Jjs_evfphC8jsQ3-wo466BzTdbmW8fZZDWAUP6zW-uGCaBlxJnYTjaYAxbdXOJCEyutz1vtcWprCEj65Y8ePundDBaYviRfVsYIC3K_MgFjwnfM6J1KeoJj_sEoaurCZ0PIlwXE2NwQd19G8xvjkwP_rZ-6HtT-0HCJb0UMmNJfhpR7gAYL2xq4OGGHw6NzuNTHndzi5FNFRoIZeEqY8aKURcgPA8NGgKhinXCg9nWhel1oIxvkhBaozkkCS0hKb3xI1yGZjoxHf7CSc6133CFb1UnhmLd9PbvcchLDbpG-TYf8QZ_0mxTm_0rUuR6C-GE.2QtrrXOZGq6FRXYNaQZnTA'
Figure A.26
import json
from jwcrypto.common import base64url_decode
parts = encdata.split('.')
# get the first part of the token
jsondata = base64url_decode(parts[0])
data = json.loads(jsondata)
data
Figure A.27
{'alg': 'dir', 'crit': ['kurl'], 'cty': 'application/geo+json', 'enc': 'A256GCM', 'kid': '1b506e2f-f576-4a9a-9570-5f406991cdb2', 'kurl': 'https://ogc.demo.secure-dimensions.de/kms/dek/1b506e2f-f576-4a9a-9570-5f406991cdb2'}
Figure A.28
kid = data['kid']
kid
Figure A.29
'1b506e2f-f576-4a9a-9570-5f406991cdb2'
Figure A.30
# kurl is a custom field, used for the testbed.
kurl = data['kurl']
kurl
Figure A.31
'https://ogc.demo.secure-dimensions.de/kms/dek/1b506e2f-f576-4a9a-9570-5f406991cdb2'
Figure A.32
A.3.3. Get the key from KMS via de kid
See https://ogc.demo.secure-dimensions.de/kms/developers
# response = requests.get("https://ogc.demo.secure-dimensions.de/kms/dek/" + kid ,
response = requests.get( kurl ,
verify=bool(verify_ssl),
headers={'Accept': 'application/json', 'Authorization': 'Bearer ' + access_token})
data = json.loads(response.text)
data
Figure A.33
{'kid': '1b506e2f-f576-4a9a-9570-5f406991cdb2', 'alg': 'A256GCM', 'kty': 'oct', 'k': 'nPOHB8puwtwdAnqA4a5pb-iKOp9RgO77vdgUvGpyrOU', 'issuer': 'https://ogc.demo.secure-dimensions.de/pycsw', 'expires': 1666366239, 'issued_at': 1666365939, 'aud': '4f9610ac-9d1f-3797-6a41-6b18f9852572', 'sub': '4e7f5c63-0552-30f5-8b56-03e634ecd978'}
Figure A.34
A.3.4. Decode the payload
import jwt
from jwcrypto import jwk, jwe
from jwcrypto.common import JWSEHeaderParameter
# create the DEK from the response obtained from the KMS.
dek = jwk.JWK.from_json(response.text)
registry = {
'kurl': JWSEHeaderParameter(description='Key URL', mustprotect=True, supported=True, check_fn=None)
}
jwe_token = jwe.JWE( header_registry = registry )
jwe_token.deserialize(encdata)
jwe_token.decrypt(dek)
decrypted_payload = jwe_token.payload
data = json.loads(decrypted_payload)
jstr = json.dumps(data, indent=3)
md("```json\n" + jstr + "\n```\n")
Figure A.35
{
"type": "FeatureCollection",
"features": [
{
"id": "05f9e795-b1ab-4ff7-9d5b-96c8c6d19d99",
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
2.53,
50.67
],
[
2.53,
51.51
],
[
5.92,
51.51
],
[
5.92,
50.67
],
[
2.53,
50.67
]
]
]
},
"properties": {
"externalId": "05f9e795-b1ab-4ff7-9d5b-96c8c6d19d99",
"datetime": "2022-04-12",
"start_datetime": "2013-11-28",
"end_datetime": "1900-01-01",
"recordUpdated": "2022-07-21T22:40:13Z",
"type": "series",
"created": "2021-09-15",
"updated": "2022-04-12",
"title": "Interessante plaatsen (POI)",
"description": "Datasetreeks van datasets met interessante plaatsen",
"associations": [
{
"href": "https://geoservices.informatievlaanderen.be/overdrachtdiensten/POI/wfs?service=WFS&version=2.0.0&request=GetCapabilities",
"name": null,
"description": "WFS Interessante plaatsen",
"type": "OGC:WFS-2.0.0-http-get-capabilities",
"rel": "OGC:WFS-2.0.0-http-get-capabilities"
},
{
"href": "https://geoservices.informatievlaanderen.be/overdrachtdiensten/POI/wfs?request=GetFeature&version=2.0.0&typename=POI:POI&count=1",
"name": "POI:POI",
"description": "Points of Interest",
"type": "OGC:WFS-2.0.0-http-get-feature",
"rel": "OGC:WFS-2.0.0-http-get-feature"
}
],
"extent": {
"spatial": {
"bbox": [
[
2.53,
50.67,
5.92,
51.51
]
],
"crs": "http://www.opengis.net/def/crs/OGC/1.3/CRS84"
}
}
},
"links": [
{
"rel": "via",
"type": "application/xml",
"title": "This document as XML",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/05f9e795-b1ab-4ff7-9d5b-96c8c6d19d99?f=xml",
"hreflang": "en-US"
}
],
"assets": {}
}
],
"links": [
{
"rel": "self",
"type": "application/dcs+geo",
"title": "This document as DCS + GeoJSON",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items?key_challenge=123&limit=1&type=series&f=dcs+geo",
"hreflang": "en-US"
},
{
"rel": "alternate",
"type": "application/jose",
"title": "This document as JOSE + GeoJSON",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items?key_challenge=123&limit=1&type=series&f=jose",
"hreflang": "en-US"
},
{
"rel": "alternate",
"type": "application/jose;profile=jws",
"title": "This document as JWS",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items?key_challenge=123&limit=1&type=series&f=jws",
"hreflang": "en-US"
},
{
"rel": "alternate",
"type": "application/geo+json",
"title": "This document as GeoJSON",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/05f9e795-b1ab-4ff7-9d5b-96c8c6d19d99?f=json",
"hreflang": "en-US"
},
{
"rel": "alternate",
"type": "text/html",
"title": "This document as HTML",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/05f9e795-b1ab-4ff7-9d5b-96c8c6d19d99?f=html",
"hreflang": "en-US"
},
{
"rel": "collection",
"type": "application/json",
"title": "Collection URL",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main",
"hreflang": "en-US"
},
{
"rel": "next",
"type": "application/dcs+geo",
"title": "items (next)",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items?key_challenge=123&limit=1&type=series&f=dcs+geo&offset=1",
"hreflang": "en-US"
}
],
"numberMatched": 4,
"numberReturned": 1,
"bbox": [
2.53,
50.67,
5.92,
51.51
]
}
Figure A.36
show_on_map(data)
Figure A.37
Make this Notebook Trusted to load map: File → Trust Notebook
A.4. D113 GET /items/{item-id} with DCS (KMS)
Example: 3.1
> Access the OGC API-Records D113 /items/{item-id} with DCS
(application/dcs+geo)
# Get the access token from https://ogc.demo.secure-dimensions.de/token-app/
response = requests.get(endpoint_item + '?key_challenge=123',
verify=bool(verify_ssl),
headers={'Accept': 'application/dcs+geo', 'Authorization': 'Bearer ' + access_token})
response
Figure A.38
<Response [200]>
Figure A.39
A.4.1. JWT
Catalogue response corresponds to a JWT. The complete response is a JWE. The syntax is defined at https://openid.net/specs/draft-jones-json-web-encryption-02.html Contains 3 parts separated by dots…
token = response.text
token
Figure A.40
'{"type": "dcs+geo", "timestamp": "2022-10-21T17:25:42+02:00", "objects": [{"metadata": {"confidentiality_information": {"policy_identifier": "TB18", "classification": "unclassified"}, "creation_data_time": "2022-10-21T17:25:42+02:00", "number_matched": 1, "number_returned": 1, "bbox": {"bbox": [[2.83, 51.18, 3.02, 51.28]], "crs": "http://www.opengis.net/def/crs/OGC/1.3/CRS84"}, "links": [{"rel": "self", "type": "application/dcs+geo", "title": "This document as DCS + GeoJSON", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?key_challenge=123&f=dcs+geo", "hreflang": "en-US"}, {"rel": "alternate", "type": "application/jose", "title": "This document as JOSE + GeoJSON", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?key_challenge=123&f=jose", "hreflang": "en-US"}, {"rel": "alternate", "type": "application/jose;profile=jws", "title": "This document as JWS", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=jws", "hreflang": "en-US"}, {"rel": "alternate", "type": "application/geo+json", "title": "This document as GeoJSON", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=json", "hreflang": "en-US"}, {"rel": "alternate", "type": "text/html", "title": "This document as HTML", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=html", "hreflang": "en-US"}, {"rel": "collection", "type": "application/json", "title": "Collection URL", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main", "hreflang": "en-US"}]}, "data": "eyJhbGciOiJkaXIiLCJjcml0IjpbImt1cmwiXSwiY3R5IjoiYXBwbGljYXRpb24vZ2VvK2pzb24iLCJlbmMiOiJBMjU2R0NNIiwia2lkIjoiNmE5ZTU3MjctMzRjNi00MDQ1LWE0MmQtNzEyNWNiMzY2ZDJhIiwia3VybCI6Imh0dHBzOi8vb2djLmRlbW8uc2VjdXJlLWRpbWVuc2lvbnMuZGUva21zL2Rlay82YTllNTcyNy0zNGM2LTQwNDUtYTQyZC03MTI1Y2IzNjZkMmEifQ..hnfAseeN7cvoodM9.AGmIrQ7WeCJE0OTb0_aWTCN3ETNWrZZ-J9lnQlWD2QmJsIsScTYV70AoEMcqEl7W5OOmU_SfKEdvRiWgN6uPFvqMT8T99Hiv4CJU-m-8q46ob4vuqZ4fmSP6-zd5iJV-5l9-Sga9QwpZDzST-wbARHtcvDo-FUoUk9N2YXts4zEnCxit_YCrQ_ZIbV_odAfGl-iv31XbVZyyB_lye3zK3il5o--jPgdRRZwhqeoUaI8Uc9TevzU_8ffgw5UpYI_8Wf2IWKzP8cqciXmnE39WMGPI3-B3ZKtMGDtR4QOmdX8XVU56hYTWfYA8Rl8QJB0YOcfoongd1TzbZij9dV4DkY3-RIbhbGRMr3yUz1HcGA9OU0anC8JbbuOEdfdnBM5yPgaX9IL0i2ZJoi8xLB3ALYyP9vQJeY8RobS97ilSApIVEH4XxNq08ZyKFd1YjBdEEWObCawa3pWTCBwh2orlyiQVLOlE-PyGVw4u0Ge-GyRoAEbiOc3l_sKJA7qacaSuWZiI-xf6f6VAIRVLsb7EJj2xMg0KS5OyHQE2UUnTyRT5C0eWa26RGa3sqJ3FlHgy6ypSDMelN_5nWbpDzwJRG-EBQJeCBVPRq483cXmkRL0JlXR9yDw1LbfsOPY3ThsePPkdEDSRzYh-QN4Fz717TymMIP6lAXpdJEKRqMsD54GFNnmC6Dc-somEFv649wMdq_58o3TB2i9FevZhIuTQXwaHuufw6XrIFIOjpPkrHTkrsNZgXnpjnuRMSIGcjoTcqVNZ9oLzAiMOcMs5TK01oz8Mgn3doDjI1LzWnATf-Dm2FcOZuNj1sN4CGsGIUiYKLUvO0qnuu9ssgUuzCczJgQHQl8gIdpFKApyAuI52qiVi0gc6vwAFz2G8o21SwaW4GGdxLk1qcAGr54CmWOup617iinduyRqo6oQNOODKkIsu0Qa2G2nRUJNrVJLIggkepcql_zd0HQUVBug_dKCtsa_1oKmdIu-kvP3CVMmJF8AHIj6gu6PaogBvmp7KEWtC2kV4wNPnqmUp9r5vdqVuNP9Id3NmWFeAG7knM2huRZI-F44fnPSjIcj5PWLF5x9eQxXAG6ClOsBMVzilap7XNrPSQgyONHGxYre1HqGFMnD2RTLYBgUpumqFypSYMWURoWV0R77TBZaiQGjSwZ7Rb_myygx18TdLuDYUp_rIfZ8Ik8_LujTD0wDfHo1zWvcJ3XTQeiRz76ZJmK8-cizz1QwtaEGM7nOtK0umuap3dai3hycLUI-gGb_PgyszTxmn5N6L9B40mEMNaa_Yp8zNBft6-lSSsbOK0a3uEGj8u8sGoaiCeGy2W6RHoArzT7XAeedfCCAbq4_PiWph2iZ647DadgqrdqZKI6h5e-pUYUUH4RxIp6pYFfoB00OhYBPt5QbDK_-zPnhxkrgNkATQGFE18I94cbq4DliS0j-cCuQ5UBk2SJUqFapCZ2YK8qPE0lZf2WbLWpLRfKBUXeKeV2nRjYQWvw9g90DTPHmAa-JjKeo1ky8nfMavmVtxWrQ2fCN5d32gFuZd58zuvdDkFJ7-B1BccZ-kQ1JI50B-kUOQvwDg3P5ZszG-HNqyLCZ98FdaEuHgYJrFjg6FMJvBGnDxUW4xZAt_4rDnIvbySp7pxzYG0lpStMFg5F2aRd9gv5VIrcHfopy2PuSZ29M9P7pDdP6qqDeJ0oD4yqahmxa3m3IBLNdEcfYKWf0UZI7Q5Xzjx1GMynMhhq0ZpYGbdocz9GerLluKsZzqtOz--a-uvI7-AokVAJICvnd2Viipd-5QVTMwRDU3fq_6tEsDNY7Tp8uKYt65DoaRucplzHk32HeDgfXC2t_X_clCQR6XM6qgjH6uGKihGCxhlLIEfKIMEpuXbrTu5pOWPrfs8E8OG88SlkfKJxahw2GhLgWgoTh8-uL-ka9wVJNtdbi3wlbWdyAoBn7QVjGGd866NkcHZEfUA0crxBAEm-bmoEgQ32E5FlVQGSwbWG3xmQtbRSkI6Y1a7atL1blnuzTMKSpZO7QWkthlai-S_VmxRTFf3DuXeTFYDKC9ridb5isU6E18Q4JJKf7tj2fOdRt4DERLtVa8CCnza8TLSgI2R5rd5UvAqD0S-rsVwhkZjl2AfnI6Mc791qPcAIgO2V6b_PwnOGZlHuI6qwUHwu7e2y9HBSJ4F3K92As0ALPfFJ4LTbky33Uw9iQ11927-7eQME3GnQK_5ReNJTAOuVP03yROnXnoPmHzKibjBAjB93SYsebWMmPjwVxBYVcJSVaGe4iHaOcVuCaih_yk9pXj14rwk9XxM95EuwQGKaDsjmoAfwcRinYyiy3syR7LF0b5x0wP6Gu_7qHXEAvQuP2oSRdIYJ8VcHDDX3JDaIpMPHmAr08I6XtZBazj1j2-cctICTNtZY3EYc_II7ckhHARYdra3kkVS-387uajG9FxRNuOnTAl_9w5-YI_8rTm6JFAeD7ATrYt6nxrP_B5rklUD1vN4sAu7J7kLJOUHrmpCPXmrHyF_TKPG4SMDzzhxivE95iBJMnx3Odc8F1qbvjpDg4aHuVYT1HvcODCnIviMtvEyyRs_FUIrGthCAsiPBmDxzApk8xONMmBfnFBPvUjKNwwHGAXE6XqmtcMv3_I6MlsmNCODNb3UQsYOGQJxn9ZaS2twA_2vDLEK44eexgVc77oyNs1kPE19a0ptgZrxOxvSIjtMhxK2r1JER5EFY-Z7r817lLCPyl9bcPJMy5ZPGPDbwDXGRHNcWfLEIkStRf6LyxL82yhVRL18ALdRuCUVLaRIk9Xh3-YS9CXBKS31372R9bPb4op-aWj3gbDDB-5xFIfBoU3lqjvHs91BdHk5ScaP0sHqwYyiJ3C_iWxm12WzYXUjFRDz6xuKkS5OvQEcs9_Zmg2Yc9Th36g-mop2gJCDtQRMgT3mtGG6uwlmZGsSiamsHeZJCQQwAasWf27nR5e381BPkcNHZR4isGDFu3ck0Xe_aboKwWOKvaCX0rVDK9awQV5PSh5brvp3a-TJaGQpapTibiL1P5VcdU4Irp-SkzKNIJfkZ-lPJGVhZvxFBMcngGJU7rDF5PbeHblRM0aD414xR8Hn514XziTQsZTQQlF9Z5nBylo1ln1XbXaHHTZVyQw_NhMt5w_PEgNmsu1iRFSB4awfKBt9V-oMwRLo_qKA-hKJLmbT0feyFsp4mRoCDFl6o_cIVeLneiflvDp9MTEQBeM7dbfoiQs1JVpXtb6pgJWi4f6y-VFuFQ_D371MdebCXdBElzPf9LPgLcJw5XcGc8zO2zsKXZLukxupIgaPjwuFc14mM23jWra6MSnaMKrBxgW9rU8ivfxVkLUBESQbHGrqovh1g0JBXAK6Gx-nlPazcZK2LfBNhlAHNTmJq7IdNbaQFlKWEoRL6l1-DyemaeVuido3YUNW4O8rDsUKiEX9VS9s15eIbtOJ3pays1_nMRWHXKF_mULi3ME4UP_iwYphTl_vAPaTqkWzXGEq23GfMOF-HkwC8jdmeo8dIC1F7O9QJ2F3Fh8XPQs7HbBRUNtcsgUEl1igtACz5I5hTl075jIoBolSSIaDiCfdj3tj0XSjXRnm0plHxdjOpxib2skKUscR8OUudaB48oRCE3pdQSjKubG_ZZNruQrVmcOW2MgZ-DNjEgyIO3CT_DO8F70Zcy7jXzKILi61iSABPh-3MP4qGmRU0cCf8HpkbnuD_8-ah029Z_9fi6ghLuoa-6FPgSx56G80hnD0s3l44ks3d_GAtDJu33eD_mA40cRndbOWDKqKH-2Ch0ZJXXXHBYB7R-Vuq6LyHBasXYD_spVlkO25nH_3ZIHd0fa5EGct-Wf3twtz2CQEBQwWsjZrMbsVSLkztvUn3lk2CDqoqoU8lm5-bM7SMHfSHsJEgQZK-lQWXHdQSjuXppZpMbinDp-fv55kE0ZFtcVPsRvam4LS3L4OjghtMf6uRrzWS1dFG0NZ8Na4-WiIjQwuGroz8X1ulx73UwJabrhGQvmA8BuhpofqYrCyN79C_R8YuwGHNEOXbgRXprZ4syE1mlr0CvR7txC2D_F_ItmE3QMLAmSmam27jeDqTgQhyTSgozASPmV151tLcxfRjIoSAzBUJw-W6UmnRICExZOP0Mw674P5KFzH6veckK21puh21iTiWJ6HZMtTa7GxM1xu_ArZAZmpxZ1cn2KiUaZ2UUcD-KykvfOmF97jF4pTuwcJmzoFqFdq_znZYBsDG_01cEqQ-kbBAafj8s6Q-WtGdzhqifpV6rlWpwVpx_NNloI-iUItx79nBiYnGuzTA5bUoihIMVFHGS_zP7hjssm8Bfq0hAIqrYHdV7VU_2s1RVFBESW5BzE1E55f3wslshXr_FgcHFy7Kr72rb5tk1j3ZgsfCUuuaYDA7LlqeevYzU_G1zNP4CH8Mvlo58V2M7lX6JT7664Yi6eTmw4rr8bmNgQyENT4915mGetg8c0mLNI25Gz5q4NKl3cxZkqaQv8cXZ6GKTeJxYaQn78d-UNaJGZ7oqJ1Qmr2zpmdcNnJxlx07knVy8UNVzfaCuevIFnSn8VIWB9_SQyQ5YNhHIC445FV62ZNh5KgiwU2o0S1ia8zbVbJk3yUm85_iSQdFZbhtrTrp9ss92sf2BRr121mlR7tV5fXssiovUjYstppcIzHUxmTHFHh8KUhS2kqhP60nouVeHobMOuuWW37Y92nnU-15mfcUT1z7dqp--Fm31QzysOn4B6tieEDRZpssea_CHVnwPQS1NfBpx3t62ru6cNfa3qfjoBQijaO_7mVWBk1-uw6JaX82U25mwOePwof26gWDu_G33cHvfSN909ToSqSUtXs4kXxvoSfTAwV2Bz3OjIrIvk3qnfUpJXCMLf3fQD9em1ze9V_8P5Tw36kU2_BgfJRyBOW5pCWkJZGNRpl8XnfzNtd-1j7qfal71G1IcQ2UhQEZ7l0wgtr5MsbE4VUMZMmMoHIl7E9gwRVxVH8Mz1J9PojKvYrySbX1AAp9_zxtnMX_BBJ6aqP7nCC9Ju25l6Lfc9NPXq8WybMDvHhFy-YOwwc0MJ3S6SqoXaxmhxrdcCNGZfwFqJxSOydlRifZ5zC3XDdCSHPw907QMI5_esmFMhWr6FEFBHHNT8YExPOeojpRWDMsHqyb6wwH707o4SPm0Z81pJ1Sm918BTn_15Sg9nLBGv_PBoJJfgea88RnD50F2V39bDWYkUnNK_nFpzh2Gn7IQwoEZJWnuQakG-kON3aTb4XoRwpdkjClZO9bhKA4DNX6gIWPWme_c2H3SXORUYsLJKC91vuJki-_Bjg-6SH3uzuKwoX02HjaScY6mXmHBHNJCHC400VqjKE-mjDEHSBLIFn5LW4mKRk4soaw1LRXhIR9QQbViKKsX6wg1tNhdOlhj8UGtDKKJuxgROD0bB3SWt8WOnhyrR9dX2xkCxrBL3LTWzxTDtQldsVw2MBn0YKYNirc_-GNaUiE4tG0VJqUquFLQ4ZZcPTPgHDySKi2TO8RkXXYNtHcMzCH6evONOYDOv1nD2p4uhIGifX6JzJm4zL4_zMli2NhWBKsRGc918zncLaISfvy0xActIhYeHSUIdlBEA5cX-xTtIV9K-58cq0IgmfPXq3VbEA7kQBK633PkJlcgUjGwttFkyF1D-1rvkwcRyNMmRHIe_tyPrkgIiUJAyQvIYrnHV4LtLyuVuTe8TaXa7NCSZ5L6jMWuGU7d4WL-lPufvMVsvC6VtMoo42z5NpdxUq99rwxCym6C6mUmf8i0h6jis6VleMWg-ryQRSoooAsoBWOfsdqSv5EU7a4PJ1U907Rt_OoLspquvq8wNsmmEmH1Q.B6wQyyEzI-KmP_w9UAMT0A"}]}'
Figure A.41
A.4.2. Decode the JWT
See https://stackoverflow.com/questions/64616462/decode-jwt-header-python
test = json.loads(token)
obj = test['objects']
encdata = obj[0]['data']
encdata
Figure A.42
'eyJhbGciOiJkaXIiLCJjcml0IjpbImt1cmwiXSwiY3R5IjoiYXBwbGljYXRpb24vZ2VvK2pzb24iLCJlbmMiOiJBMjU2R0NNIiwia2lkIjoiNmE5ZTU3MjctMzRjNi00MDQ1LWE0MmQtNzEyNWNiMzY2ZDJhIiwia3VybCI6Imh0dHBzOi8vb2djLmRlbW8uc2VjdXJlLWRpbWVuc2lvbnMuZGUva21zL2Rlay82YTllNTcyNy0zNGM2LTQwNDUtYTQyZC03MTI1Y2IzNjZkMmEifQ..hnfAseeN7cvoodM9.AGmIrQ7WeCJE0OTb0_aWTCN3ETNWrZZ-J9lnQlWD2QmJsIsScTYV70AoEMcqEl7W5OOmU_SfKEdvRiWgN6uPFvqMT8T99Hiv4CJU-m-8q46ob4vuqZ4fmSP6-zd5iJV-5l9-Sga9QwpZDzST-wbARHtcvDo-FUoUk9N2YXts4zEnCxit_YCrQ_ZIbV_odAfGl-iv31XbVZyyB_lye3zK3il5o--jPgdRRZwhqeoUaI8Uc9TevzU_8ffgw5UpYI_8Wf2IWKzP8cqciXmnE39WMGPI3-B3ZKtMGDtR4QOmdX8XVU56hYTWfYA8Rl8QJB0YOcfoongd1TzbZij9dV4DkY3-RIbhbGRMr3yUz1HcGA9OU0anC8JbbuOEdfdnBM5yPgaX9IL0i2ZJoi8xLB3ALYyP9vQJeY8RobS97ilSApIVEH4XxNq08ZyKFd1YjBdEEWObCawa3pWTCBwh2orlyiQVLOlE-PyGVw4u0Ge-GyRoAEbiOc3l_sKJA7qacaSuWZiI-xf6f6VAIRVLsb7EJj2xMg0KS5OyHQE2UUnTyRT5C0eWa26RGa3sqJ3FlHgy6ypSDMelN_5nWbpDzwJRG-EBQJeCBVPRq483cXmkRL0JlXR9yDw1LbfsOPY3ThsePPkdEDSRzYh-QN4Fz717TymMIP6lAXpdJEKRqMsD54GFNnmC6Dc-somEFv649wMdq_58o3TB2i9FevZhIuTQXwaHuufw6XrIFIOjpPkrHTkrsNZgXnpjnuRMSIGcjoTcqVNZ9oLzAiMOcMs5TK01oz8Mgn3doDjI1LzWnATf-Dm2FcOZuNj1sN4CGsGIUiYKLUvO0qnuu9ssgUuzCczJgQHQl8gIdpFKApyAuI52qiVi0gc6vwAFz2G8o21SwaW4GGdxLk1qcAGr54CmWOup617iinduyRqo6oQNOODKkIsu0Qa2G2nRUJNrVJLIggkepcql_zd0HQUVBug_dKCtsa_1oKmdIu-kvP3CVMmJF8AHIj6gu6PaogBvmp7KEWtC2kV4wNPnqmUp9r5vdqVuNP9Id3NmWFeAG7knM2huRZI-F44fnPSjIcj5PWLF5x9eQxXAG6ClOsBMVzilap7XNrPSQgyONHGxYre1HqGFMnD2RTLYBgUpumqFypSYMWURoWV0R77TBZaiQGjSwZ7Rb_myygx18TdLuDYUp_rIfZ8Ik8_LujTD0wDfHo1zWvcJ3XTQeiRz76ZJmK8-cizz1QwtaEGM7nOtK0umuap3dai3hycLUI-gGb_PgyszTxmn5N6L9B40mEMNaa_Yp8zNBft6-lSSsbOK0a3uEGj8u8sGoaiCeGy2W6RHoArzT7XAeedfCCAbq4_PiWph2iZ647DadgqrdqZKI6h5e-pUYUUH4RxIp6pYFfoB00OhYBPt5QbDK_-zPnhxkrgNkATQGFE18I94cbq4DliS0j-cCuQ5UBk2SJUqFapCZ2YK8qPE0lZf2WbLWpLRfKBUXeKeV2nRjYQWvw9g90DTPHmAa-JjKeo1ky8nfMavmVtxWrQ2fCN5d32gFuZd58zuvdDkFJ7-B1BccZ-kQ1JI50B-kUOQvwDg3P5ZszG-HNqyLCZ98FdaEuHgYJrFjg6FMJvBGnDxUW4xZAt_4rDnIvbySp7pxzYG0lpStMFg5F2aRd9gv5VIrcHfopy2PuSZ29M9P7pDdP6qqDeJ0oD4yqahmxa3m3IBLNdEcfYKWf0UZI7Q5Xzjx1GMynMhhq0ZpYGbdocz9GerLluKsZzqtOz--a-uvI7-AokVAJICvnd2Viipd-5QVTMwRDU3fq_6tEsDNY7Tp8uKYt65DoaRucplzHk32HeDgfXC2t_X_clCQR6XM6qgjH6uGKihGCxhlLIEfKIMEpuXbrTu5pOWPrfs8E8OG88SlkfKJxahw2GhLgWgoTh8-uL-ka9wVJNtdbi3wlbWdyAoBn7QVjGGd866NkcHZEfUA0crxBAEm-bmoEgQ32E5FlVQGSwbWG3xmQtbRSkI6Y1a7atL1blnuzTMKSpZO7QWkthlai-S_VmxRTFf3DuXeTFYDKC9ridb5isU6E18Q4JJKf7tj2fOdRt4DERLtVa8CCnza8TLSgI2R5rd5UvAqD0S-rsVwhkZjl2AfnI6Mc791qPcAIgO2V6b_PwnOGZlHuI6qwUHwu7e2y9HBSJ4F3K92As0ALPfFJ4LTbky33Uw9iQ11927-7eQME3GnQK_5ReNJTAOuVP03yROnXnoPmHzKibjBAjB93SYsebWMmPjwVxBYVcJSVaGe4iHaOcVuCaih_yk9pXj14rwk9XxM95EuwQGKaDsjmoAfwcRinYyiy3syR7LF0b5x0wP6Gu_7qHXEAvQuP2oSRdIYJ8VcHDDX3JDaIpMPHmAr08I6XtZBazj1j2-cctICTNtZY3EYc_II7ckhHARYdra3kkVS-387uajG9FxRNuOnTAl_9w5-YI_8rTm6JFAeD7ATrYt6nxrP_B5rklUD1vN4sAu7J7kLJOUHrmpCPXmrHyF_TKPG4SMDzzhxivE95iBJMnx3Odc8F1qbvjpDg4aHuVYT1HvcODCnIviMtvEyyRs_FUIrGthCAsiPBmDxzApk8xONMmBfnFBPvUjKNwwHGAXE6XqmtcMv3_I6MlsmNCODNb3UQsYOGQJxn9ZaS2twA_2vDLEK44eexgVc77oyNs1kPE19a0ptgZrxOxvSIjtMhxK2r1JER5EFY-Z7r817lLCPyl9bcPJMy5ZPGPDbwDXGRHNcWfLEIkStRf6LyxL82yhVRL18ALdRuCUVLaRIk9Xh3-YS9CXBKS31372R9bPb4op-aWj3gbDDB-5xFIfBoU3lqjvHs91BdHk5ScaP0sHqwYyiJ3C_iWxm12WzYXUjFRDz6xuKkS5OvQEcs9_Zmg2Yc9Th36g-mop2gJCDtQRMgT3mtGG6uwlmZGsSiamsHeZJCQQwAasWf27nR5e381BPkcNHZR4isGDFu3ck0Xe_aboKwWOKvaCX0rVDK9awQV5PSh5brvp3a-TJaGQpapTibiL1P5VcdU4Irp-SkzKNIJfkZ-lPJGVhZvxFBMcngGJU7rDF5PbeHblRM0aD414xR8Hn514XziTQsZTQQlF9Z5nBylo1ln1XbXaHHTZVyQw_NhMt5w_PEgNmsu1iRFSB4awfKBt9V-oMwRLo_qKA-hKJLmbT0feyFsp4mRoCDFl6o_cIVeLneiflvDp9MTEQBeM7dbfoiQs1JVpXtb6pgJWi4f6y-VFuFQ_D371MdebCXdBElzPf9LPgLcJw5XcGc8zO2zsKXZLukxupIgaPjwuFc14mM23jWra6MSnaMKrBxgW9rU8ivfxVkLUBESQbHGrqovh1g0JBXAK6Gx-nlPazcZK2LfBNhlAHNTmJq7IdNbaQFlKWEoRL6l1-DyemaeVuido3YUNW4O8rDsUKiEX9VS9s15eIbtOJ3pays1_nMRWHXKF_mULi3ME4UP_iwYphTl_vAPaTqkWzXGEq23GfMOF-HkwC8jdmeo8dIC1F7O9QJ2F3Fh8XPQs7HbBRUNtcsgUEl1igtACz5I5hTl075jIoBolSSIaDiCfdj3tj0XSjXRnm0plHxdjOpxib2skKUscR8OUudaB48oRCE3pdQSjKubG_ZZNruQrVmcOW2MgZ-DNjEgyIO3CT_DO8F70Zcy7jXzKILi61iSABPh-3MP4qGmRU0cCf8HpkbnuD_8-ah029Z_9fi6ghLuoa-6FPgSx56G80hnD0s3l44ks3d_GAtDJu33eD_mA40cRndbOWDKqKH-2Ch0ZJXXXHBYB7R-Vuq6LyHBasXYD_spVlkO25nH_3ZIHd0fa5EGct-Wf3twtz2CQEBQwWsjZrMbsVSLkztvUn3lk2CDqoqoU8lm5-bM7SMHfSHsJEgQZK-lQWXHdQSjuXppZpMbinDp-fv55kE0ZFtcVPsRvam4LS3L4OjghtMf6uRrzWS1dFG0NZ8Na4-WiIjQwuGroz8X1ulx73UwJabrhGQvmA8BuhpofqYrCyN79C_R8YuwGHNEOXbgRXprZ4syE1mlr0CvR7txC2D_F_ItmE3QMLAmSmam27jeDqTgQhyTSgozASPmV151tLcxfRjIoSAzBUJw-W6UmnRICExZOP0Mw674P5KFzH6veckK21puh21iTiWJ6HZMtTa7GxM1xu_ArZAZmpxZ1cn2KiUaZ2UUcD-KykvfOmF97jF4pTuwcJmzoFqFdq_znZYBsDG_01cEqQ-kbBAafj8s6Q-WtGdzhqifpV6rlWpwVpx_NNloI-iUItx79nBiYnGuzTA5bUoihIMVFHGS_zP7hjssm8Bfq0hAIqrYHdV7VU_2s1RVFBESW5BzE1E55f3wslshXr_FgcHFy7Kr72rb5tk1j3ZgsfCUuuaYDA7LlqeevYzU_G1zNP4CH8Mvlo58V2M7lX6JT7664Yi6eTmw4rr8bmNgQyENT4915mGetg8c0mLNI25Gz5q4NKl3cxZkqaQv8cXZ6GKTeJxYaQn78d-UNaJGZ7oqJ1Qmr2zpmdcNnJxlx07knVy8UNVzfaCuevIFnSn8VIWB9_SQyQ5YNhHIC445FV62ZNh5KgiwU2o0S1ia8zbVbJk3yUm85_iSQdFZbhtrTrp9ss92sf2BRr121mlR7tV5fXssiovUjYstppcIzHUxmTHFHh8KUhS2kqhP60nouVeHobMOuuWW37Y92nnU-15mfcUT1z7dqp--Fm31QzysOn4B6tieEDRZpssea_CHVnwPQS1NfBpx3t62ru6cNfa3qfjoBQijaO_7mVWBk1-uw6JaX82U25mwOePwof26gWDu_G33cHvfSN909ToSqSUtXs4kXxvoSfTAwV2Bz3OjIrIvk3qnfUpJXCMLf3fQD9em1ze9V_8P5Tw36kU2_BgfJRyBOW5pCWkJZGNRpl8XnfzNtd-1j7qfal71G1IcQ2UhQEZ7l0wgtr5MsbE4VUMZMmMoHIl7E9gwRVxVH8Mz1J9PojKvYrySbX1AAp9_zxtnMX_BBJ6aqP7nCC9Ju25l6Lfc9NPXq8WybMDvHhFy-YOwwc0MJ3S6SqoXaxmhxrdcCNGZfwFqJxSOydlRifZ5zC3XDdCSHPw907QMI5_esmFMhWr6FEFBHHNT8YExPOeojpRWDMsHqyb6wwH707o4SPm0Z81pJ1Sm918BTn_15Sg9nLBGv_PBoJJfgea88RnD50F2V39bDWYkUnNK_nFpzh2Gn7IQwoEZJWnuQakG-kON3aTb4XoRwpdkjClZO9bhKA4DNX6gIWPWme_c2H3SXORUYsLJKC91vuJki-_Bjg-6SH3uzuKwoX02HjaScY6mXmHBHNJCHC400VqjKE-mjDEHSBLIFn5LW4mKRk4soaw1LRXhIR9QQbViKKsX6wg1tNhdOlhj8UGtDKKJuxgROD0bB3SWt8WOnhyrR9dX2xkCxrBL3LTWzxTDtQldsVw2MBn0YKYNirc_-GNaUiE4tG0VJqUquFLQ4ZZcPTPgHDySKi2TO8RkXXYNtHcMzCH6evONOYDOv1nD2p4uhIGifX6JzJm4zL4_zMli2NhWBKsRGc918zncLaISfvy0xActIhYeHSUIdlBEA5cX-xTtIV9K-58cq0IgmfPXq3VbEA7kQBK633PkJlcgUjGwttFkyF1D-1rvkwcRyNMmRHIe_tyPrkgIiUJAyQvIYrnHV4LtLyuVuTe8TaXa7NCSZ5L6jMWuGU7d4WL-lPufvMVsvC6VtMoo42z5NpdxUq99rwxCym6C6mUmf8i0h6jis6VleMWg-ryQRSoooAsoBWOfsdqSv5EU7a4PJ1U907Rt_OoLspquvq8wNsmmEmH1Q.B6wQyyEzI-KmP_w9UAMT0A'
Figure A.43
import json
from jwcrypto.common import base64url_decode
parts = encdata.split('.')
# get the first part of the token
jsondata = base64url_decode(parts[0])
data = json.loads(jsondata)
data
Figure A.44
{'alg': 'dir', 'crit': ['kurl'], 'cty': 'application/geo+json', 'enc': 'A256GCM', 'kid': '6a9e5727-34c6-4045-a42d-7125cb366d2a', 'kurl': 'https://ogc.demo.secure-dimensions.de/kms/dek/6a9e5727-34c6-4045-a42d-7125cb366d2a'}
Figure A.45
# header contains the 'kid' which can be requested to the KMS.
kid = data['kid']
kid
Figure A.46
'6a9e5727-34c6-4045-a42d-7125cb366d2a'
Figure A.47
# header contains the 'kurl' which is the URL to retrieve the key with 'kid' from the KMS.
kurl = data['kurl']
kurl
Figure A.48
'https://ogc.demo.secure-dimensions.de/kms/dek/6a9e5727-34c6-4045-a42d-7125cb366d2a'
Figure A.49
A.4.3. Get the key from KMS via de kid
See https://ogc.demo.secure-dimensions.de/kms/developers
response = requests.get( kurl ,
verify=bool(verify_ssl),
headers={'Accept': 'application/json', 'Authorization': 'Bearer ' + access_token})
data = json.loads(response.text)
data
Figure A.50
{'kid': '6a9e5727-34c6-4045-a42d-7125cb366d2a', 'alg': 'A256GCM', 'kty': 'oct', 'k': 'UbFiy-2i3nzPkaUVEvkDF29FDoN7vRUjN5ACBvoohA0', 'issuer': 'https://ogc.demo.secure-dimensions.de/pycsw', 'expires': 1666366243, 'issued_at': 1666365942, 'aud': '4f9610ac-9d1f-3797-6a41-6b18f9852572', 'sub': '4e7f5c63-0552-30f5-8b56-03e634ecd978'}
Figure A.51
A.4.4. Decode the payload
import jwt
from jwcrypto import jwk, jwe
# create the DEK from the response obtained from the KMS.
dek = jwk.JWK.from_json(response.text)
registry = {
'kurl': JWSEHeaderParameter(description='Key URL', mustprotect=True, supported=True, check_fn=None)
}
jwe_token = jwe.JWE(header_registry = registry )
jwe_token.deserialize(encdata)
jwe_token.decrypt(dek)
decrypted_payload = jwe_token.payload
data = json.loads(decrypted_payload)
jstr = json.dumps(data, indent=3)
md("```json\n" + jstr + "\n```\n")
Figure A.52
{
"id": "PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001",
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
2.83,
51.18
],
[
2.83,
51.28
],
[
3.02,
51.28
],
[
3.02,
51.18
],
[
2.83,
51.18
]
]
]
},
"properties": {
"externalId": "PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001",
"datetime": "2022-06-30T14:16:24",
"start_datetime": "2022-03-07T14:02:00Z",
"end_datetime": "2022-03-07T14:06:00Z",
"recordUpdated": "2022-07-21T22:40:13Z",
"type": "dataset",
"created": "2019-05-22",
"updated": "2022-06-30T14:16:24",
"title": "Proba CHRIS Level 1A",
"description": "CHRIS acquires a set of up to five images of each target during\n each acquisition sequence, these images are acquired when Proba-1 is pointing at\n distinct angles with respect to the target. CHRIS Level 1A products (supplied in\n HDF data files, version 4.1r3) include five formal CHRIS imaging modes,\n classified as modes 1 to 5: \u2022 MODE 1: Full swath width, 62 spectral bands, 773nm\n / 1036nm, nadir ground sampling distance 34m @ 556km \u2022 MODE 2 WATER BANDS: Full\n swath width, 18 spectral bands, nadir ground sampling distance 17m @ 556km \u2022\n MODE 3 LAND CHANNELS: Full swath width, 18 spectral bands, nadir ground sampling\n distance 17m @ 556km \u2022 MODE 4 CHLOROPHYL BAND SET: Full swath width, 18 spectral\n bands, nadir ground sampling distance 17m @ 556km \u2022 MODE 5 LAND CHANNELS: Half\n swath width, 37 spectral bands, nadir ground sampling distance 17m @ 556km All\n Proba-1 passes are systematically acquired according to the current acquisition\n plan, CHRIS data are processed every day to Level 1A and made available to ESA\n users. Observation over a new specific area can be performed by submitting the\n request to add a new site to the acquisition plan.",
"associations": [
{
"href": "https://tpm-ds.eo.esa.int/oads/data/PROBA1-CHRIS/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP",
"name": "Download",
"description": null,
"type": "WWW:DOWNLOAD",
"rel": "WWW:DOWNLOAD"
},
{
"href": "http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/browse/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP_BID.PNG",
"name": "QUICKLOOK",
"description": null,
"type": null,
"rel": null
},
{
"href": "http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/thumbnail/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP_TIMG.jpg",
"name": "THUMBNAIL",
"description": null,
"type": null,
"rel": null
}
],
"extent": {
"spatial": {
"bbox": [
[
2.83,
51.18,
3.02,
51.28
]
],
"crs": "http://www.opengis.net/def/crs/OGC/1.3/CRS84"
}
}
},
"links": [
{
"rel": "self",
"type": "application/dcs+geo",
"title": "This document as DCS + GeoJSON",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?key_challenge=123&f=dcs+geo",
"hreflang": "en-US"
},
{
"rel": "alternate",
"type": "application/jose",
"title": "This document as JOSE + GeoJSON",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?key_challenge=123&f=jose",
"hreflang": "en-US"
},
{
"rel": "alternate",
"type": "application/jose;profile=jws",
"title": "This document as JWS",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=jws",
"hreflang": "en-US"
},
{
"rel": "alternate",
"type": "application/geo+json",
"title": "This document as GeoJSON",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=json",
"hreflang": "en-US"
},
{
"rel": "alternate",
"type": "text/html",
"title": "This document as HTML",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=html",
"hreflang": "en-US"
},
{
"rel": "collection",
"type": "application/json",
"title": "Collection URL",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main",
"hreflang": "en-US"
}
],
"assets": {}
}
Figure A.53
show_on_map(data)
Figure A.54
Make this Notebook Trusted to load map: File → Trust Notebook
A.5. D113 GET /items/{item-id} with DCS (JOSE)
Example: 3.2
> Access the OGC API-Records D113 /items/{item-id} with DCS
(application/jose) and public key. See
https://www.rfc-editor.org/rfc/rfc7515.html.
# Prepare client key pair for encryption/decryption (public and private)
cli_kid = "clikid"
ce_key = jwk.JWK(generate='RSA', kid=cli_kid, use="enc" )
ce_key.export(False, True)
Figure A.55
{'kty': 'RSA', 'use': 'enc', 'kid': 'clikid', 'n': 'rLItABpzNyhZDBFhi1kRX1PdlMVeT1d_Tik4bFwOcW7foc1R4O-oswjMGrhgSRDAj-n4B_anrQ6Z0hzr58aC0yEI_ueNzdnpOECFoA5vHPjunqHv9gqqa1vIQq4GDbEsjYA5iJ828UQVpTrdY7RUC-qT9B0Ib4TW2HcCvBuxrOh4kiswLFrfEtS2QJcYh4tScMFzZdIY985s2sDTf0qxdU7c4h84J_y292mfce-0egMzamnYOGOZfcoGXCtDC-pB6TbWGWtLAhfpkwRc1qiQUqcMru8X896eIIYjUjQdKnVc5nfwa0cUy8KlC29m0zAVQwuzUJHsnZuuCgqXyGj6xQ', 'e': 'AQAB'}
Figure A.56
# Convert the public key into a comma-separated string to pass as query parameter (as per OpenAPI example)
ce_pk = ce_key.export(private_key=False, as_dict=True)
cli_public_key = ",".join(",".join([key, str(value)])
for key, value in ce_pk.items())
cli_public_key
Figure A.57
'kty,RSA,use,enc,kid,clikid,n,rLItABpzNyhZDBFhi1kRX1PdlMVeT1d_Tik4bFwOcW7foc1R4O-oswjMGrhgSRDAj-n4B_anrQ6Z0hzr58aC0yEI_ueNzdnpOECFoA5vHPjunqHv9gqqa1vIQq4GDbEsjYA5iJ828UQVpTrdY7RUC-qT9B0Ib4TW2HcCvBuxrOh4kiswLFrfEtS2QJcYh4tScMFzZdIY985s2sDTf0qxdU7c4h84J_y292mfce-0egMzamnYOGOZfcoGXCtDC-pB6TbWGWtLAhfpkwRc1qiQUqcMru8X896eIIYjUjQdKnVc5nfwa0cUy8KlC29m0zAVQwuzUJHsnZuuCgqXyGj6xQ,e,AQAB'
Figure A.58
response = requests.get(endpoint_item + '?public_key=' + cli_public_key,
verify=bool(verify_ssl),
headers={'Accept': 'application/jose', 'Authorization': 'Bearer ' + access_token})
response
Figure A.59
<Response [200]>
Figure A.60
A.5.1. Get JOSE response
Catalogue response is an application/jose structure (RFC7515) encoded as a series of base64url-encoded values (some of which may be the empty string), each separated from the next by a single period (`.’) character. Next steps are the same as the application/dcs+geo decoding, but the decryption key is known by the client and does not need to be retrieved from the KMS with information obtained in the response.
encdata = response.text
encdata
Figure A.61
'eyJhbGciOiJSU0EtT0FFUCIsImN0eSI6ImFwcGxpY2F0aW9uL2dlbytqc29uIiwiZW5jIjoiQTEyOEdDTSIsImtpZCI6ImNsaWtpZCJ9.cMgGbydXjpDK2NasNt5_xhBI0CU1pJ7LkWPRtqGZ2rqlmHF7sEE18cpDcpmb0LvUiNrvwzqpzZ6_6SsGqusZWPk_i-X6eUBzDbuS_R35vjpZeaPdINQVCp39f4f5vZXXmOcA9fvLYPLA8HHNH2eNAEi8-5ZEVBcOoUKYN4NTK32xrsA6WZ0KEVV7Mhndn9XavQZe6gcuTrr3cyokt0m_P4imOuynuvqt02ZVAHGRpBwc48ItHEs18T2q953xl3yi8O_hNVwZxSgGfhLwIRTdOfYfpSkZpZotT6qplZyTT_SNVZqtyvlOfAYgQZc1BLbu5VomqbL2tuqxGkfszj7hWA.Co1isjTv7pCSgz2l.8YYNi1GSZmls7-EaVxR2tEFBaHFvJSDkFyxe6gqMD9nxbu4TWHMOf1CmAtUC8mSrb7uInenFgUa1l4SOB2_MJtW1oUZ_SPCZoQ-FciZ24zJ6gcxCV2JixFC3YZpcxnFm4vQ-LcPwffKwXTSqlP0xeCwL-x4aOxrDWME7GA5s9LAW-HcdWG4ZKbHspLBLjgG-eul642baBWnOEPhV4XoQ-kX4h1DoPj41KkXcXFBlojh9-YLYmjtK8_kYEnaL9htY6VbNHyqvmn6j5Q7P1FDEfL_he4PYgLGRx0sBHpqvvim2xfUMWnPm_E3UiZ3NKQojADiHbUyBQR05HesN4cS7wXF_VOPYz5ZdweBoSkCyGbe9fc1ruOFT7Sm9zuLjv04Oq0p27hyraxeILh_l8MLCQnJXbzn7jGbqHtescQTwM4ewBAAOSP3kb6u26wNYGq7GDYnww9DBhb05QUhtXR0ISRPDjv6KVxcgWSC0R8CR4BT4mghUfFNBsT7LtPqRnWgFCrOfnLHM8Ldhn9N_FpyI6mLfQEQa6kKvJm0EeZ3r4HWCrWCtFGJ-uqc_oRtnKJh5xWecql0VPbcC3xRJAB2LYNPNyqrl54nEabf0XjleInV6mcVzhn2EBQt_Z9lWp5JcQU3z945oxGP9FfiXV7lTLvwW5XsGNTYx0qBqTJkCaqwxPaj_en8ojRJI2muk2NPnXEOZZkP_Ds_kVG2SWberwReMGqtMv5i28IrG1gSQO46365dCc-R43B7cAw4LvR9TTL1mp1WVBe0E8ppW19OAuktaGOHDM1k0H77cGQsJOt_yUANsMyaR9FyfN1shY0LHqj6nA03XwLr-vz9PRn-PFJCUATGjbR1CfIfI851gxNwfeCgdXlOs9bFxd41FmkgHR1auTkCNuGGfkXt7-VPBVtyFFDNWcNUEyfL1w95i6iRWFtxOQxNToFtVPmRhT9p31gcgBNsLy33p0RdqIcAElfG5BKDJ7P31tJOoWtVywhibvzXJ2Ojye35QtDpyMvvHZrm2oGyCSHJR4aGE5uiHicQZiTBO3JVvWKZo8ocTizkImrttPY-0xe2e5TAvSiorZPzlXxlIUiDlhc-6NUs_FykQUKGA-IeCM_RsG6qpB52bhO0nfECV1YC6YuKkQbWihzGcOO4Ze5mWKdvfmNGU5AVbqDtbW3S1mkAc6WA038p0EiUM4L3THtUWw2ea4EP9OVKex-3aqKboERmyGAYNUn7gR27N-MDlYUxafZWy1nP5Sw_CgdWCtPMGkvUFFKrMBCN84gsmuwreQJGF-yiDBruOsL0nYKUyNgEeCrA3tnP9SVVHDvv-ZDC1svuxbZb_9O9WAX6B7sdsZsDV5dQ-vph49IPhys6IcNV-doC9ettkuTH7RO2x7ZSop7uasGSP9tVljXr0amC0uxCB5oudxLAHm_MacH9XiVD6pnY3aAdRoGaBWdNVqgHJnKympn1z2ZsRnHT7JnRfSrfXHVV0ja4K0B6w0GHL3tIRicRZXpy68Y4zqY3ore2XWeN8o5-RNvlYC0mbD1OdkS4Jokor14ikOtFvUxU8ti01VSkZPKDNUGSJ6391VsG5HRfh54mZr1gnAc0jRWgz7TWH1LytZwwqfxIFhWzqGCQCNWgI8VC4y8VRhKXyxoO5BsHn_LG5i6mUAEfQPVj0LiKJX1qUTtFux1n01aDRXp0gEca1QLknxffBMlwEL0_d_q0BD4AwXB8e7KW56s5PkY2HdqLnKmrA_e3-gwFDewcq-463V0ah0zRfARWXBjo8dsL6ezuuoBLSvurpvPOBWmMngmouqHZJ6jq2f6GM3oWyuwqGUJefeGjiP7cMEfsEK48Z2E1YJiEpA5Mvo-gbYrPXtJxzlQj6x6em95KQbvg_pFbbakr9qMjFCpd7pKk3YLlBYHma-61fzR9CDS-pJps_oEm1ApE8MLbDJgD_UtHyBbz2tHQOCtjFR7BSoajgGq1p8wZ83_a4acyzYjgXmZnls_ZuDrplw1G2Si_7kq4zllepo9_dwE-eFKtZGlUqeofGq6eHS61ndXBuoGwjsGFBShmfNPNqp0hDcAO_jShiLclB8b9uM0e6VE5faJHsZyD1AzBzbi1F46U9m96eiwWjUadHgtKOQ1b27gATLQ1ksuaWdWbHTC-O4VTINVGaZLRYEhSouLJfDGtQ-FpaRA76TbL1qCNhdQ03yYqn4DTgQ8W-QkGzTaz4tVODfqIRPouanmIFKjvhkgAJcds3OvllOaBCEkO-mS6HNawji81yz78mtIJ03jtNm9zXkwxxs7KTJ-GPDtb_2oaIDKAT1cqPixKyD1227OWReF4RSOtKKxw6hIO0mzt-LUIeOCoA5xK2YNABOi7-kqdS4vPDIF-t-WMgrNQf-MT9K9uSqZvUhcyNzhnEuSRu5pUMUjkB-gvKq5EwLjx_JsdovrwqouPIR2XV9iOczk3Pzmv1zsQuug-5KjD7_NGfWzQz8BzG1DfrhPB0y0W8y__wLNd1Q1Hc--2SsV82OygqWFz1RwwQ3pMfHGsmm74cbhGtMKQe4NeasukvJDtDdeezVxROPAWFDS4G3aq8JJirb_NByDSv9skKEaY8fRopfmDTT06seWM7N-SD_VTbEK13lJQKXZiN9xVRNJrQmPmWP3pXAQH65oFMP9L4xlqcgBQrujS1P9bZ2rM2FB9cfz4iMOZwWaeSyJ-cx8f7F9pm9rnH9-zrcrqomn-OvqRlFMT9Ih675k1C-rUd3P662OO6Hr_RyQfk35CMHZmBt-uu8bHk6xzpstoixqv6SfAe9R_EhgEdavRl4OCxHv-TFT-HctOF12ySX1LFrh6T9nKDiJawFGntyVD1Vwfaoek433_sXsH6Dd5YJet5TQlWyAGxdwmvOEm9bDXhvNgrUMXeFDDTheDS9Vb5s265kFb41Su0Cw98DB-MlueChFzJCo-RmAas6HUBl0HDVguoYurRfYraSM8xRDs6uJu4woeUs5WIz8XdR5DvD0mZ5orAuL97a3zzGvSID5ttPbDdVcUDpy6ySkpERN5wrOIVQkCDxXjzQW7sB9VWeZlviJ-nVBEmDUQjEqtjmOd9oGnOyEQT3WsKvrhk2tDxHC1jFx6n6sgtKK77EJwCffwzLwATLmOnVLEbpGVfLgVQ1h8473whRAbv9eUGkVk16Kh0OxMnSAN4iMJCjLr_9aPqGyqipVaxfAAgiF5zgEOPW7ShQoYt5cUqfInYYIsPfS6M7hWcu3D0VMr4j7bFgU1z1iSvcUyKT1jR-cHApGZFE_aGvsGKdFpomye1ufbnP0z4ieoUbzgka90MTieFON3SuK_QFd1rXuuBfeVGlEDdZY0dO1-a_zducQgfzJA3Nd49dJu2ORtfnvBoYmJtRMAe-7J2mEzPbLpB14rIldHLzVfqXG-GNd934Gl21IWV-oez1XilQejeGPHOTlI9puezxQE-rcucah7wN1nB4yICb1W2iYsXMYj28zkQwWwdlN4gbdQjmAHB_k1I7Owta7jphFrqg9owbIXRAWaMng4TS_HIlH9Bke9W81geLkmQnGqFL-J1qr1XtVGE3xsQW2GTOOlH0YzY_ci5rSSr9vF39iUrrB75QUxExTFPLDsZOBxDlQ__SMDWHBfx051tymzeMasY3Cf0_EiTyDHUu-Mgct9ZSfLljB3BH5Ij3cekFgHK3mVjwcn_3RQfWNdrRjAM7tb8BsQQ-z0U8GvC7TN6nbonfwDYV6dgAWqDFhEhxujnfZuIwja_CLBzvDpGPk6Qa6U3_DpNmw4NmsE8TTY9RB8__CXwPHoL6rAASKNOrQuKuGqMVnUGt_3zaZ0VV89XaIntuFszSUDrp-82XxmzjBJMbV7GVyti3bwP0XM3_ltqfKIh-mhAIUXJPIqxurdqFWbwwqAbo9qr2D0nTCZRW05Stzml7etgmcQFYTtKOFUAx31qjhNvZa7Q26knMut8B8yJY7xaj9SSpVAlR6KFWEnEtmJNcAnDfSorPPOrZ8PGWNMzV_ZjKSaS5OEHkjftj9flox5zShioPxfIw2UOktWNZXlphezOW_YkFHW-3td1990aUv46dEM6kfLpHM3L8KqB2vz3dWq9wUqQVJFcdIMgHvPlEz84yV0-LGj9pORqXFeRET7EFCl5g5m49GpqBW4vdsneYphnvqY6pe-QIk5zRXAnVlZo1RlXIhM0oBynJD69jZ7ia7rb-JNZh7pRfP1XHeTanyegFqVnLrwAV3Y3NZDhl_NFlFgSBWOhLt2XISEez1SAlk6tm_k4jhVXQX4QRWmUpaSzTNzXTv3AEtJKeYK78yHHDNe1d6ks1XBELkXzlOWlfA-hHmEm-csW0HRyqW_RV_VAASN_H1Q6Bqrq2JOUS6KdWmOFRAKq6rKwDyr9CJMPWA4uVCY0I06mBpqF0M1ClvPzLkAy2TjEJQv2VEim-ctaTicDEt2ITTbIHvKTd9vuJc32mkHGkPSqM7cETeo36tZ5oOZWoSuHXj_ZMoResjZ-dWQVUKdJRkAwXKPcxc7ZpDMGkK2StNizZys3k0Yla3XSZ4ahYU-yKqmiq32MC-G8CPr35LR6CgnkhTQtRGgO-H2h-Pbf1VY-K5E7Mgx1mLjGfeIHLmILoCLBeRFtio9UUJ31MLUza5EJOAZ8DecoEp34RUzckfmI1zKrLVVbQFIcfK0IeLuxrokemJk_8a5-DoUx1sgMzTzjBIejnjv49L-hkT5X5ARB1Svq6YP2nKcg1zQi4z9R7U-IGTd0pCnYSviKatuuwZB0NGKv3N7VM7hl0UOWvFB0zBoNLULvGc1xBW6heEjtnoyG5IwhKgd6VF4Zr0_9OzXtyyM6UyjUrSVmeHLazpLoh6YDEXUK5dK5fcpKHYWDL9GZZeUhXxs-pv3nOuyXNCXuFUI7kKXaAgwaLOZIThP7qMZ8UmojEeS3SMBFS3wEb8UU9ugcmLwEU9tO-cuQwoQ8WAYyhBxFwha3F66_blZa244BN-5cF_LmOrjtzLbK6GLIhSzcSraYgPPmdd3nR0iwJRN4fLg0bwnN4_LrilHKsf8dK3JvUN7qRblRGLAQV-ASyt43slkknT1r90x49dnRIbyRrL23Kt3xG0ZGR3sLg8Bsiz8XilyiadTEi9eJIetbIH7Xznt4jmFyL1SQN-1ujVISru-YqaB7tvzIIYAT-ZegTVwXrQSgrJakg05UA5NNGc3Xuzetoi6P1gtklq2HnNKFzcfctMV7Ps36_y70omMYBKYDYD3yuKMfzkLgVZDvbRQeADQYWEpIi_l58y2XYAGjHBJPNN7NToKJ3E-B0-bUnBw-W9AgHndIjQFJ8lBn3zP3CyGg603lcvjfz-avCr2SAZpq-O_j7LvMWd_gbFJ0eapkCRE2TnbCfERX-58ZpJ0LivJxEbi6OgkG_a1p76QpClFocuB9dDh2C3_sAaTKIA1T44aufJJ_q7NAB4d03KbNmDXebq7yDrkJOufRqYK5DafR6UjEwWF2Qekpx24XqslNTwzd_rtE1ZwpmGN6AEKF0VxU4ws97GPqAu89w9DSX0sXEIW9hGj5RxxmR106Ne4B8q_LF9t9VP4Al00_0jVOTsbfTjLQyj8w2BVDwN8hqxyanvOoSMDMH6R_CTmlA6UQv0GukohZ5fC82xdWxjVBm-xYHy9LeLMBQrpymlOnCo08fbvAFC5s2gNWXdA6n0Ub3FL32N1bJh8HIJQKOaPvSksuMWRORg78zqMIta_U2O5eInSUHBuj7ehdmL_fxltqkMKYuzlox9L7rNYBWad8OTtARcsMDvUNrzoTq-0EKkTiO48fgEKlAYUbtrUOnJ_CKIPpaYiK6tuJ5O_I4iRwSZ_ZGxpGd8hKBxlyCYZt0pVhhJSQYjIM60Mq5VO_rN9cyTtOlCzDHRcfU43DO8ut1vesjoQFtKGjcK9j6cuvB8S2cL-MwIXi6Gdea7e89FwY9-1xg-rhb3t-MccX67zojYcOl3HQ3hg86E43RAvHRZ3H1Bf_m0DUc8iom3_abLa3xpP5nSmrKyh2gkBFgDK0UifV1FhBoEre6bmrrOQTedw2q8HZ2olS4t5aADLBIpWsMKBmlcTrhAVMvKV_QUpECzY7xTeYK-CMkN1IgMKFwtG3QjrbEHcO958edS62ho5STTjo6JBIJry7R6o1FytiASbx8duOyJdEzg1yhQqI8I1RsGROBo1zucgyky6RukPFN1gkK7OL_50TBnm9W1bzaaYPyn8c76rl3KMx5WkEZJdPdZHw3qJXeDKhtIX7rPnAeZb_0bUZlwJCyoa7qjyzkEEGCiSyNh_ge9znS9eLbbhRYxQm42D6XbVWzgGR4NW-3Ylwaz6Fzm0JklGR1n_Z-7bB7tPlq91jdVFJ9mqik_0noAuOdDIqPLKIjES9_gS8KHDnG850sn6s45RglVloq6UwRY7eRMRs22WjOJ4qaR3-hESNqas3S5Une8pEcV5l-uN7DaQwXjEl8Eyy8yAwMdPvAKdIf4LYAZslCCE9yGNh5CZuziX0R67ZA6tYE16aNUMnUW2I-5dGl3lvlb-ZuaFHFRFxgv-Lg83uJy9cj_82xhFpGziImZaRHIU0MdllFoIN5jn4mDgz5AWw6y-inQA56HE7qLl58s7CCa4LFfFKwwATKfKe9rFCc8trWu7obwA_VD3AXscBE2elOfQO2L-4qLGU3aTg4sD1aSVtAbvaEXMGh1msRJR3-oDBXS3x_onA_MSQqN9jVX3AH06owZgfY1NzpepKPRPTYvGIR1UjhGuwzRqhPGHPXsW8QqgMMxAw6tOKQ5uEY5VIfX1K9O8Wobo9WvzIlrh8EDXc4Ns6bYK2PmFqo7KUBcObXKSJaSULGyusE_WWCzu4MIeFRkLfxrGvyltATVbPJw64YDYI2YQTDIvWB9rmUgaYieOHS7DFChqK49fZa1TQPHOJcuPNxZig9EC8Wzz83HjQRHC9K5Dn_0kxS_KaTLpBfkxyvux3n171mPCZJgaJaIthdCIiOMS10j-rHaVndSr4UhDckQYy88vMzGx8Eo64zgTsSA4d3FN_x84pWFoh7EN8rXniT_0kw0t1e6lGTzRPDpO-NijZNFMXKDDMTnO6EziGaRpbEKXTwHrgAxi1CMo_-fB_-TT_f1I3rA1Q1cFESICasYDvV3fDO_qOGY-mgyxcsrxhBJOidn_PSjYV8MBSUADrdzXL9VEn5FNt88cky9OBlYUqTNVFaXEf7Uaqnba1fTNF2fRVtp9gr4kk3ZlyeAWDO6Npqqr-mEYxmULfAVak6Vfv4waT-QS4mQs0wsOYgFAzavBqkePGXdZgTyFiGjobnlEVifV4XUVz0pNKiG5FaVXu0kHdqmPxK4jBI3UZjBptuwTwNUeYYSmddKsSYWaaI2C4i4av83fFBnBfLynfma5y0XaG_f1ow_G4X0PUt-hGq6BtFXbivpAAfEk79qrNVX3jgUH6t482ueL4ZPMePJ5mr4zH8e7RizyKzBEAg_Xx_ml5wbyf3fiLPiiCcRRF3GIYQ8-pL6foKfqAKliZgpkdR9hSKx7SHG1QWK4SLrTOe9PsI_xk1gkjbRj0HrP1UINWhXyWheHYfkBj4UcTe3Tbeocae6P8Mwsgw-TCWlBBBo0jZeRYwSFl9tAKt2ZB0iWu0bbdPH2C0IQJ32skrWrX_ppSxGiFMk9rP-jytP44Axlzd4inayKncv-_CTqiDxHvQOs_-SqCYFeUsIA3VR80CSMvyIDwjp4TkpVC3dAJJejEN9Bqm4fJnIRIoXHeAYExJVR_IhrJGd_2akTfC8lSSzPN2FCWswsr7gtxO8L4XBiSA1fqpKjJFXIOVauYp-btNzC4kMG88101WKjwLHQHWUxnFWMcVm5Vk1QSFkadP3b8v2GsALvBcoBK1TaZCrd7xegBYCeJ-UqpWRZieurGPTl2BKKrR_S0wwg-KmWBJdo3fPZ-6R4vHwusTRYlEUbZMtJp6Axm1gYTgxTOp80v6KxWeQS7CRTrrBLBSBRD9sg6VFdWlL7tc0g3qh4qXe70JTqpmJTNpXaLFVfAlHLzsOcA6wz7ha0RQoSsrp8VqoiS7d4DGbhL_1a-pC4H2tU7jdMMIqcD7Hf_mjr87agcqVHE81_-YtxtDAvN9GcSTpTnrQU5UXjLZFA0xE8ONQvFg6oCm1nYfnDS7eIHnGqUFqxQIXOWT-Yaet2vyepb08DWr7k1dOEWPTwSgbUTLDy6w0vc_9GxVaMJTH9ps09e36M-04gq5jzP5I2_aC3Ndf8nnFEBQ101oivTEYf9WoCvOOVvwTNsyTft8tc2hhNwvP1QVzXNuMZsbj7n91WEC2odID8Gqw3VMNmOFmf6XCHDY1OZkZl87dRJ1_P4bybPw0TucLQklJ634DXIwD4--BTfveifHBEDyQVjJS3Tl32OpWJYDyXlTNYjLb_WEsarb9RmaKG7lksPZyOHSRauBpVgBw82Ix5v32aeoXotaPIFZQC58unzZInbKyHzIt5qfNzSEYP29_63oRIl6ACY.kJK74b1pPOLcuYpIDK4mOQ'
Figure A.62
Extract the header information. This info is not further used.
import json
from jwcrypto.common import base64url_decode
parts = encdata.split('.')
jsondata = base64url_decode(parts[0])
data = json.loads(jsondata)
data
Figure A.63
{'alg': 'RSA-OAEP', 'cty': 'application/geo+json', 'enc': 'A128GCM', 'kid': 'clikid'}
Figure A.64
A.5.2. Decode the payload
Use as `dek’ the private key of the client key pair used for encryption/decryption (ce_key)
# private key needed to decrypt the content
dek_str = ce_key.export(private_key=True, as_dict=False)
dek = jwk.JWK.from_json(dek_str)
dek.export()
Figure A.65
'{"d":"C15sP_l9yqYvvO-kyeIPMFHHeifHUaNwKg3ko2pcBdoUUGtbD8Fqcn7XXcFaW8HSkdoHp6ta1oKDj3JMxXFefQlLtYKg5Z0jqvEnp6XLnGiqEzj6ulCkoqfkKYYAHmtvhDedkgG8dQQHOMPRsOKjz2g3kHaCbttoswKcSq3rQHd7D_VxEGKZWQa2---cK1YmZBa_w-aNZ8-E15awJz7nIFn0c0COKUERmoF2tscN1_0r1JYN7UxUkEA3sXoyj0dmDK5sMlbmmBeUTSeuvA885C5m3GwIeI1ZElCvVjDd9AMGTSGK1QMydyzUs7F3LJI9942Mxw1iKlXFxsbkjVqn8Q","dp":"Yj83etJoO1KW8V8i23ml0SGb7kk0vtCuGRcN9nl5rQB5HIiI4c9zX-GD4eXAM-24RqIlTOBX6XmP5l91IOw9QAbHtelLcWGAfTtOQkPAY7v3TlZJNYacQDUUMbdn-Jd_85wh9VOpw8eyvhzyjCzniNz8buUKPbVOOjkI2X8FG8c","dq":"2N608ZQpomUpjVbI78NUeSrraz6pTOU70sB9xNjMFYqb_wuo3TaW319PpWtKm5F_lHfjgEvK644FlaU1TJmkAbwOoZuRG2ve4tMcdx2A_e-GAoZMhCi98QTd0gJsg8O9gLbujLa4a421Oes1rTBlogGrD_6UFRzdzPJm_3e9F9U","e":"AQAB","kid":"clikid","kty":"RSA","n":"rLItABpzNyhZDBFhi1kRX1PdlMVeT1d_Tik4bFwOcW7foc1R4O-oswjMGrhgSRDAj-n4B_anrQ6Z0hzr58aC0yEI_ueNzdnpOECFoA5vHPjunqHv9gqqa1vIQq4GDbEsjYA5iJ828UQVpTrdY7RUC-qT9B0Ib4TW2HcCvBuxrOh4kiswLFrfEtS2QJcYh4tScMFzZdIY985s2sDTf0qxdU7c4h84J_y292mfce-0egMzamnYOGOZfcoGXCtDC-pB6TbWGWtLAhfpkwRc1qiQUqcMru8X896eIIYjUjQdKnVc5nfwa0cUy8KlC29m0zAVQwuzUJHsnZuuCgqXyGj6xQ","p":"t-BuJNDnlmUnPIax1K4msbDGJj5TAZjLMWC4riq13YYOyidizp5QuGIbu43hUmJUtGrabEi0JlkoOwHvBvolNq1dZlIyem62ezawGQvxdmZjG0X7ewfx9Go2mjWwEH045Je5TR5Aoy-xFigVECj3nOZEtJX-zndpvw-HTbvtRpc","q":"8G8P6XNxL_gnFx5H5jVAEbxObZu0jwrj6VxkQDm49BFdH8JdxTAYn6urhYIeJ0mtaj65eO8HfTgwugVLzWERrMQOpQplhcbl2JmczcyjrXGBVGewJ3LdnScilFVS9UUULIm127t1vfD8HAeV4mM3zCIujXrKZPEtCZ-eGf7b8QM","qi":"McWFm-FqXLIwI7t8Q8okkLc8K6IkVk94XwCjO9SrZydrEnDbOgpj8CHcElkdALTCtt-j7bCKPwdMb9Iis0TkjnUavQz_WNSyaS1HUE394DjYawb1lz042PbczfQTGkoA6mmT-ScOb8tTOn01mUJ1qEj-J-HkLvqrMy3r9YryZCs","use":"enc"}'
Figure A.66
# Decrypt the payload with the dek (private key of the client)
jwe_token = jwe.JWE()
jwe_token.deserialize(encdata)
jwe_token.decrypt(dek)
decrypted_payload = jwe_token.payload
data = json.loads(decrypted_payload)
jstr = json.dumps(data, indent=3)
md("```json\n" + jstr + "\n```\n")
# jwe_token.header
Figure A.67
{
"id": "PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001",
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
2.83,
51.18
],
[
2.83,
51.28
],
[
3.02,
51.28
],
[
3.02,
51.18
],
[
2.83,
51.18
]
]
]
},
"properties": {
"externalId": "PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001",
"datetime": "2022-06-30T14:16:24",
"start_datetime": "2022-03-07T14:02:00Z",
"end_datetime": "2022-03-07T14:06:00Z",
"recordUpdated": "2022-07-21T22:40:13Z",
"type": "dataset",
"created": "2019-05-22",
"updated": "2022-06-30T14:16:24",
"title": "Proba CHRIS Level 1A",
"description": "CHRIS acquires a set of up to five images of each target during\n each acquisition sequence, these images are acquired when Proba-1 is pointing at\n distinct angles with respect to the target. CHRIS Level 1A products (supplied in\n HDF data files, version 4.1r3) include five formal CHRIS imaging modes,\n classified as modes 1 to 5: \u2022 MODE 1: Full swath width, 62 spectral bands, 773nm\n / 1036nm, nadir ground sampling distance 34m @ 556km \u2022 MODE 2 WATER BANDS: Full\n swath width, 18 spectral bands, nadir ground sampling distance 17m @ 556km \u2022\n MODE 3 LAND CHANNELS: Full swath width, 18 spectral bands, nadir ground sampling\n distance 17m @ 556km \u2022 MODE 4 CHLOROPHYL BAND SET: Full swath width, 18 spectral\n bands, nadir ground sampling distance 17m @ 556km \u2022 MODE 5 LAND CHANNELS: Half\n swath width, 37 spectral bands, nadir ground sampling distance 17m @ 556km All\n Proba-1 passes are systematically acquired according to the current acquisition\n plan, CHRIS data are processed every day to Level 1A and made available to ESA\n users. Observation over a new specific area can be performed by submitting the\n request to add a new site to the acquisition plan.",
"associations": [
{
"href": "https://tpm-ds.eo.esa.int/oads/data/PROBA1-CHRIS/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP",
"name": "Download",
"description": null,
"type": "WWW:DOWNLOAD",
"rel": "WWW:DOWNLOAD"
},
{
"href": "http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/browse/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP_BID.PNG",
"name": "QUICKLOOK",
"description": null,
"type": null,
"rel": null
},
{
"href": "http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/thumbnail/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP_TIMG.jpg",
"name": "THUMBNAIL",
"description": null,
"type": null,
"rel": null
}
],
"extent": {
"spatial": {
"bbox": [
[
2.83,
51.18,
3.02,
51.28
]
],
"crs": "http://www.opengis.net/def/crs/OGC/1.3/CRS84"
}
}
},
"links": [
{
"rel": "alternate",
"type": "application/dcs+geo",
"title": "This document as DCS + GeoJSON",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?public_key=kty%2CRSA%2Cuse%2Cenc%2Ckid%2Cclikid%2Cn%2CrLItABpzNyhZDBFhi1kRX1PdlMVeT1d_Tik4bFwOcW7foc1R4O-oswjMGrhgSRDAj-n4B_anrQ6Z0hzr58aC0yEI_ueNzdnpOECFoA5vHPjunqHv9gqqa1vIQq4GDbEsjYA5iJ828UQVpTrdY7RUC-qT9B0Ib4TW2HcCvBuxrOh4kiswLFrfEtS2QJcYh4tScMFzZdIY985s2sDTf0qxdU7c4h84J_y292mfce-0egMzamnYOGOZfcoGXCtDC-pB6TbWGWtLAhfpkwRc1qiQUqcMru8X896eIIYjUjQdKnVc5nfwa0cUy8KlC29m0zAVQwuzUJHsnZuuCgqXyGj6xQ%2Ce%2CAQAB&f=dcs+geo",
"hreflang": "en-US"
},
{
"rel": "self",
"type": "application/jose",
"title": "This document as JOSE + GeoJSON",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?public_key=kty%2CRSA%2Cuse%2Cenc%2Ckid%2Cclikid%2Cn%2CrLItABpzNyhZDBFhi1kRX1PdlMVeT1d_Tik4bFwOcW7foc1R4O-oswjMGrhgSRDAj-n4B_anrQ6Z0hzr58aC0yEI_ueNzdnpOECFoA5vHPjunqHv9gqqa1vIQq4GDbEsjYA5iJ828UQVpTrdY7RUC-qT9B0Ib4TW2HcCvBuxrOh4kiswLFrfEtS2QJcYh4tScMFzZdIY985s2sDTf0qxdU7c4h84J_y292mfce-0egMzamnYOGOZfcoGXCtDC-pB6TbWGWtLAhfpkwRc1qiQUqcMru8X896eIIYjUjQdKnVc5nfwa0cUy8KlC29m0zAVQwuzUJHsnZuuCgqXyGj6xQ%2Ce%2CAQAB&f=jose",
"hreflang": "en-US"
},
{
"rel": "alternate",
"type": "application/jose;profile=jws",
"title": "This document as JWS",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?public_key=kty%2CRSA%2Cuse%2Cenc%2Ckid%2Cclikid%2Cn%2CrLItABpzNyhZDBFhi1kRX1PdlMVeT1d_Tik4bFwOcW7foc1R4O-oswjMGrhgSRDAj-n4B_anrQ6Z0hzr58aC0yEI_ueNzdnpOECFoA5vHPjunqHv9gqqa1vIQq4GDbEsjYA5iJ828UQVpTrdY7RUC-qT9B0Ib4TW2HcCvBuxrOh4kiswLFrfEtS2QJcYh4tScMFzZdIY985s2sDTf0qxdU7c4h84J_y292mfce-0egMzamnYOGOZfcoGXCtDC-pB6TbWGWtLAhfpkwRc1qiQUqcMru8X896eIIYjUjQdKnVc5nfwa0cUy8KlC29m0zAVQwuzUJHsnZuuCgqXyGj6xQ%2Ce%2CAQAB&f=jws",
"hreflang": "en-US"
},
{
"rel": "alternate",
"type": "application/geo+json",
"title": "This document as GeoJSON",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?public_key=kty%2CRSA%2Cuse%2Cenc%2Ckid%2Cclikid%2Cn%2CrLItABpzNyhZDBFhi1kRX1PdlMVeT1d_Tik4bFwOcW7foc1R4O-oswjMGrhgSRDAj-n4B_anrQ6Z0hzr58aC0yEI_ueNzdnpOECFoA5vHPjunqHv9gqqa1vIQq4GDbEsjYA5iJ828UQVpTrdY7RUC-qT9B0Ib4TW2HcCvBuxrOh4kiswLFrfEtS2QJcYh4tScMFzZdIY985s2sDTf0qxdU7c4h84J_y292mfce-0egMzamnYOGOZfcoGXCtDC-pB6TbWGWtLAhfpkwRc1qiQUqcMru8X896eIIYjUjQdKnVc5nfwa0cUy8KlC29m0zAVQwuzUJHsnZuuCgqXyGj6xQ%2Ce%2CAQAB&f=json",
"hreflang": "en-US"
},
{
"rel": "alternate",
"type": "text/html",
"title": "This document as HTML",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?public_key=kty%2CRSA%2Cuse%2Cenc%2Ckid%2Cclikid%2Cn%2CrLItABpzNyhZDBFhi1kRX1PdlMVeT1d_Tik4bFwOcW7foc1R4O-oswjMGrhgSRDAj-n4B_anrQ6Z0hzr58aC0yEI_ueNzdnpOECFoA5vHPjunqHv9gqqa1vIQq4GDbEsjYA5iJ828UQVpTrdY7RUC-qT9B0Ib4TW2HcCvBuxrOh4kiswLFrfEtS2QJcYh4tScMFzZdIY985s2sDTf0qxdU7c4h84J_y292mfce-0egMzamnYOGOZfcoGXCtDC-pB6TbWGWtLAhfpkwRc1qiQUqcMru8X896eIIYjUjQdKnVc5nfwa0cUy8KlC29m0zAVQwuzUJHsnZuuCgqXyGj6xQ%2Ce%2CAQAB&f=html",
"hreflang": "en-US"
},
{
"rel": "collection",
"type": "application/json",
"title": "Collection URL",
"href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main",
"hreflang": "en-US"
}
],
"assets": {}
}
Figure A.68
A.6. D113 POST /items without DCS
Example: 3.3
> Insert records to OGC API-Records D113 /items without DCS
# Get an ISO19139 (dataset) record from FedEO (EOVOC) to insert in the OGC API-Records server.
response = requests.get('https://eovoc.spacebel.be/collections/datasets/items/KO2_OTPF_KO2_MSC_2F_20091107T041750_20091107T041750_017498_E082_N028?httpAccept=application/vnd.iso.19139%2Bxml', verify=True,
headers={'Accept': 'application/xml'})
# xmlstr = minidom.parseString(response.text).toprettyxml(indent=' ',newl='')
# md("```xml\n" + xmlstr + "\n```\n")
response = requests.post(endpoint_items, data = response.text,
verify=bool(verify_ssl),
headers={'Accept': 'application/json', 'Content-Type': 'application/xml', 'Authorization': 'Bearer ' + access_token})
response.headers
Figure A.69
{'Server': 'nginx/1.23.1', 'Date': 'Fri, 21 Oct 2022 15:25:49 GMT', 'Content-Type': 'application/json', 'Content-Length': '2', 'Connection': 'keep-alive', 'Host': 'ogc.demo.secure-dimensions.de', 'User-Agent': 'python-requests/2.26.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': 'application/json', 'Authorization': 'Bearer 4e6e701e0eb6a7d13e76b33da136fa07a2c4d7fc', 'Location': 'https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/KO2_OTPF_KO2_MSC_2F_20091107T041750_20091107T041750_017498_E082_N028'}
Figure A.70
# Get an ISO19139 (service) record from FedEO (EOVOC) to insert in the OGC API-Records server.
response = requests.get('https://eovoc.spacebel.be/collections/services/items/eo-pdgs-landsat-datacube?httpAccept=application/vnd.iso.19139%2Bxml', verify=True,
headers={'Accept': 'application/xml'})
# xmlstr = minidom.parseString(response.text).toprettyxml(indent=' ',newl='')
# md("```xml\n" + xmlstr + "\n```\n")
response = requests.post(endpoint_items, data = response.text,
verify=bool(verify_ssl),
headers={'Accept': 'application/json', 'Content-Type': 'application/xml', 'Authorization': 'Bearer ' + access_token})
response.headers
Figure A.71
{'Server': 'nginx/1.23.1', 'Date': 'Fri, 21 Oct 2022 15:25:49 GMT', 'Content-Type': 'application/json', 'Content-Length': '2', 'Connection': 'keep-alive', 'Host': 'ogc.demo.secure-dimensions.de', 'User-Agent': 'python-requests/2.26.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': 'application/json', 'Authorization': 'Bearer 4e6e701e0eb6a7d13e76b33da136fa07a2c4d7fc', 'Location': 'https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/eo-pdgs-landsat-datacube'}
Figure A.72
# Delete the record that was just inserted. 204 response means deletion was successful.
response = requests.delete(endpoint_items + '/KO2_OTPF_KO2_MSC_2F_20091107T041750_20091107T041750_017498_E082_N028',
verify=bool(verify_ssl),
headers={'Accept': 'application/json', 'Authorization': 'Bearer ' + access_token})
response
Figure A.73
<Response [405]>
Figure A.74
A.7. D113 POST /items with DCS (JOSE)
Example: 3.4
> Insert records to OGC API-Records D113 /items with DCS
(application/jose) and public key.
As a first step, obtain the public key of the Catalog via https://ogc.demo.secure-dimensions.de/.well-known/jwks.json.
# Get the keyset published by the catalogue server from its well-known location.
response = requests.get('https://ogc.demo.secure-dimensions.de/.well-known/jwks.json', verify=True,
headers={'Accept': 'application/json'})
response.text
Figure A.75
'{"keys":[{"kid":"catalog-sign-key","kty":"RSA","n":"loOcM6QC6jUB6wnMM7S5px2OPkLbuycsA6qqJoFWPkXyFFx5Z6CJNOc-7li4WBprIAX65Sh6aOq3bBZ8FP3v7R7mZOo7e5fckvMTPOAzizkjXQuN8ZZoQta6xu9ryZoTkD2bOK11buLcc_ZtZt3pRBkgA_ZHZ7LJawhnkMGq_hpSMmDxkDoUHsJ5PLH1yATPhquQwdUWajUZJMs4S7Ns0LgCDoj0zeixq5K6lip4Mh6hSoRep8aB4UwshdV2VUbpBP-Tq6MF_DzjeOEgIlEnILu2E6JN83Dz_sjDEdrC5qNjEDLMnLJTzsrnOcdD3FrXiDTolXjmEjnq-mAfjL3IvQ","e":"AQAB","use":"sig"},{"kid":"catalog-wrap-key","kty":"RSA","n":"utfDC-oXhPJVBn2KY-Lus_H6zn_lx5K6UNHySSXaAeu1cI1Q5UM782pvWI1iSxrq0s6a1a2faGocfR5XP7hugmQaQaTRHVTRL7L1cvu4oCLDm5DzI0CN_um6BH2zUW_MUBqpJuumgHEH17sMumg4jeH7x3oeW0xM7g-NzaCiQF5IEDMVHC9HGytpJcmCAev0vHR80oe7hSncJwbaa_Gryh3tH6YPcml-seGCJHPrLBIMVeTaSr-65gV050VZs2vF4W0bq_1AdObq1L1FISkHsayay0kleC4hq09uY5WqDkAHIIAxsj2R-weAE3M2UunIyKLFdXghnktlb9UKJavi_Q","e":"AQAB","use":"enc","key_ops":"wrapKey"},{"kid":"893ef3c8-c249-47a2-91e2-001a0b201647","kty":"RSA","n":"nhM1yyeJzcopJo79Cy_0jYbdhOL7XNzuYb2zi3HyTeQaNKwAzvt1c1MNMlm3Mt39kcB_mw5ehBZS1UZXGDWGV2BH5WZhyvTufxONizUlb65M5NHRMIKbmeDEYgyegKke6aaNaOl4QfSI6sd7JH6Zq_RtFBb85evfm74poRuV_JnS7u8j-kKrXUTgHNhwxHa8xuyz19o8506uWdDrYta53NYiuWdZ_So2Mzi3eK26o8rO3IX9Wk6nIWTYKmYetwYps0KOi7Q8hiH1RknrLvnNFT-z7eK2SZ3jycZCbDmD15KAasm5HQAlP3tOWJvq9_w3HiZakHZlNDwGbgCT1l_1pQ","e":"AQAB"}]}'
Figure A.76
import jwt
from jwcrypto import jwk, jwe
# Get the keyset from the catalog server (receiver)
server_keyset = jwk.JWKSet.from_json(response.text)
server_keyset
Figure A.77
{"keys":["{\"kid\":\"catalog-wrap-key\",\"thumbprint\":\"cqHuddqPaJd1vpyf7HBee_qR98eabtEIvpuFgnQlO4s\"}","{\"kid\":\"catalog-sign-key\",\"thumbprint\":\"uwatboW3aEXg3z0g1Ci6jyQzze5ZbpvYC_ahbTnwXs8\"}","{\"kid\":\"893ef3c8-c249-47a2-91e2-001a0b201647\",\"thumbprint\":\"ygIxjy7LMfiUVhDwEX_esDpGK8dsw3SnJgkF8yT4B6M\"}"]}
Figure A.78
se_key_kid = 'catalog-wrap-key'
# Get the keypair for encryption by the catalog from the keyset via its 'kid' as there may be multiple.
se_key = server_keyset.get_key(kid=se_key_kid)
# From the pair, get the public key.
se_key.export(private_key=False, as_dict=True)
Figure A.79
{'kty': 'RSA', 'use': 'enc', 'key_ops': 'wrapKey', 'kid': 'catalog-wrap-key', 'n': 'utfDC-oXhPJVBn2KY-Lus_H6zn_lx5K6UNHySSXaAeu1cI1Q5UM782pvWI1iSxrq0s6a1a2faGocfR5XP7hugmQaQaTRHVTRL7L1cvu4oCLDm5DzI0CN_um6BH2zUW_MUBqpJuumgHEH17sMumg4jeH7x3oeW0xM7g-NzaCiQF5IEDMVHC9HGytpJcmCAev0vHR80oe7hSncJwbaa_Gryh3tH6YPcml-seGCJHPrLBIMVeTaSr-65gV050VZs2vF4W0bq_1AdObq1L1FISkHsayay0kleC4hq09uY5WqDkAHIIAxsj2R-weAE3M2UunIyKLFdXghnktlb9UKJavi_Q', 'e': 'AQAB'}
Figure A.80
# Get an ISO19139 (dataset) record from FedEO (EOVOC) to insert in the OGC API-Records server.
# You can use any /datasets/items URL available on EOVOC, for example found via the STAC Browser at https://stacindex.org/catalogs/fedeo-clearinghouse#/.
# response = requests.get('https://eovoc.spacebel.be/collections/datasets/items/ASA_APS_1PNESA20021115_100404_000000152011_00151_03712_0000?httpAccept=application/vnd.iso.19139%2Bxml', verify=True,
# headers={'Accept': 'application/xml'})
# response = requests.get('https://eovoc.spacebel.be/collections/datasets/items/ASA_IMP_1PNESA20030910_100809_000000152019_00423_07992_0000?httpAccept=application/vnd.iso.19139%2Bxml', verify=True,
# headers={'Accept': 'application/xml'})
response = requests.get('https://eovoc.spacebel.be/collections/datasets/items/SP4_OPER_HRI__I__2A_20030714T104451_20030714T104500_000213_0042_0246?httpAccept=application/vnd.iso.19139%2Bxml', verify=True,
headers={'Accept': 'application/xml'})
payload = response.text
# 'cty' tells receiver what content-type to expect after decryption (i.e. the type of the secured content). "application/" is left out of the media type.
# 'kid' key hint references the public key to which the JWE was encrypted; this can be used to determine the private key needed to decrypt the JWE.
# See https://www.rfc-editor.org/rfc/rfc7516.txt
#
protected_header = {'alg': 'RSA-OAEP',
'cty': 'xml',
'enc': 'A128GCM',
'kid': se_key_kid }
# Encrypt the payload with the dek (public key of the server)
jwe_token = jwe.JWE(plaintext = payload.encode('utf-8'), recipient = se_key, protected = protected_header )
enc = jwe_token.serialize(compact=True)
Figure A.81
# Insert the metadata record (JOSE) in the catalog with 'POST'.
response = requests.post(endpoint_items, data = enc,
verify=bool(verify_ssl),
headers={'Accept': 'application/json', 'Content-Type': 'application/jose', 'Authorization': 'Bearer ' + access_token})
response
Figure A.82
<Response [201]>
Figure A.83
response.headers['Location']
Figure A.84
'https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/SP4_OPER_HRI__I__2A_20030714T104451_20030714T104500_000213_0042_0246'
Figure A.85
Retrieve the metadata record that was inserted from the OGC API-Records catalog.
# extract location of new image from HTTP header
url_location = endpoint_api_records + response.headers['Location']
# get it unencrypted.
response = requests.get(url_location, verify=bool(verify_ssl), headers={'Accept': 'application/geo+json'})
data = json.loads(response.text)
show_on_map(data)
Figure A.86
Make this Notebook Trusted to load map: File → Trust Notebook
A.8. D113 GET /items/{item-id} with DCS (JWS)
Example: 3.5
> Access the OGC API-Records D113 /items/{item-id} to get a signed
response (JWS format). The signature is used to verify the integrity of
the response. The media type and value of the ``f'’ parameter are
subject to change but allow to demonstrate the response format. The
response is returned in clear (part 2 of the JWS token).
response = requests.get(endpoint_item + '?f=jws',
verify=bool(verify_ssl),
headers={'Accept': 'application/jose;profile=jws'})
response
Figure A.87
<Response [200]>
Figure A.88
The JWS response consists of three parts separated by a ``.'’ as explained in https://medium.facilelogin.com/jwt-jws-and-jwe-for-not-so-dummies-b63310d201a3
encdata = response.text
parts = encdata.split('.')
Figure A.89
# JWS token part 1 contains information about the key to use for verifying the signature.
from jwcrypto.common import base64url_decode
header = base64url_decode(parts[0])
header
Figure A.90
b'{"alg":"RS256","cty":"geo+json","iss":"https://ogc.demo.secure-dimensions.de","jku":"https://ogc.demo.secure-dimensions.de/.well-known/jwks.json","jwk":{"alg":"RS256","e":"AQAB","kid":"catalog-sign-key","kty":"RSA","n":"loOcM6QC6jUB6wnMM7S5px2OPkLbuycsA6qqJoFWPkXyFFx5Z6CJNOc-7li4WBprIAX65Sh6aOq3bBZ8FP3v7R7mZOo7e5fckvMTPOAzizkjXQuN8ZZoQta6xu9ryZoTkD2bOK11buLcc_ZtZt3pRBkgA_ZHZ7LJawhnkMGq_hpSMmDxkDoUHsJ5PLH1yATPhquQwdUWajUZJMs4S7Ns0LgCDoj0zeixq5K6lip4Mh6hSoRep8aB4UwshdV2VUbpBP-Tq6MF_DzjeOEgIlEnILu2E6JN83Dz_sjDEdrC5qNjEDLMnLJTzsrnOcdD3FrXiDTolXjmEjnq-mAfjL3IvQ"},"kid":"catalog-sign-key","typ":"JWT"}'
Figure A.91
# The "jwk" property contains the public key to verify the signature
from jwcrypto import jwk
data = json.loads(header)
data
Figure A.92
{'alg': 'RS256', 'cty': 'geo+json', 'iss': 'https://ogc.demo.secure-dimensions.de', 'jku': 'https://ogc.demo.secure-dimensions.de/.well-known/jwks.json', 'jwk': {'alg': 'RS256', 'e': 'AQAB', 'kid': 'catalog-sign-key', 'kty': 'RSA', 'n': 'loOcM6QC6jUB6wnMM7S5px2OPkLbuycsA6qqJoFWPkXyFFx5Z6CJNOc-7li4WBprIAX65Sh6aOq3bBZ8FP3v7R7mZOo7e5fckvMTPOAzizkjXQuN8ZZoQta6xu9ryZoTkD2bOK11buLcc_ZtZt3pRBkgA_ZHZ7LJawhnkMGq_hpSMmDxkDoUHsJ5PLH1yATPhquQwdUWajUZJMs4S7Ns0LgCDoj0zeixq5K6lip4Mh6hSoRep8aB4UwshdV2VUbpBP-Tq6MF_DzjeOEgIlEnILu2E6JN83Dz_sjDEdrC5qNjEDLMnLJTzsrnOcdD3FrXiDTolXjmEjnq-mAfjL3IvQ'}, 'kid': 'catalog-sign-key', 'typ': 'JWT'}
Figure A.93
# extract the embedded public key needed to verify the signature
key = jwk.JWK.from_json(json.dumps(data['jwk']))
key
Figure A.94
{"kid":"catalog-sign-key","thumbprint":"uwatboW3aEXg3z0g1Ci6jyQzze5ZbpvYC_ahbTnwXs8"}
Figure A.95
# JWS token part 2 (the actual response)
from jwcrypto.common import base64url_decode
payload = base64url_decode(parts[1])
payload
Figure A.96
b'{"id": "PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001", "type": "Feature", "geometry": {"type": "Polygon", "coordinates": [[[2.83, 51.18], [2.83, 51.28], [3.02, 51.28], [3.02, 51.18], [2.83, 51.18]]]}, "properties": {"externalId": "PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001", "datetime": "2022-06-30T14:16:24", "start_datetime": "2022-03-07T14:02:00Z", "end_datetime": "2022-03-07T14:06:00Z", "recordUpdated": "2022-07-21T22:40:13Z", "type": "dataset", "created": "2019-05-22", "updated": "2022-06-30T14:16:24", "title": "Proba CHRIS Level 1A", "description": "CHRIS acquires a set of up to five images of each target during\\n each acquisition sequence, these images are acquired when Proba-1 is pointing at\\n distinct angles with respect to the target. CHRIS Level 1A products (supplied in\\n HDF data files, version 4.1r3) include five formal CHRIS imaging modes,\\n classified as modes 1 to 5: \\u2022 MODE 1: Full swath width, 62 spectral bands, 773nm\\n / 1036nm, nadir ground sampling distance 34m @ 556km \\u2022 MODE 2 WATER BANDS: Full\\n swath width, 18 spectral bands, nadir ground sampling distance 17m @ 556km \\u2022\\n MODE 3 LAND CHANNELS: Full swath width, 18 spectral bands, nadir ground sampling\\n distance 17m @ 556km \\u2022 MODE 4 CHLOROPHYL BAND SET: Full swath width, 18 spectral\\n bands, nadir ground sampling distance 17m @ 556km \\u2022 MODE 5 LAND CHANNELS: Half\\n swath width, 37 spectral bands, nadir ground sampling distance 17m @ 556km All\\n Proba-1 passes are systematically acquired according to the current acquisition\\n plan, CHRIS data are processed every day to Level 1A and made available to ESA\\n users. Observation over a new specific area can be performed by submitting the\\n request to add a new site to the acquisition plan.", "associations": [{"href": "https://tpm-ds.eo.esa.int/oads/data/PROBA1-CHRIS/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP", "name": "Download", "description": null, "type": "WWW:DOWNLOAD", "rel": "WWW:DOWNLOAD"}, {"href": "http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/browse/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP_BID.PNG", "name": "QUICKLOOK", "description": null, "type": null, "rel": null}, {"href": "http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/thumbnail/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP_TIMG.jpg", "name": "THUMBNAIL", "description": null, "type": null, "rel": null}], "extent": {"spatial": {"bbox": [[2.83, 51.18, 3.02, 51.28]], "crs": "http://www.opengis.net/def/crs/OGC/1.3/CRS84"}}}, "links": [{"rel": "alternate", "type": "application/dcs+geo", "title": "This document as DCS + GeoJSON", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=dcs+geo", "hreflang": "en-US"}, {"rel": "alternate", "type": "application/jose", "title": "This document as JOSE + GeoJSON", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=jose", "hreflang": "en-US"}, {"rel": "self", "type": "application/jose;profile=jws", "title": "This document as JWS", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=jws", "hreflang": "en-US"}, {"rel": "alternate", "type": "application/geo+json", "title": "This document as GeoJSON", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=json", "hreflang": "en-US"}, {"rel": "alternate", "type": "text/html", "title": "This document as HTML", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=html", "hreflang": "en-US"}, {"rel": "collection", "type": "application/json", "title": "Collection URL", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main", "hreflang": "en-US"}], "assets": {}}'
Figure A.97
# JWS token part 3
from jwcrypto.common import base64url_decode
signature = base64url_decode(parts[2])
signature
Figure A.98
b"Lhd\x03;\xad\x8f\xe5#\xbd\x90\x15\x96\x9c\xdav\xfe,\xffk\xdeID\x937r\xa6\xcfo\x83\xe4\x83\xdb\xda\x19\x11\x17a+\xdb.\xbe\x0fa%7\x9b\xce~\x1e,\x83t\xd0_\xad\x953;K\r\x93\xfd\xb6\xb5\xbdnd\xc4#6\xd8O\x0f\xc5\xca\xb0e;1\x1d\xc0\x11f\x05\xe6% yQ\x19W\xa8KN\xf6\x07\xd5sS\xac\xbf\x87l\xc8\x01\x0f\xc7ZZ~+\xca\xffp\xc5\\\x16\xde\xcc\x9c\x7f\xafQ\x9d0\xee\xa9:\x00\xa4F\x95lV\xfd\x06\xf7\x1f4\x90j?\x1d;\x82\x8a~\xa1\xf1\x02\xf1a4\x1a'\xc28K\x13`v\xd6I\xb23\x91LK9,\x98K\xc6\xf3\xd9x+\xae^\x9c\xa8\x12t\xf0W'|\xdf\xb5%\x89\xed\xdb\x13t\x0f\xb4m\x11*\xfd\x07\xfc\x82\xbc\xea\x96\xd2\x0eO,]\\,\xf7\xb6\x97\xe2\xcela\xb4\x08\xa2\x19qV\xfd\xed\xff'\xc6\x9d\x0e\x17\xb2%D\xceh\xed\xf4l\n\x8fL9x\xf5\x90\xf3w\xbd\x83\xae"
Figure A.99
Verify the signature and thus the integrity of the response with the key extracted from part 1 of the header. If an exception is raised, then the signature does not match.
from jwcrypto import jws
jwstoken = jws.JWS()
jwstoken.deserialize(raw_jws = response.text)
# Verify the signature with the key from the header
jwstoken.verify(key)
payload = jwstoken.payload
payload
Figure A.100
b'{"id": "PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001", "type": "Feature", "geometry": {"type": "Polygon", "coordinates": [[[2.83, 51.18], [2.83, 51.28], [3.02, 51.28], [3.02, 51.18], [2.83, 51.18]]]}, "properties": {"externalId": "PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001", "datetime": "2022-06-30T14:16:24", "start_datetime": "2022-03-07T14:02:00Z", "end_datetime": "2022-03-07T14:06:00Z", "recordUpdated": "2022-07-21T22:40:13Z", "type": "dataset", "created": "2019-05-22", "updated": "2022-06-30T14:16:24", "title": "Proba CHRIS Level 1A", "description": "CHRIS acquires a set of up to five images of each target during\\n each acquisition sequence, these images are acquired when Proba-1 is pointing at\\n distinct angles with respect to the target. CHRIS Level 1A products (supplied in\\n HDF data files, version 4.1r3) include five formal CHRIS imaging modes,\\n classified as modes 1 to 5: \\u2022 MODE 1: Full swath width, 62 spectral bands, 773nm\\n / 1036nm, nadir ground sampling distance 34m @ 556km \\u2022 MODE 2 WATER BANDS: Full\\n swath width, 18 spectral bands, nadir ground sampling distance 17m @ 556km \\u2022\\n MODE 3 LAND CHANNELS: Full swath width, 18 spectral bands, nadir ground sampling\\n distance 17m @ 556km \\u2022 MODE 4 CHLOROPHYL BAND SET: Full swath width, 18 spectral\\n bands, nadir ground sampling distance 17m @ 556km \\u2022 MODE 5 LAND CHANNELS: Half\\n swath width, 37 spectral bands, nadir ground sampling distance 17m @ 556km All\\n Proba-1 passes are systematically acquired according to the current acquisition\\n plan, CHRIS data are processed every day to Level 1A and made available to ESA\\n users. Observation over a new specific area can be performed by submitting the\\n request to add a new site to the acquisition plan.", "associations": [{"href": "https://tpm-ds.eo.esa.int/oads/data/PROBA1-CHRIS/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP", "name": "Download", "description": null, "type": "WWW:DOWNLOAD", "rel": "WWW:DOWNLOAD"}, {"href": "http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/browse/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP_BID.PNG", "name": "QUICKLOOK", "description": null, "type": null, "rel": null}, {"href": "http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/thumbnail/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP_TIMG.jpg", "name": "THUMBNAIL", "description": null, "type": null, "rel": null}], "extent": {"spatial": {"bbox": [[2.83, 51.18, 3.02, 51.28]], "crs": "http://www.opengis.net/def/crs/OGC/1.3/CRS84"}}}, "links": [{"rel": "alternate", "type": "application/dcs+geo", "title": "This document as DCS + GeoJSON", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=dcs+geo", "hreflang": "en-US"}, {"rel": "alternate", "type": "application/jose", "title": "This document as JOSE + GeoJSON", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=jose", "hreflang": "en-US"}, {"rel": "self", "type": "application/jose;profile=jws", "title": "This document as JWS", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=jws", "hreflang": "en-US"}, {"rel": "alternate", "type": "application/geo+json", "title": "This document as GeoJSON", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=json", "hreflang": "en-US"}, {"rel": "alternate", "type": "text/html", "title": "This document as HTML", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=html", "hreflang": "en-US"}, {"rel": "collection", "type": "application/json", "title": "Collection URL", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main", "hreflang": "en-US"}], "assets": {}}'
Figure A.101
Example: 3.6
> The signature is used to verify the integrity of the response,
however, the key is retrieved from the originator of the response
instead of using the included public key.
# Get the keyset published by the catalogue server from its well-known location.
response = requests.get('https://ogc.demo.secure-dimensions.de/.well-known/jwks.json', verify=True,
headers={'Accept': 'application/json'})
response.text
Figure A.102
'{"keys":[{"kid":"catalog-sign-key","kty":"RSA","n":"loOcM6QC6jUB6wnMM7S5px2OPkLbuycsA6qqJoFWPkXyFFx5Z6CJNOc-7li4WBprIAX65Sh6aOq3bBZ8FP3v7R7mZOo7e5fckvMTPOAzizkjXQuN8ZZoQta6xu9ryZoTkD2bOK11buLcc_ZtZt3pRBkgA_ZHZ7LJawhnkMGq_hpSMmDxkDoUHsJ5PLH1yATPhquQwdUWajUZJMs4S7Ns0LgCDoj0zeixq5K6lip4Mh6hSoRep8aB4UwshdV2VUbpBP-Tq6MF_DzjeOEgIlEnILu2E6JN83Dz_sjDEdrC5qNjEDLMnLJTzsrnOcdD3FrXiDTolXjmEjnq-mAfjL3IvQ","e":"AQAB","use":"sig"},{"kid":"catalog-wrap-key","kty":"RSA","n":"utfDC-oXhPJVBn2KY-Lus_H6zn_lx5K6UNHySSXaAeu1cI1Q5UM782pvWI1iSxrq0s6a1a2faGocfR5XP7hugmQaQaTRHVTRL7L1cvu4oCLDm5DzI0CN_um6BH2zUW_MUBqpJuumgHEH17sMumg4jeH7x3oeW0xM7g-NzaCiQF5IEDMVHC9HGytpJcmCAev0vHR80oe7hSncJwbaa_Gryh3tH6YPcml-seGCJHPrLBIMVeTaSr-65gV050VZs2vF4W0bq_1AdObq1L1FISkHsayay0kleC4hq09uY5WqDkAHIIAxsj2R-weAE3M2UunIyKLFdXghnktlb9UKJavi_Q","e":"AQAB","use":"enc","key_ops":"wrapKey"},{"kid":"893ef3c8-c249-47a2-91e2-001a0b201647","kty":"RSA","n":"nhM1yyeJzcopJo79Cy_0jYbdhOL7XNzuYb2zi3HyTeQaNKwAzvt1c1MNMlm3Mt39kcB_mw5ehBZS1UZXGDWGV2BH5WZhyvTufxONizUlb65M5NHRMIKbmeDEYgyegKke6aaNaOl4QfSI6sd7JH6Zq_RtFBb85evfm74poRuV_JnS7u8j-kKrXUTgHNhwxHa8xuyz19o8506uWdDrYta53NYiuWdZ_So2Mzi3eK26o8rO3IX9Wk6nIWTYKmYetwYps0KOi7Q8hiH1RknrLvnNFT-z7eK2SZ3jycZCbDmD15KAasm5HQAlP3tOWJvq9_w3HiZakHZlNDwGbgCT1l_1pQ","e":"AQAB"}]}'
Figure A.103
import jwt
from jwcrypto import jwk, jwe
# Get the keyset from the catalog server (receiver)
server_keyset = jwk.JWKSet.from_json(response.text)
server_keyset
Figure A.104
{"keys":["{\"kid\":\"catalog-wrap-key\",\"thumbprint\":\"cqHuddqPaJd1vpyf7HBee_qR98eabtEIvpuFgnQlO4s\"}","{\"kid\":\"catalog-sign-key\",\"thumbprint\":\"uwatboW3aEXg3z0g1Ci6jyQzze5ZbpvYC_ahbTnwXs8\"}","{\"kid\":\"893ef3c8-c249-47a2-91e2-001a0b201647\",\"thumbprint\":\"ygIxjy7LMfiUVhDwEX_esDpGK8dsw3SnJgkF8yT4B6M\"}"]}
Figure A.105
# JWS header contains the "kid" of the key to be used for signature check.
data['kid']
Figure A.106
'catalog-sign-key'
Figure A.107
# JWS header contains also the well-known URL we just used to retrieve the server's keys.
data['jku']
Figure A.108
'https://ogc.demo.secure-dimensions.de/.well-known/jwks.json'
Figure A.109
se_key_kid = data['kid']
# Get the keypair for encryption by the catalog from the keyset via its 'kid' as there may be multiple.
key = server_keyset.get_key(kid=se_key_kid)
# Display the public key.
key.export(private_key=False, as_dict=True)
Figure A.110
{'kty': 'RSA', 'use': 'sig', 'kid': 'catalog-sign-key', 'n': 'loOcM6QC6jUB6wnMM7S5px2OPkLbuycsA6qqJoFWPkXyFFx5Z6CJNOc-7li4WBprIAX65Sh6aOq3bBZ8FP3v7R7mZOo7e5fckvMTPOAzizkjXQuN8ZZoQta6xu9ryZoTkD2bOK11buLcc_ZtZt3pRBkgA_ZHZ7LJawhnkMGq_hpSMmDxkDoUHsJ5PLH1yATPhquQwdUWajUZJMs4S7Ns0LgCDoj0zeixq5K6lip4Mh6hSoRep8aB4UwshdV2VUbpBP-Tq6MF_DzjeOEgIlEnILu2E6JN83Dz_sjDEdrC5qNjEDLMnLJTzsrnOcdD3FrXiDTolXjmEjnq-mAfjL3IvQ', 'e': 'AQAB'}
Figure A.111
from jwcrypto import jws
# decrypt the same JWS with the key directly retrieved from the server.
jwstoken = jws.JWS()
jwstoken.deserialize(raw_jws = encdata)
# Verify the signature with the key obtained from the well§known URL at the server.
jwstoken.verify(key)
payload = jwstoken.payload
payload
Figure A.112
b'{"id": "PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001", "type": "Feature", "geometry": {"type": "Polygon", "coordinates": [[[2.83, 51.18], [2.83, 51.28], [3.02, 51.28], [3.02, 51.18], [2.83, 51.18]]]}, "properties": {"externalId": "PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001", "datetime": "2022-06-30T14:16:24", "start_datetime": "2022-03-07T14:02:00Z", "end_datetime": "2022-03-07T14:06:00Z", "recordUpdated": "2022-07-21T22:40:13Z", "type": "dataset", "created": "2019-05-22", "updated": "2022-06-30T14:16:24", "title": "Proba CHRIS Level 1A", "description": "CHRIS acquires a set of up to five images of each target during\\n each acquisition sequence, these images are acquired when Proba-1 is pointing at\\n distinct angles with respect to the target. CHRIS Level 1A products (supplied in\\n HDF data files, version 4.1r3) include five formal CHRIS imaging modes,\\n classified as modes 1 to 5: \\u2022 MODE 1: Full swath width, 62 spectral bands, 773nm\\n / 1036nm, nadir ground sampling distance 34m @ 556km \\u2022 MODE 2 WATER BANDS: Full\\n swath width, 18 spectral bands, nadir ground sampling distance 17m @ 556km \\u2022\\n MODE 3 LAND CHANNELS: Full swath width, 18 spectral bands, nadir ground sampling\\n distance 17m @ 556km \\u2022 MODE 4 CHLOROPHYL BAND SET: Full swath width, 18 spectral\\n bands, nadir ground sampling distance 17m @ 556km \\u2022 MODE 5 LAND CHANNELS: Half\\n swath width, 37 spectral bands, nadir ground sampling distance 17m @ 556km All\\n Proba-1 passes are systematically acquired according to the current acquisition\\n plan, CHRIS data are processed every day to Level 1A and made available to ESA\\n users. Observation over a new specific area can be performed by submitting the\\n request to add a new site to the acquisition plan.", "associations": [{"href": "https://tpm-ds.eo.esa.int/oads/data/PROBA1-CHRIS/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP", "name": "Download", "description": null, "type": "WWW:DOWNLOAD", "rel": "WWW:DOWNLOAD"}, {"href": "http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/browse/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP_BID.PNG", "name": "QUICKLOOK", "description": null, "type": null, "rel": null}, {"href": "http://tpm-ds.eo.esa.int/oads/meta/PROBA1-CHRIS/thumbnail/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001.SIP.ZIP_TIMG.jpg", "name": "THUMBNAIL", "description": null, "type": null, "rel": null}], "extent": {"spatial": {"bbox": [[2.83, 51.18, 3.02, 51.28]], "crs": "http://www.opengis.net/def/crs/OGC/1.3/CRS84"}}}, "links": [{"rel": "alternate", "type": "application/dcs+geo", "title": "This document as DCS + GeoJSON", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=dcs+geo", "hreflang": "en-US"}, {"rel": "alternate", "type": "application/jose", "title": "This document as JOSE + GeoJSON", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=jose", "hreflang": "en-US"}, {"rel": "self", "type": "application/jose;profile=jws", "title": "This document as JWS", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=jws", "hreflang": "en-US"}, {"rel": "alternate", "type": "application/geo+json", "title": "This document as GeoJSON", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=json", "hreflang": "en-US"}, {"rel": "alternate", "type": "text/html", "title": "This document as HTML", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items/PR1_OPER_CHR_MO1_1P_20220307T140200_N51-240_E002-920_0001?f=html", "hreflang": "en-US"}, {"rel": "collection", "type": "application/json", "title": "Collection URL", "href": "https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main", "hreflang": "en-US"}], "assets": {}}'
Figure A.113
A.9. Other signatures with DCS (JWS/CT)
Example: 3.7
> JWS/CT (Clear Text) signature creation: The signature is included in
the original JSON metadata record (payload). See
https://www.ietf.org/archive/id/draft-jordan-jws-ct-08.txt.
# Get a JSON metadata record (OGC 17-003r2) to be used for demonstrating the encoding.
response = requests.get('https://eovoc.spacebel.be/collections/datasets/items/ASA_APS_1PNESA20021115_100404_000000152011_00151_03712_0000?mode=owc', verify=True,
headers={'Accept': 'application/geo+json'})
datastr = response.text
data = json.loads(datastr)
Figure A.114
# create a key for signing (private+public).
srv_kid = "srvkid"
ss_key = jwk.JWK(generate='RSA', kid=srv_kid, use="sig")
ss_key
Figure A.115
{"kid":"srvkid","thumbprint":"PKZ9rKjdrxgH-RsxRzz0KgSvz1GvXf0j8sEbLSQdVI0"}
Figure A.116
import jwt
import jcs
from jwcrypto import jwk, jwe, jws
protected_header = {
'alg': 'RS256',
"kty": "RSA",
'cty': 'geo+json',
'kid': srv_kid }
# normalise the JSON to compute the JWS.
payload = str(jcs.canonicalize( data ))
jwstoken = jws.JWS(payload.encode('utf-8'))
jwstoken.add_signature(key = ss_key,
alg = None,
protected = protected_header)
Figure A.117
enc = jwstoken.serialize(compact = True)
Figure A.118
# Remove middle part of the token to create a JWS token without payload.
parts = enc.split('.')
jwsstr = parts[0] + ".." + parts[2]
jwsstr
Figure A.119
'eyJhbGciOiJSUzI1NiIsImN0eSI6Imdlbytqc29uIiwia2lkIjoic3J2a2lkIiwia3R5IjoiUlNBIn0..Jw0cFyewMQApaJZYpMjzqGxiDfKh19ICzWtw8tpfRE1lUv9yn4_51X2C8EZkic_9QQ16BNa9k4HYtj0r7RigFmdra6aYps9nHuv1ATm3g6e6hVTYP3bgHKfzvyA2NkngU1eu9NafDjq4BlPI73-G6U_YRIFeEVnYcFiBfgOSaRICIpTczqgBqgWEaZnEUXq5v4dGT6aZa8JNoMMaNvOcP8dsGk2-JLI3xkBhtcgHo7N1kQtC0x7hJ13b26BhS-F_6qlrNb3k62wRQx7fJj0YMpqrJuUUE0GFGKq2fCC76N_efn3XtLIuXPDTCOViFZf6LgUfRQV5-qATv7rygIGyJg'
Figure A.120
Create the JWS/CT
# add signature property to the original JSON object (data) and print result.
data['signature'] = jwsstr
jstr = json.dumps(data, indent=3)
md("```json\n" + jstr + "\n```\n")
Figure A.121
{
"bbox": [
5.8,
54.78,
7.85,
55.89
],
"geometry": {
"coordinates": [
[
[
6.17,
55.89
],
[
5.8,
55.01
],
[
7.45,
54.78
],
[
7.85,
55.66
]
]
],
"type": "Polygon"
},
"id": "https://eovoc.spacebel.be/collections/datasets/items/ASA_APS_1PNESA20021115_100404_000000152011_00151_03712_0000?mode=owc",
"type": "Feature",
"properties": {
"date": "2002-11-15T10:04:04.824Z/2002-11-15T10:04:19.914Z",
"identifier": "ASA_APS_1PNESA20021115_100404_000000152011_00151_03712_0000",
"kind": "http://purl.org/dc/dcmitype/Dataset",
"parentIdentifier": "ENVISAT.ASA.APS_1P",
"productInformation": {
"referenceSystemIdentifier": "epsg:4326",
"productType": "ASA_APS_1P",
"availabilityTime": "2002-11-15T10:04:19.914Z"
},
"links": {
"data": [
{
"href": "https://esar-ds.eo.esa.int/oads/data/ASA_APS_1P/ASA_APS_1PNESA20021115_100404_000000152011_00151_03712_0000.N1",
"type": "application/x-binary",
"title": "Download"
}
],
"previews": [
{
"href": "http://esar-ds.eo.esa.int/oads/meta/ASA_APS_1P/browse/ASA_APS_1PNESA20021115_100404_000000152011_00151_03712_0000.N1_BID.JPG",
"type": "image/jpeg",
"title": "QUICKLOOK"
},
{
"href": "http://esar-ds.eo.esa.int/oads/meta/ASA_APS_1P/thumbnail/ASA_APS_1PNESA20021115_100404_000000152011_00151_03712_0000.N1_TIMG.jpg",
"type": "image/jpeg",
"title": "THUMBNAIL"
}
],
"up": [
{
"href": "https://eovoc.spacebel.be/collections/series/items/ENVISAT.ASA.APS_1P?mode=owc",
"title": "OGC 17-084r1 metadata",
"type": "application/geo+json"
}
],
"alternates": [
{
"href": "https://eovoc.spacebel.be/collections/datasets/items/ASA_APS_1PNESA20021115_100404_000000152011_00151_03712_0000?httpAccept=application/atom%2Bxml",
"type": "application/atom+xml",
"title": "Atom format"
},
{
"href": "https://eovoc.spacebel.be/collections/datasets/items/ASA_APS_1PNESA20021115_100404_000000152011_00151_03712_0000?httpAccept=application/gml%2Bxml&recordSchema=om",
"type": "application/gml+xml;profile=\"http://www.opengis.net/spec/EOMPOM/1.1\"",
"title": "OGC 10-157r4 metadata"
},
{
"href": "https://eovoc.spacebel.be/collections/datasets/items/ASA_APS_1PNESA20021115_100404_000000152011_00151_03712_0000?httpAccept=application/gml%2Bxml&recordSchema=om10",
"type": "application/gml+xml;profile=\"http://www.opengis.net/spec/EOMPOM/1.0\"",
"title": "OGC 10-157r3 metadata"
},
{
"href": "https://eovoc.spacebel.be/collections/datasets/items/ASA_APS_1PNESA20021115_100404_000000152011_00151_03712_0000",
"type": "application/geo+json;profile=\"http://www.opengis.net/spec/ogcapi-features-1/1.0\"",
"title": "OGC 17-069r3 metadata"
},
{
"href": "https://eovoc.spacebel.be/collections/datasets/items/ASA_APS_1PNESA20021115_100404_000000152011_00151_03712_0000?httpAccept=application/geo%2Bjson;profile=https://stacspec.org",
"type": "application/geo+json;profile=\"https://stacspec.org\"",
"title": "STAC metadata"
},
{
"href": "https://eovoc.spacebel.be/collections/datasets/items/ASA_APS_1PNESA20021115_100404_000000152011_00151_03712_0000?httpAccept=application/vnd.iso.19139%2Bxml",
"type": "application/vnd.iso.19139+xml",
"title": "ISO 19139 metadata"
},
{
"href": "https://eovoc.spacebel.be/collections/datasets/items/ASA_APS_1PNESA20021115_100404_000000152011_00151_03712_0000?httpAccept=application/ld%2Bjson",
"type": "application/ld+json",
"title": "JSON-LD metadata"
},
{
"href": "https://eovoc.spacebel.be/collections/datasets/items/ASA_APS_1PNESA20021115_100404_000000152011_00151_03712_0000?httpAccept=application/ld%2Bjson;profile=https://schema.org",
"type": "application/ld+json;profile=\"https://schema.org\"",
"title": "JSON-LD (schema.org) metadata"
},
{
"href": "https://eovoc.spacebel.be/collections/datasets/items/ASA_APS_1PNESA20021115_100404_000000152011_00151_03712_0000?httpAccept=application/ld%2Bjson;profile=http://data.europa.eu/930/",
"type": "application/ld+json;profile=\"http://data.europa.eu/930/\"",
"title": "JSON-LD (GeoDCAT-AP) metadata"
},
{
"href": "https://eovoc.spacebel.be/collections/datasets/items/ASA_APS_1PNESA20021115_100404_000000152011_00151_03712_0000?httpAccept=application/rdf%2Bxml",
"type": "application/rdf+xml",
"title": "RDF/XML metadata"
},
{
"href": "https://eovoc.spacebel.be/collections/datasets/items/ASA_APS_1PNESA20021115_100404_000000152011_00151_03712_0000?httpAccept=application/rdf%2Bxml;profile=https://schema.org",
"type": "application/rdf+xml;profile=\"https://schema.org\"",
"title": "RDF/XML (schema.org) metadata"
},
{
"href": "https://eovoc.spacebel.be/collections/datasets/items/ASA_APS_1PNESA20021115_100404_000000152011_00151_03712_0000?httpAccept=application/rdf%2Bxml;profile=http://data.europa.eu/930/",
"type": "application/rdf+xml;profile=\"http://data.europa.eu/930/\"",
"title": "RDF/XML (GeoDCAT-AP) metadata"
},
{
"href": "https://eovoc.spacebel.be/collections/datasets/items/ASA_APS_1PNESA20021115_100404_000000152011_00151_03712_0000?httpAccept=text/turtle",
"type": "text/turtle",
"title": "Turtle metadata"
},
{
"href": "https://eovoc.spacebel.be/collections/datasets/items/ASA_APS_1PNESA20021115_100404_000000152011_00151_03712_0000?httpAccept=text/turtle;profile=https://schema.org",
"type": "text/turtle;profile=\"https://schema.org\"",
"title": "Turtle (schema.org) metadata"
},
{
"href": "https://eovoc.spacebel.be/collections/datasets/items/ASA_APS_1PNESA20021115_100404_000000152011_00151_03712_0000?httpAccept=text/turtle;profile=http://data.europa.eu/930/",
"type": "text/turtle;profile=\"http://data.europa.eu/930/\"",
"title": "Turtle (GeoDCAT-AP) metadata"
},
{
"href": "https://eovoc.spacebel.be/collections/datasets/items/ASA_APS_1PNESA20021115_100404_000000152011_00151_03712_0000?httpAccept=text/html",
"type": "text/html",
"title": "HTML"
}
]
},
"title": "ASA_APS_1PNESA20021115_100404_000000152011_00151_03712_0000",
"updated": "2022-07-08T16:51:53Z",
"acquisitionInformation": [
{
"acquisitionParameters": {
"polarisationMode": "D",
"acquisitionType": "NOMINAL",
"polarisationChannels": "VV, VH",
"swathIdentifier": "IS2",
"resolution": 30,
"endingDateTime": "2002-11-15T10:04:19.914Z",
"orbitNumber": 3712,
"operationalMode": "AP",
"beginningDateTime": "2002-11-15T10:04:04.824Z",
"wrsLongitudeGrid": "151",
"wrsLatitudeGrid": "2490",
"startTimeFromAscendingNode": 2079834,
"completionTimeFromAscendingNode": 2094924,
"orbitDirection": "DESCENDING"
},
"instrument": {
"instrumentShortName": "ASAR",
"sensorType": "RADAR"
},
"platform": {
"platformShortName": "Envisat"
}
}
],
"status": "ARCHIVED"
},
"signature": "eyJhbGciOiJSUzI1NiIsImN0eSI6Imdlbytqc29uIiwia2lkIjoic3J2a2lkIiwia3R5IjoiUlNBIn0..Jw0cFyewMQApaJZYpMjzqGxiDfKh19ICzWtw8tpfRE1lUv9yn4_51X2C8EZkic_9QQ16BNa9k4HYtj0r7RigFmdra6aYps9nHuv1ATm3g6e6hVTYP3bgHKfzvyA2NkngU1eu9NafDjq4BlPI73-G6U_YRIFeEVnYcFiBfgOSaRICIpTczqgBqgWEaZnEUXq5v4dGT6aZa8JNoMMaNvOcP8dsGk2-JLI3xkBhtcgHo7N1kQtC0x7hJ13b26BhS-F_6qlrNb3k62wRQx7fJj0YMpqrJuUUE0GFGKq2fCC76N_efn3XtLIuXPDTCOViFZf6LgUfRQV5-qATv7rygIGyJg"
}
Figure A.122
Example: 3.8
> JWS/CT (Clear Text) signature validation: The signature is included in
the original JSON metadata record (payload). See
https://www.ietf.org/archive/id/draft-jordan-jws-ct-08.txt.
# jstr is signed JSON metadata
data = json.loads(jstr)
# Fetch the Signature Property String containing the JWS token without a payload part.
sig = data['signature']
sig
Figure A.123
'eyJhbGciOiJSUzI1NiIsImN0eSI6Imdlbytqc29uIiwia2lkIjoic3J2a2lkIiwia3R5IjoiUlNBIn0..Jw0cFyewMQApaJZYpMjzqGxiDfKh19ICzWtw8tpfRE1lUv9yn4_51X2C8EZkic_9QQ16BNa9k4HYtj0r7RigFmdra6aYps9nHuv1ATm3g6e6hVTYP3bgHKfzvyA2NkngU1eu9NafDjq4BlPI73-G6U_YRIFeEVnYcFiBfgOSaRICIpTczqgBqgWEaZnEUXq5v4dGT6aZa8JNoMMaNvOcP8dsGk2-JLI3xkBhtcgHo7N1kQtC0x7hJ13b26BhS-F_6qlrNb3k62wRQx7fJj0YMpqrJuUUE0GFGKq2fCC76N_efn3XtLIuXPDTCOViFZf6LgUfRQV5-qATv7rygIGyJg'
Figure A.124
# Remove the Signature Property String
del data['signature']
# Canonicalize the Remaining JSON Object
payload = str(jcs.canonicalize( data ))
# Validate the JWS String (Annex F of JWS RFC7515)
jwstoken = jws.JWS(payload = None)
jwstoken.deserialize(raw_jws = sig)
try:
jwstoken.verify(key = ss_key.public(), detached_payload = payload)
print("JWS signature verification completed.")
except jws.InvalidJWSSignature:
print("JWS signature verification failed.")
Figure A.125
JWS signature verification completed.
Figure A.126
A.10. D112 (CSW) GetCapabilities without DCS
See information available at https://cat.csiss.gmu.edu/CSW_Client-Guide.pdf.
Example: 4.1
> Access the GMU CSW D112 (GetCapabilities) to retrieve supported
queryables.
csw_endpoint_items = endpoint_csw + "?SERVICE=CSW&REQUEST=GetCapabilities&VERSION=2.0.2§ions=OperationsMetadata"
response = requests.get(csw_endpoint_items,
verify=True,
headers={})
# Extract information about GetRecords from the response.
rt = ElementTree.fromstring(response.text)
r = rt.find("{http://www.opengis.net/ows}OperationsMetadata/{http://www.opengis.net/ows}Operation[@name='GetRecords']")
try:
xmltxt = ElementTree.tostring(r, encoding='unicode', method='xml')
except:
xmltxt= 'Not found.'
md("```xml\n" + xmltxt + "\n```\n")
Figure A.127
<ns0:Operation xmlns:ns0="http://www.opengis.net/ows" xmlns:ns1="http://www.w3.org/1999/xlink" name="GetRecords"><ns0:DCP><ns0:HTTP><ns0:Get ns1:type="simple" ns1:href="https://cat.csiss.gmu.edu/ows18" /><ns0:Post ns1:type="simple" ns1:href="https://cat.csiss.gmu.edu/ows18" /></ns0:HTTP></ns0:DCP><ns0:Parameter name="CONSTRAINTLANGUAGE"><ns0:Value>CQL_TEXT</ns0:Value><ns0:Value>FILTER</ns0:Value></ns0:Parameter><ns0:Parameter name="ElementSetName"><ns0:Value>brief</ns0:Value><ns0:Value>full</ns0:Value><ns0:Value>summary</ns0:Value></ns0:Parameter><ns0:Parameter name="outputFormat"><ns0:Value>application/json</ns0:Value><ns0:Value>application/xml</ns0:Value></ns0:Parameter><ns0:Parameter name="outputSchema"><ns0:Value>http://gcmd.gsfc.nasa.gov/Aboutus/xml/dif/</ns0:Value><ns0:Value>http://www.interlis.ch/INTERLIS2.3</ns0:Value><ns0:Value>http://www.isotc211.org/2005/gmd</ns0:Value><ns0:Value>http://www.opengis.net/cat/csw/2.0.2</ns0:Value><ns0:Value>http://www.opengis.net/cat/csw/csdgm</ns0:Value><ns0:Value>http://www.w3.org/2005/Atom</ns0:Value><ns0:Value>urn:oasis:names:tc:ebxml-regrep:xsd:rim:3.0</ns0:Value></ns0:Parameter><ns0:Parameter name="resultType"><ns0:Value>hits</ns0:Value><ns0:Value>results</ns0:Value><ns0:Value>validate</ns0:Value></ns0:Parameter><ns0:Parameter name="typeNames"><ns0:Value>csw:Record</ns0:Value><ns0:Value>gmd:MD_Metadata</ns0:Value><ns0:Value>rim:RegistryObject</ns0:Value></ns0:Parameter><ns0:Constraint name="AdditionalQueryables"><ns0:Value>apiso:AccessConstraints</ns0:Value><ns0:Value>apiso:Bands</ns0:Value><ns0:Value>apiso:Classification</ns0:Value><ns0:Value>apiso:CloudCover</ns0:Value><ns0:Value>apiso:ConditionApplyingToAccessAndUse</ns0:Value><ns0:Value>apiso:Contributor</ns0:Value><ns0:Value>apiso:Creator</ns0:Value><ns0:Value>apiso:Degree</ns0:Value><ns0:Value>apiso:Instrument</ns0:Value><ns0:Value>apiso:Lineage</ns0:Value><ns0:Value>apiso:OtherConstraints</ns0:Value><ns0:Value>apiso:Platform</ns0:Value><ns0:Value>apiso:Publisher</ns0:Value><ns0:Value>apiso:Relation</ns0:Value><ns0:Value>apiso:ResponsiblePartyRole</ns0:Value><ns0:Value>apiso:SensorType</ns0:Value><ns0:Value>apiso:SpecificationDate</ns0:Value><ns0:Value>apiso:SpecificationDateType</ns0:Value><ns0:Value>apiso:SpecificationTitle</ns0:Value></ns0:Constraint><ns0:Constraint name="SupportedDublinCoreQueryables"><ns0:Value>csw:AnyText</ns0:Value><ns0:Value>dc:contributor</ns0:Value><ns0:Value>dc:creator</ns0:Value><ns0:Value>dc:date</ns0:Value><ns0:Value>dc:format</ns0:Value><ns0:Value>dc:identifier</ns0:Value><ns0:Value>dc:language</ns0:Value><ns0:Value>dc:publisher</ns0:Value><ns0:Value>dc:relation</ns0:Value><ns0:Value>dc:rights</ns0:Value><ns0:Value>dc:source</ns0:Value><ns0:Value>dc:subject</ns0:Value><ns0:Value>dc:title</ns0:Value><ns0:Value>dc:type</ns0:Value><ns0:Value>dct:abstract</ns0:Value><ns0:Value>dct:alternative</ns0:Value><ns0:Value>dct:modified</ns0:Value><ns0:Value>dct:spatial</ns0:Value><ns0:Value>ows:BoundingBox</ns0:Value></ns0:Constraint><ns0:Constraint name="SupportedISOQueryables"><ns0:Value>apiso:Abstract</ns0:Value><ns0:Value>apiso:AlternateTitle</ns0:Value><ns0:Value>apiso:AnyText</ns0:Value><ns0:Value>apiso:BoundingBox</ns0:Value><ns0:Value>apiso:CRS</ns0:Value><ns0:Value>apiso:CouplingType</ns0:Value><ns0:Value>apiso:CreationDate</ns0:Value><ns0:Value>apiso:Denominator</ns0:Value><ns0:Value>apiso:DistanceUOM</ns0:Value><ns0:Value>apiso:DistanceValue</ns0:Value><ns0:Value>apiso:Format</ns0:Value><ns0:Value>apiso:GeographicDescriptionCode</ns0:Value><ns0:Value>apiso:HasSecurityConstraints</ns0:Value><ns0:Value>apiso:Identifier</ns0:Value><ns0:Value>apiso:KeywordType</ns0:Value><ns0:Value>apiso:Language</ns0:Value><ns0:Value>apiso:Modified</ns0:Value><ns0:Value>apiso:OperatesOn</ns0:Value><ns0:Value>apiso:OperatesOnIdentifier</ns0:Value><ns0:Value>apiso:OperatesOnName</ns0:Value><ns0:Value>apiso:Operation</ns0:Value><ns0:Value>apiso:OrganisationName</ns0:Value><ns0:Value>apiso:ParentIdentifier</ns0:Value><ns0:Value>apiso:PublicationDate</ns0:Value><ns0:Value>apiso:ResourceLanguage</ns0:Value><ns0:Value>apiso:RevisionDate</ns0:Value><ns0:Value>apiso:ServiceType</ns0:Value><ns0:Value>apiso:ServiceTypeVersion</ns0:Value><ns0:Value>apiso:Subject</ns0:Value><ns0:Value>apiso:TempExtent_begin</ns0:Value><ns0:Value>apiso:TempExtent_end</ns0:Value><ns0:Value>apiso:Title</ns0:Value><ns0:Value>apiso:TopicCategory</ns0:Value><ns0:Value>apiso:Type</ns0:Value></ns0:Constraint></ns0:Operation>
Figure A.128
A.11. D112 (CSW) GetRecords without DCS
Example: 4.2
> Access the GMU CSW D112 (GetRecords).
csw_endpoint_items = endpoint_csw + "?SERVICE=CSW&REQUEST=GetRecords&VERSION=2.0.2&ElementSetName=full&typeNames=gmd:MD_Metadata&resultType=results&outputSchema=http://www.isotc211.org/2005/gmd&maxRecords=1"
response = requests.get(csw_endpoint_items,
verify=True,
headers={})
# headers={'Accept': 'application/xml'})
xmlstr = minidom.parseString(response.text).toprettyxml(indent=' ',newl='')
md("```xml\n" + xmlstr + "\n```\n")
Figure A.129
<?xml version="1.0" ?><!-- pycsw 3.0.dev0 --><csw:GetRecordsResponse xmlns:csw="http://www.opengis.net/cat/csw/2.0.2" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dct="http://purl.org/dc/terms/" xmlns:gmd="http://www.isotc211.org/2005/gmd" xmlns:gml="http://www.opengis.net/gml" xmlns:ows="http://www.opengis.net/ows" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:gco="http://www.isotc211.org/2005/gco" version="2.0.2" xsi:schemaLocation="http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd"> <csw:SearchStatus timestamp="2022-10-21T15:19:25Z"/> <csw:SearchResults numberOfRecordsMatched="8" numberOfRecordsReturned="1" nextRecord="2" recordSchema="http://www.isotc211.org/2005/gmd" elementSet="full"> <gmd:MD_Metadata xsi:schemaLocation="http://www.isotc211.org/2005/gmd http://schemas.opengis.net/csw/2.0.2/profiles/apiso/1.0.0/apiso.xsd"> <gmd:fileIdentifier> <gco:CharacterString>urn:uuid:b1e7ef9a-0146-11ed-b12e-d19c2be36fcc</gco:CharacterString> </gmd:fileIdentifier> <gmd:language> <gco:CharacterString>en-US</gco:CharacterString> </gmd:language> <gmd:hierarchyLevel> <gmd:MD_ScopeCode codeSpace="ISOTC211/19115" codeList="http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#MD_ScopeCode" codeListValue="vector digital data">vector digital data</gmd:MD_ScopeCode> </gmd:hierarchyLevel> <gmd:contact> <gmd:CI_ResponsibleParty> <gmd:organisationName> <gco:CharacterString>Earth Data Analysis Center</gco:CharacterString> </gmd:organisationName> </gmd:CI_ResponsibleParty> </gmd:contact> <gmd:dateStamp> <gco:Date/> </gmd:dateStamp> <gmd:metadataStandardName> <gco:CharacterString>ISO19115</gco:CharacterString> </gmd:metadataStandardName> <gmd:metadataStandardVersion> <gco:CharacterString>2003/Cor.1:2006</gco:CharacterString> </gmd:metadataStandardVersion> <gmd:identificationInfo> <gmd:MD_DataIdentification id="urn:uuid:b1e7ef9a-0146-11ed-b12e-d19c2be36fcc"> <gmd:citation> <gmd:CI_Citation> <gmd:title> <gco:CharacterString>Current Core Based Statistical Areas for San Miguel County, New Mexico, 2006se TIGER</gco:CharacterString> </gmd:title> <gmd:date> <gmd:CI_Date> <gmd:date> <gco:Date>20080108</gco:Date> </gmd:date> <gmd:dateType> <gmd:CI_DateTypeCode codeSpace="ISOTC211/19115" codeList="http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#CI_DateTypeCode" codeListValue="publication">publication</gmd:CI_DateTypeCode> </gmd:dateType> </gmd:CI_Date> </gmd:date> </gmd:CI_Citation> </gmd:citation> <gmd:abstract> <gco:CharacterString>The 2006 Second Edition TIGER/Line files are an extract of selected geographic and cartographic information from the Census TIGER database. The geographic coverage for a single TIGER/Line file is a county or statistical equivalent entity, with the coverage area based on the latest available governmental unit boundaries. The Census TIGER database represents a seamless national file with no overlaps or gaps between parts. However, each county-based TIGER/Line file is designed to stand alone as an independent data set or the files can be combined to cover the whole Nation. The 2006 Second Edition TIGER/Line files consist of line segments representing physical features and governmental and statistical boundaries.
This shapefile represents the current Core Based Statistical Areas in the 2006 TIGER Second Edition dataset for San Miguel County, NM.</gco:CharacterString> </gmd:abstract> <gmd:descriptiveKeywords> <gmd:MD_Keywords> <gmd:keyword> <gco:CharacterString>boundaries</gco:CharacterString> </gmd:keyword> </gmd:MD_Keywords> </gmd:descriptiveKeywords> <gmd:language> <gco:CharacterString/> </gmd:language> <gmd:extent> <gmd:EX_Extent> <gmd:geographicElement> <gmd:EX_GeographicBoundingBox> <gmd:westBoundLongitude> <gco:Decimal>-105.72</gco:Decimal> </gmd:westBoundLongitude> <gmd:eastBoundLongitude> <gco:Decimal>-103.64</gco:Decimal> </gmd:eastBoundLongitude> <gmd:southBoundLatitude> <gco:Decimal>35.04</gco:Decimal> </gmd:southBoundLatitude> <gmd:northBoundLatitude> <gco:Decimal>35.87</gco:Decimal> </gmd:northBoundLatitude> </gmd:EX_GeographicBoundingBox> </gmd:geographicElement> </gmd:EX_Extent> </gmd:extent> </gmd:MD_DataIdentification> </gmd:identificationInfo> <gmd:distributionInfo> <gmd:MD_Distribution> <gmd:transferOptions> <gmd:MD_DigitalTransferOptions> <gmd:onLine> <gmd:CI_OnlineResource> <gmd:linkage> <gmd:URL>http://rgis.unm.edu</gmd:URL> </gmd:linkage> <gmd:protocol> <gco:CharacterString/> </gmd:protocol> <gmd:name> <gco:CharacterString/> </gmd:name> <gmd:description> <gco:CharacterString/> </gmd:description> </gmd:CI_OnlineResource> </gmd:onLine> <gmd:onLine> <gmd:CI_OnlineResource> <gmd:linkage> <gmd:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/services/ogc/wms?SERVICE=wms&REQUEST=GetCapabilities&VERSION=1.1.1</gmd:URL> </gmd:linkage> <gmd:protocol> <gco:CharacterString/> </gmd:protocol> <gmd:name> <gco:CharacterString/> </gmd:name> <gmd:description> <gco:CharacterString/> </gmd:description> </gmd:CI_OnlineResource> </gmd:onLine> <gmd:onLine> <gmd:CI_OnlineResource> <gmd:linkage> <gmd:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/services/ogc/wfs?SERVICE=wfs&REQUEST=GetCapabilities&VERSION=1.0.0</gmd:URL> </gmd:linkage> <gmd:protocol> <gco:CharacterString/> </gmd:protocol> <gmd:name> <gco:CharacterString/> </gmd:name> <gmd:description> <gco:CharacterString/> </gmd:description> </gmd:CI_OnlineResource> </gmd:onLine> <gmd:onLine> <gmd:CI_OnlineResource> <gmd:linkage> <gmd:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/tgr2006se_sanm_cbsacu.derived.shp</gmd:URL> </gmd:linkage> <gmd:protocol> <gco:CharacterString/> </gmd:protocol> <gmd:name> <gco:CharacterString/> </gmd:name> <gmd:description> <gco:CharacterString/> </gmd:description> </gmd:CI_OnlineResource> </gmd:onLine> <gmd:onLine> <gmd:CI_OnlineResource> <gmd:linkage> <gmd:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/tgr2006se_sanm_cbsacu.original.zip</gmd:URL> </gmd:linkage> <gmd:protocol> <gco:CharacterString/> </gmd:protocol> <gmd:name> <gco:CharacterString/> </gmd:name> <gmd:description> <gco:CharacterString/> </gmd:description> </gmd:CI_OnlineResource> </gmd:onLine> <gmd:onLine> <gmd:CI_OnlineResource> <gmd:linkage> <gmd:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/tgr2006se_sanm_cbsacu.derived.gml</gmd:URL> </gmd:linkage> <gmd:protocol> <gco:CharacterString/> </gmd:protocol> <gmd:name> <gco:CharacterString/> </gmd:name> <gmd:description> <gco:CharacterString/> </gmd:description> </gmd:CI_OnlineResource> </gmd:onLine> <gmd:onLine> <gmd:CI_OnlineResource> <gmd:linkage> <gmd:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/tgr2006se_sanm_cbsacu.derived.kml</gmd:URL> </gmd:linkage> <gmd:protocol> <gco:CharacterString/> </gmd:protocol> <gmd:name> <gco:CharacterString/> </gmd:name> <gmd:description> <gco:CharacterString/> </gmd:description> </gmd:CI_OnlineResource> </gmd:onLine> <gmd:onLine> <gmd:CI_OnlineResource> <gmd:linkage> <gmd:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/tgr2006se_sanm_cbsacu.derived.geojson</gmd:URL> </gmd:linkage> <gmd:protocol> <gco:CharacterString/> </gmd:protocol> <gmd:name> <gco:CharacterString/> </gmd:name> <gmd:description> <gco:CharacterString/> </gmd:description> </gmd:CI_OnlineResource> </gmd:onLine> <gmd:onLine> <gmd:CI_OnlineResource> <gmd:linkage> <gmd:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/tgr2006se_sanm_cbsacu.derived.json</gmd:URL> </gmd:linkage> <gmd:protocol> <gco:CharacterString/> </gmd:protocol> <gmd:name> <gco:CharacterString/> </gmd:name> <gmd:description> <gco:CharacterString/> </gmd:description> </gmd:CI_OnlineResource> </gmd:onLine> <gmd:onLine> <gmd:CI_OnlineResource> <gmd:linkage> <gmd:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/tgr2006se_sanm_cbsacu.derived.csv</gmd:URL> </gmd:linkage> <gmd:protocol> <gco:CharacterString/> </gmd:protocol> <gmd:name> <gco:CharacterString/> </gmd:name> <gmd:description> <gco:CharacterString/> </gmd:description> </gmd:CI_OnlineResource> </gmd:onLine> <gmd:onLine> <gmd:CI_OnlineResource> <gmd:linkage> <gmd:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/tgr2006se_sanm_cbsacu.derived.xls</gmd:URL> </gmd:linkage> <gmd:protocol> <gco:CharacterString/> </gmd:protocol> <gmd:name> <gco:CharacterString/> </gmd:name> <gmd:description> <gco:CharacterString/> </gmd:description> </gmd:CI_OnlineResource> </gmd:onLine> <gmd:onLine> <gmd:CI_OnlineResource> <gmd:linkage> <gmd:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/metadata/FGDC-STD-001-1998.xml</gmd:URL> </gmd:linkage> <gmd:protocol> <gco:CharacterString/> </gmd:protocol> <gmd:name> <gco:CharacterString/> </gmd:name> <gmd:description> <gco:CharacterString/> </gmd:description> </gmd:CI_OnlineResource> </gmd:onLine> <gmd:onLine> <gmd:CI_OnlineResource> <gmd:linkage> <gmd:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/metadata/FGDC-STD-001-1998.html</gmd:URL> </gmd:linkage> <gmd:protocol> <gco:CharacterString/> </gmd:protocol> <gmd:name> <gco:CharacterString/> </gmd:name> <gmd:description> <gco:CharacterString/> </gmd:description> </gmd:CI_OnlineResource> </gmd:onLine> <gmd:onLine> <gmd:CI_OnlineResource> <gmd:linkage> <gmd:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/metadata/ISO-19115:2003.xml</gmd:URL> </gmd:linkage> <gmd:protocol> <gco:CharacterString/> </gmd:protocol> <gmd:name> <gco:CharacterString/> </gmd:name> <gmd:description> <gco:CharacterString/> </gmd:description> </gmd:CI_OnlineResource> </gmd:onLine> <gmd:onLine> <gmd:CI_OnlineResource> <gmd:linkage> <gmd:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/metadata/ISO-19115:2003.html</gmd:URL> </gmd:linkage> <gmd:protocol> <gco:CharacterString/> </gmd:protocol> <gmd:name> <gco:CharacterString/> </gmd:name> <gmd:description> <gco:CharacterString/> </gmd:description> </gmd:CI_OnlineResource> </gmd:onLine> <gmd:onLine> <gmd:CI_OnlineResource> <gmd:linkage> <gmd:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/metadata/ISO-19119:WMS.xml</gmd:URL> </gmd:linkage> <gmd:protocol> <gco:CharacterString/> </gmd:protocol> <gmd:name> <gco:CharacterString/> </gmd:name> <gmd:description> <gco:CharacterString/> </gmd:description> </gmd:CI_OnlineResource> </gmd:onLine> <gmd:onLine> <gmd:CI_OnlineResource> <gmd:linkage> <gmd:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/metadata/ISO-19119:WFS.xml</gmd:URL> </gmd:linkage> <gmd:protocol> <gco:CharacterString/> </gmd:protocol> <gmd:name> <gco:CharacterString/> </gmd:name> <gmd:description> <gco:CharacterString/> </gmd:description> </gmd:CI_OnlineResource> </gmd:onLine> <gmd:onLine> <gmd:CI_OnlineResource> <gmd:linkage> <gmd:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/metadata/ISO-19110.xml</gmd:URL> </gmd:linkage> <gmd:protocol> <gco:CharacterString/> </gmd:protocol> <gmd:name> <gco:CharacterString/> </gmd:name> <gmd:description> <gco:CharacterString/> </gmd:description> </gmd:CI_OnlineResource> </gmd:onLine> <gmd:onLine> <gmd:CI_OnlineResource> <gmd:linkage> <gmd:URL/> </gmd:linkage> <gmd:protocol> <gco:CharacterString/> </gmd:protocol> <gmd:name> <gco:CharacterString/> </gmd:name> <gmd:description> <gco:CharacterString>ZIP</gco:CharacterString> </gmd:description> </gmd:CI_OnlineResource> </gmd:onLine> </gmd:MD_DigitalTransferOptions> </gmd:transferOptions> </gmd:MD_Distribution> </gmd:distributionInfo> </gmd:MD_Metadata> </csw:SearchResults></csw:GetRecordsResponse>
Figure A.130
A.12. D112 (CSW) GetRecordByID without DCS
Example: 4.3
> Access the GMU CSW D112 (GetRecordByID).
item_id = "urn:uuid:b1e7ef9a-0146-11ed-b12e-d19c2be36fcc"
csw_endpoint_item = endpoint_csw + "?SERVICE=CSW&REQUEST=GetRecordById&VERSION=2.0.2&id=" + item_id + "&ElementSetName=full&outputSchema=http://www.isotc211.org/2005/gmd&outputFormat=application/xml"
response = requests.get(csw_endpoint_item,
verify=True,
headers={})
# Extract ISO19139 metadata record from the response.
rt = ElementTree.fromstring(response.text)
r = rt.find('{*}MD_Metadata')
try:
xmltxt = ElementTree.tostring(r, encoding='unicode', method='xml')
except:
xmltxt= 'Not found.'
md("```xml\n" + xmltxt + "\n```\n")
Figure A.131
<ns0:MD_Metadata xmlns:ns0="http://www.isotc211.org/2005/gmd" xmlns:ns2="http://www.isotc211.org/2005/gco" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.isotc211.org/2005/gmd http://schemas.opengis.net/csw/2.0.2/profiles/apiso/1.0.0/apiso.xsd"><ns0:fileIdentifier><ns2:CharacterString>urn:uuid:b1e7ef9a-0146-11ed-b12e-d19c2be36fcc</ns2:CharacterString></ns0:fileIdentifier><ns0:language><ns2:CharacterString>en-US</ns2:CharacterString></ns0:language><ns0:hierarchyLevel><ns0:MD_ScopeCode codeSpace="ISOTC211/19115" codeList="http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#MD_ScopeCode" codeListValue="vector digital data">vector digital data</ns0:MD_ScopeCode></ns0:hierarchyLevel><ns0:contact><ns0:CI_ResponsibleParty><ns0:organisationName><ns2:CharacterString>Earth Data Analysis Center</ns2:CharacterString></ns0:organisationName></ns0:CI_ResponsibleParty></ns0:contact><ns0:dateStamp><ns2:Date /></ns0:dateStamp><ns0:metadataStandardName><ns2:CharacterString>ISO19115</ns2:CharacterString></ns0:metadataStandardName><ns0:metadataStandardVersion><ns2:CharacterString>2003/Cor.1:2006</ns2:CharacterString></ns0:metadataStandardVersion><ns0:identificationInfo><ns0:MD_DataIdentification id="urn:uuid:b1e7ef9a-0146-11ed-b12e-d19c2be36fcc"><ns0:citation><ns0:CI_Citation><ns0:title><ns2:CharacterString>Current Core Based Statistical Areas for San Miguel County, New Mexico, 2006se TIGER</ns2:CharacterString></ns0:title><ns0:date><ns0:CI_Date><ns0:date><ns2:Date>20080108</ns2:Date></ns0:date><ns0:dateType><ns0:CI_DateTypeCode codeSpace="ISOTC211/19115" codeList="http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#CI_DateTypeCode" codeListValue="publication">publication</ns0:CI_DateTypeCode></ns0:dateType></ns0:CI_Date></ns0:date></ns0:CI_Citation></ns0:citation><ns0:abstract><ns2:CharacterString>The 2006 Second Edition TIGER/Line files are an extract of selected geographic and cartographic information from the Census TIGER database. The geographic coverage for a single TIGER/Line file is a county or statistical equivalent entity, with the coverage area based on the latest available governmental unit boundaries. The Census TIGER database represents a seamless national file with no overlaps or gaps between parts. However, each county-based TIGER/Line file is designed to stand alone as an independent data set or the files can be combined to cover the whole Nation. The 2006 Second Edition TIGER/Line files consist of line segments representing physical features and governmental and statistical boundaries.
This shapefile represents the current Core Based Statistical Areas in the 2006 TIGER Second Edition dataset for San Miguel County, NM.</ns2:CharacterString></ns0:abstract><ns0:descriptiveKeywords><ns0:MD_Keywords><ns0:keyword><ns2:CharacterString>boundaries</ns2:CharacterString></ns0:keyword></ns0:MD_Keywords></ns0:descriptiveKeywords><ns0:language><ns2:CharacterString /></ns0:language><ns0:extent><ns0:EX_Extent><ns0:geographicElement><ns0:EX_GeographicBoundingBox><ns0:westBoundLongitude><ns2:Decimal>-105.72</ns2:Decimal></ns0:westBoundLongitude><ns0:eastBoundLongitude><ns2:Decimal>-103.64</ns2:Decimal></ns0:eastBoundLongitude><ns0:southBoundLatitude><ns2:Decimal>35.04</ns2:Decimal></ns0:southBoundLatitude><ns0:northBoundLatitude><ns2:Decimal>35.87</ns2:Decimal></ns0:northBoundLatitude></ns0:EX_GeographicBoundingBox></ns0:geographicElement></ns0:EX_Extent></ns0:extent></ns0:MD_DataIdentification></ns0:identificationInfo><ns0:distributionInfo><ns0:MD_Distribution><ns0:transferOptions><ns0:MD_DigitalTransferOptions><ns0:onLine><ns0:CI_OnlineResource><ns0:linkage><ns0:URL>http://rgis.unm.edu</ns0:URL></ns0:linkage><ns0:protocol><ns2:CharacterString /></ns0:protocol><ns0:name><ns2:CharacterString /></ns0:name><ns0:description><ns2:CharacterString /></ns0:description></ns0:CI_OnlineResource></ns0:onLine><ns0:onLine><ns0:CI_OnlineResource><ns0:linkage><ns0:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/services/ogc/wms?SERVICE=wms&REQUEST=GetCapabilities&VERSION=1.1.1</ns0:URL></ns0:linkage><ns0:protocol><ns2:CharacterString /></ns0:protocol><ns0:name><ns2:CharacterString /></ns0:name><ns0:description><ns2:CharacterString /></ns0:description></ns0:CI_OnlineResource></ns0:onLine><ns0:onLine><ns0:CI_OnlineResource><ns0:linkage><ns0:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/services/ogc/wfs?SERVICE=wfs&REQUEST=GetCapabilities&VERSION=1.0.0</ns0:URL></ns0:linkage><ns0:protocol><ns2:CharacterString /></ns0:protocol><ns0:name><ns2:CharacterString /></ns0:name><ns0:description><ns2:CharacterString /></ns0:description></ns0:CI_OnlineResource></ns0:onLine><ns0:onLine><ns0:CI_OnlineResource><ns0:linkage><ns0:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/tgr2006se_sanm_cbsacu.derived.shp</ns0:URL></ns0:linkage><ns0:protocol><ns2:CharacterString /></ns0:protocol><ns0:name><ns2:CharacterString /></ns0:name><ns0:description><ns2:CharacterString /></ns0:description></ns0:CI_OnlineResource></ns0:onLine><ns0:onLine><ns0:CI_OnlineResource><ns0:linkage><ns0:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/tgr2006se_sanm_cbsacu.original.zip</ns0:URL></ns0:linkage><ns0:protocol><ns2:CharacterString /></ns0:protocol><ns0:name><ns2:CharacterString /></ns0:name><ns0:description><ns2:CharacterString /></ns0:description></ns0:CI_OnlineResource></ns0:onLine><ns0:onLine><ns0:CI_OnlineResource><ns0:linkage><ns0:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/tgr2006se_sanm_cbsacu.derived.gml</ns0:URL></ns0:linkage><ns0:protocol><ns2:CharacterString /></ns0:protocol><ns0:name><ns2:CharacterString /></ns0:name><ns0:description><ns2:CharacterString /></ns0:description></ns0:CI_OnlineResource></ns0:onLine><ns0:onLine><ns0:CI_OnlineResource><ns0:linkage><ns0:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/tgr2006se_sanm_cbsacu.derived.kml</ns0:URL></ns0:linkage><ns0:protocol><ns2:CharacterString /></ns0:protocol><ns0:name><ns2:CharacterString /></ns0:name><ns0:description><ns2:CharacterString /></ns0:description></ns0:CI_OnlineResource></ns0:onLine><ns0:onLine><ns0:CI_OnlineResource><ns0:linkage><ns0:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/tgr2006se_sanm_cbsacu.derived.geojson</ns0:URL></ns0:linkage><ns0:protocol><ns2:CharacterString /></ns0:protocol><ns0:name><ns2:CharacterString /></ns0:name><ns0:description><ns2:CharacterString /></ns0:description></ns0:CI_OnlineResource></ns0:onLine><ns0:onLine><ns0:CI_OnlineResource><ns0:linkage><ns0:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/tgr2006se_sanm_cbsacu.derived.json</ns0:URL></ns0:linkage><ns0:protocol><ns2:CharacterString /></ns0:protocol><ns0:name><ns2:CharacterString /></ns0:name><ns0:description><ns2:CharacterString /></ns0:description></ns0:CI_OnlineResource></ns0:onLine><ns0:onLine><ns0:CI_OnlineResource><ns0:linkage><ns0:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/tgr2006se_sanm_cbsacu.derived.csv</ns0:URL></ns0:linkage><ns0:protocol><ns2:CharacterString /></ns0:protocol><ns0:name><ns2:CharacterString /></ns0:name><ns0:description><ns2:CharacterString /></ns0:description></ns0:CI_OnlineResource></ns0:onLine><ns0:onLine><ns0:CI_OnlineResource><ns0:linkage><ns0:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/tgr2006se_sanm_cbsacu.derived.xls</ns0:URL></ns0:linkage><ns0:protocol><ns2:CharacterString /></ns0:protocol><ns0:name><ns2:CharacterString /></ns0:name><ns0:description><ns2:CharacterString /></ns0:description></ns0:CI_OnlineResource></ns0:onLine><ns0:onLine><ns0:CI_OnlineResource><ns0:linkage><ns0:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/metadata/FGDC-STD-001-1998.xml</ns0:URL></ns0:linkage><ns0:protocol><ns2:CharacterString /></ns0:protocol><ns0:name><ns2:CharacterString /></ns0:name><ns0:description><ns2:CharacterString /></ns0:description></ns0:CI_OnlineResource></ns0:onLine><ns0:onLine><ns0:CI_OnlineResource><ns0:linkage><ns0:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/metadata/FGDC-STD-001-1998.html</ns0:URL></ns0:linkage><ns0:protocol><ns2:CharacterString /></ns0:protocol><ns0:name><ns2:CharacterString /></ns0:name><ns0:description><ns2:CharacterString /></ns0:description></ns0:CI_OnlineResource></ns0:onLine><ns0:onLine><ns0:CI_OnlineResource><ns0:linkage><ns0:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/metadata/ISO-19115:2003.xml</ns0:URL></ns0:linkage><ns0:protocol><ns2:CharacterString /></ns0:protocol><ns0:name><ns2:CharacterString /></ns0:name><ns0:description><ns2:CharacterString /></ns0:description></ns0:CI_OnlineResource></ns0:onLine><ns0:onLine><ns0:CI_OnlineResource><ns0:linkage><ns0:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/metadata/ISO-19115:2003.html</ns0:URL></ns0:linkage><ns0:protocol><ns2:CharacterString /></ns0:protocol><ns0:name><ns2:CharacterString /></ns0:name><ns0:description><ns2:CharacterString /></ns0:description></ns0:CI_OnlineResource></ns0:onLine><ns0:onLine><ns0:CI_OnlineResource><ns0:linkage><ns0:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/metadata/ISO-19119:WMS.xml</ns0:URL></ns0:linkage><ns0:protocol><ns2:CharacterString /></ns0:protocol><ns0:name><ns2:CharacterString /></ns0:name><ns0:description><ns2:CharacterString /></ns0:description></ns0:CI_OnlineResource></ns0:onLine><ns0:onLine><ns0:CI_OnlineResource><ns0:linkage><ns0:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/metadata/ISO-19119:WFS.xml</ns0:URL></ns0:linkage><ns0:protocol><ns2:CharacterString /></ns0:protocol><ns0:name><ns2:CharacterString /></ns0:name><ns0:description><ns2:CharacterString /></ns0:description></ns0:CI_OnlineResource></ns0:onLine><ns0:onLine><ns0:CI_OnlineResource><ns0:linkage><ns0:URL>https://gstore.unm.edu/apps/rgisarchive/datasets/5b718539-f99f-43a0-9a7e-2cefed2df238/metadata/ISO-19110.xml</ns0:URL></ns0:linkage><ns0:protocol><ns2:CharacterString /></ns0:protocol><ns0:name><ns2:CharacterString /></ns0:name><ns0:description><ns2:CharacterString /></ns0:description></ns0:CI_OnlineResource></ns0:onLine><ns0:onLine><ns0:CI_OnlineResource><ns0:linkage><ns0:URL /></ns0:linkage><ns0:protocol><ns2:CharacterString /></ns0:protocol><ns0:name><ns2:CharacterString /></ns0:name><ns0:description><ns2:CharacterString>ZIP</ns2:CharacterString></ns0:description></ns0:CI_OnlineResource></ns0:onLine></ns0:MD_DigitalTransferOptions></ns0:transferOptions></ns0:MD_Distribution></ns0:distributionInfo></ns0:MD_Metadata>
Figure A.132
A.13. Subscriptions to OGC API-Records
See information available at https://ogc.demo.secure-dimensions.de/sms/api.
Prepare key pairs See https://jwcrypto.readthedocs.io/en/latest/jwk.html
srv_kid = "srvkid"
cli_kid = "clikid"
ss_key = jwk.JWK(generate='RSA', kid=srv_kid, use="sig")
se_key = jwk.JWK(generate='RSA', kid=srv_kid, use="enc")
cs_key = jwk.JWK(generate='RSA', kid=cli_kid, use="sig")
ce_key = jwk.JWK(generate='RSA', kid=cli_kid, use="enc")
# client key pair for encryption (public+private)
ce_key.export()
Figure A.133
'{"d":"_rw1-M-daUJgW80IuhltH3uFpv0lttiSbeIa_A1Gn75mc48w3kaTXH0RHpC6whAz88N0fKxbJwDbmsUs6PJ1BvkZJTu04nOtlTF0GuWj7uhAY5S-zj-Gq5odBUyi72S8aSOpKMFOeiwcYZxWs-L4_attPMJSDgMxTzHtpTjmZvTSSESuD-KYkJPTbvvA7UVBIt43usuNTUhxDVcQY-emGTAYsicOeZGWFGWYo24LjX1RKP95IztCa0Mw2MPEPE8rA1muvfkk3MnhntdOLRTlw0TexpAwNGn0_2hy80uFwD6vRPOCzocLZT0FdllgOLYzr4JwXE_G1MIVIgTXnwZB","dp":"P60BtUnExG1zxR6obqGnP5z2yCGtp0LXjrg5tFJa6H6OPv_wALbPSfEf67Dj8IvQTmZnPDVmOT21GRbB2fV7LtqfHMpt0-bTMHlwBkR0BJo47BF0PHwnX_MtepHzvYA36roXkimS_8Oc_PR4DqPa0up3DbsO6Bid0xwBRkcYXCU","dq":"TQ466gqzsiLTQK3VTKg1J-zY4Gp-xocHHPALnrrj96aeHUWMb09zArFxKIMLpzDHs24DN0PxyVC2h6hjQAP-dheSYFRwcQOF5uj1NkfFvyTf19hTzP1pBKTTNm9exMSwAEXel4bJlfqFs89k6NGsFTEuhVnavf7eY7FjRfv-itU","e":"AQAB","kid":"clikid","kty":"RSA","n":"2qBsAlkltTmv-oMoLVsay9B-CAo_3ie5fi8Mg9Aph72w9uR5gEcfz6A-rsPLMH8buNwuUIoKo73NRc-glXBA9XUSvNn86dJiHTEyKAZm9ybm3_qZGSDl0KlgqDNx-qGOi2r5JSN3AQYlAvLi1_qSaIVDOwKQJY7NZR1C7Z2l7jqQfSxEoIRSt_K57Gt9wo7GIHcuOnzr30zTYg1UzSQx_b8bxdoUDWrNgCJYw9NuwmvRkjaBJr___bMbKz0LnqlwfI3eHqCYb8bfcR9YdL17f4vIAtkk_XWXjB-hldoPwQiVpBno4Bz14PXaDFB4p8d3BcrLwKz3ESy6sW6CiZmIQw","p":"-uTjBeriYAs1L11usnn1B763ki0flOK5Lcj_r2nFZ1-qwd52fZqSoIkSKJ06zPmIkYSuVDLzfzTP4mKj_NmWBakxmLAdR2jIsGQ8BU1IdkyzrhgrL7vYmbQ0mlVFe3tphT2lWbOV8fkGJlijMYMEHwxby6Qn4XTsxbYZD6CtakU","q":"3xNtcipbvk3RUDBgjoxhb1HzKvzNSDDTYGf0C2HNl9snjjvF4mp2CfTe7wRd7i7N5_R-zfB_KoZ6XH2aAKuCRiKb61wsHohG3QtJhMtqiSIG4jcuW1cqVt6X4uYSdPfYEcxI-kslTcfQ8ChycZDTaMxRORycgb-Xct5P1JFAVOc","qi":"H7sbm1Vp7BlX5gihmu5s4sA3H2nf-NyG6M01pYBcR5RpyaouwEQEVQK71JGm1VWt3jYfVQ79wNHzYZ6UYVOiLV-U4oFRXz2wAkQMjQvQrQrrdxujlgQ8hRj_S_6ogQnFnxAGd8onm2cdX1LZGoEPCfsEy1QLjUHs_fwCAcq1HNA","use":"enc"}'
Figure A.134
# Prepare subscription object including public key. Put here your actual email address to receive notifications.
myobj = {
"name": "pySubscription",
"delivery": "mailto:john.doe@company.com" ,
"schedule": "* * */1 * *",
# "resources-uri": endpoint_items + '?f=xml',
"resources-uri": endpoint_items,
"expires": 1759104237,
"sec-opts": {
"x-ogc-callback-key": "string",
"public-key": ce_key.export()
}
}
myobj
Figure A.135
{'name': 'pySubscription', 'delivery': 'mailto:john.doe@company.com', 'schedule': '* * */1 * *', 'resources-uri': 'https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items', 'expires': 1759104237, 'sec-opts': {'x-ogc-callback-key': 'string', 'public-key': '{"d":"_rw1-M-daUJgW80IuhltH3uFpv0lttiSbeIa_A1Gn75mc48w3kaTXH0RHpC6whAz88N0fKxbJwDbmsUs6PJ1BvkZJTu04nOtlTF0GuWj7uhAY5S-zj-Gq5odBUyi72S8aSOpKMFOeiwcYZxWs-L4_attPMJSDgMxTzHtpTjmZvTSSESuD-KYkJPTbvvA7UVBIt43usuNTUhxDVcQY-emGTAYsicOeZGWFGWYo24LjX1RKP95IztCa0Mw2MPEPE8rA1muvfkk3MnhntdOLRTlw0TexpAwNGn0_2hy80uFwD6vRPOCzocLZT0FdllgOLYzr4JwXE_G1MIVIgTXnwZB","dp":"P60BtUnExG1zxR6obqGnP5z2yCGtp0LXjrg5tFJa6H6OPv_wALbPSfEf67Dj8IvQTmZnPDVmOT21GRbB2fV7LtqfHMpt0-bTMHlwBkR0BJo47BF0PHwnX_MtepHzvYA36roXkimS_8Oc_PR4DqPa0up3DbsO6Bid0xwBRkcYXCU","dq":"TQ466gqzsiLTQK3VTKg1J-zY4Gp-xocHHPALnrrj96aeHUWMb09zArFxKIMLpzDHs24DN0PxyVC2h6hjQAP-dheSYFRwcQOF5uj1NkfFvyTf19hTzP1pBKTTNm9exMSwAEXel4bJlfqFs89k6NGsFTEuhVnavf7eY7FjRfv-itU","e":"AQAB","kid":"clikid","kty":"RSA","n":"2qBsAlkltTmv-oMoLVsay9B-CAo_3ie5fi8Mg9Aph72w9uR5gEcfz6A-rsPLMH8buNwuUIoKo73NRc-glXBA9XUSvNn86dJiHTEyKAZm9ybm3_qZGSDl0KlgqDNx-qGOi2r5JSN3AQYlAvLi1_qSaIVDOwKQJY7NZR1C7Z2l7jqQfSxEoIRSt_K57Gt9wo7GIHcuOnzr30zTYg1UzSQx_b8bxdoUDWrNgCJYw9NuwmvRkjaBJr___bMbKz0LnqlwfI3eHqCYb8bfcR9YdL17f4vIAtkk_XWXjB-hldoPwQiVpBno4Bz14PXaDFB4p8d3BcrLwKz3ESy6sW6CiZmIQw","p":"-uTjBeriYAs1L11usnn1B763ki0flOK5Lcj_r2nFZ1-qwd52fZqSoIkSKJ06zPmIkYSuVDLzfzTP4mKj_NmWBakxmLAdR2jIsGQ8BU1IdkyzrhgrL7vYmbQ0mlVFe3tphT2lWbOV8fkGJlijMYMEHwxby6Qn4XTsxbYZD6CtakU","q":"3xNtcipbvk3RUDBgjoxhb1HzKvzNSDDTYGf0C2HNl9snjjvF4mp2CfTe7wRd7i7N5_R-zfB_KoZ6XH2aAKuCRiKb61wsHohG3QtJhMtqiSIG4jcuW1cqVt6X4uYSdPfYEcxI-kslTcfQ8ChycZDTaMxRORycgb-Xct5P1JFAVOc","qi":"H7sbm1Vp7BlX5gihmu5s4sA3H2nf-NyG6M01pYBcR5RpyaouwEQEVQK71JGm1VWt3jYfVQ79wNHzYZ6UYVOiLV-U4oFRXz2wAkQMjQvQrQrrdxujlgQ8hRj_S_6ogQnFnxAGd8onm2cdX1LZGoEPCfsEy1QLjUHs_fwCAcq1HNA","use":"enc"}'}}
Figure A.136
A.13.1. Create subscription
Example: 5.1
> Create subscription.
response = requests.post(endpoint_subscriptions, json = myobj,
verify=bool(verify_ssl),
headers={'Accept': 'application/json', 'Authorization': 'Bearer ' + access_token})
response
Figure A.137
<Response [201]>
Figure A.138
A.13.2. Get list of subscriptions
Example: 5.2
> Get list of subscriptions.
response = requests.get(endpoint_subscriptions,
verify=bool(verify_ssl),
headers={'Accept': 'application/json', 'Authorization': 'Bearer ' + access_token})
response.text
Figure A.139
'[{"id":212,"name":"pySubscription","delivery":"mailto:john.doe@company.com","schedule":"* * */1 * *","resources-uri":"https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items","expires":1759104237,"sec-opts":{"x-ogc-callback-key":"string","public-key":"{\\"d\\":\\"GTSwJzYovf79k7JB6gW3ziiTy_VnFHL2PFiVcTTRs_TnNEN0_AgoUPQZ0U2gKM1L2vTiNqbAg1Wzs3CYYf_TJGCELVbikG82x5Pum0yxN3UDHvHXESum8OKdjIuGhhOw1kWbAUD9-haQIKpMUnLy432IC3TLlZ-f1twS-0YQR3zk2qdtsiQF5rIqFps0bjjcJid4F9ifxTQqeeYhaAkdh-SBmO2kikwkA_g4PH3fQdfM57R4iuy32TF6u-uLT5p54qRuQ-wTDZ0B_vzpQZ7jVc6skNvuW-XNmTng2hY9mSaeLoKiOf74QZyIKBSywKgAresxKfVnBuEppQEvdZKbSQ\\",\\"dp\\":\\"YKPZt__yim_TNerZ0inwls-hmmsv4BKzKyZTN2cl7VN_ruw4YCPQXXO5S4CzmUW8NO5g0icih1UHDwTLddTx-4w7nSlMJIv8sY6r46dAKMHtYju1HtF3ayrJoT6M9J5Re4tnLZx0Ns-rLxndbwCzFgS3viJPeaYKZkMUvwRzhbE\\",\\"dq\\":\\"FhWIJ3UroDsWHsLJUlh5MCybYzLsDFt7i8k0qJGHaad_zqdplWl_jkgBI6OSQeZUufhyNhkHsd_jTe-8a8ONuDT_4EUXphdQbnNw0vVGZqVtzcL9Fa-bnNiwrHSlA8UnF-jiDXX65z6jDEHKWD2fM37z112lP8xoueLcti4FvQk\\",\\"e\\":\\"AQAB\\",\\"kid\\":\\"clikid\\",\\"kty\\":\\"RSA\\",\\"n\\":\\"tt88JhkKs-d7tZy7mZGcXMvIQs2UWdufE5K3BfQ-6vvyfI3eHoRKpCqlLVBmSCD39pyv8ML0n7r5ZWUPZpeMJtqaJ_YPMwUX1TBgfEKwcI3ZQguXZbfvPOnpbVBx7zgnPYsdYT-nSeIu19I7A_-3ex29NjIbNXW7l2xEu__a5lJCDZjhXRu0Oy8blZz28WY20lSC79W0FB-gKlaNM_zZvBMWanTGg3IxmZf_YldZjvli37UVzROdDbSdlK02s9FiDQFbyGmpp25BCx5wn76Jue79Lxmo4j_OXqOwkNYx-gTYXb1bNIC5SMz-OYRXmSZEO-rtoM53bk08UrEZ4Qsqpw\\",\\"p\\":\\"xprCRD94cvlh5wjgXQWX3z_KZGIl0fE5H4dAebeiRgtPmuI2RPmAb4UiuJ5cdi1JmjLgfOi1mp-8eOT3hyPJGF-eM_Y_uMe8jGnhKRxFjRf80oY_kRRT6NWCIKhfVDxaLk9uSo6uWnxxmL3PCeQc45jHfhkPG4v8T0rbfcUZDBk\\",\\"q\\":\\"67iL9zdUx744x9WkfNKeIUNb4pO7QjCxwH1u-sEf_J5_Vtt8ct6vcDit7oSqVr9mlE_klpEAnxYQQNXndpN9vRHZMb1JWNkUa5CQXFBxPLL39gbKKOOJG7KDTMWF8BR3SeFlKdyoqSyf5C746dFHl9rywTAOkdSpCf1F7BnYxL8\\",\\"qi\\":\\"h96KLTIDphk0opY3dWep1ooMDTLHdawJ_3B2jOamhUv_feoHkdH6VAxGQETm-5_PMcOijHDIpzsWlZ54C9JhXlw6vEDHsR3FQAvcVWyo6M4XdefwoC4FgTKwJT3GsU71bhK2Q-W-1oaCMDVsg6IIGDzbMx6c-MuGdvN2E4BFBvU\\",\\"use\\":\\"enc\\"}"},"state":"created","created":1666365527},{"id":213,"name":"pySubscription","delivery":"mailto:john.doe@company.com","schedule":"* * */1 * *","resources-uri":"https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items","expires":1759104237,"sec-opts":{"x-ogc-callback-key":"string","public-key":"{\\"d\\":\\"_rw1-M-daUJgW80IuhltH3uFpv0lttiSbeIa_A1Gn75mc48w3kaTXH0RHpC6whAz88N0fKxbJwDbmsUs6PJ1BvkZJTu04nOtlTF0GuWj7uhAY5S-zj-Gq5odBUyi72S8aSOpKMFOeiwcYZxWs-L4_attPMJSDgMxTzHtpTjmZvTSSESuD-KYkJPTbvvA7UVBIt43usuNTUhxDVcQY-emGTAYsicOeZGWFGWYo24LjX1RKP95IztCa0Mw2MPEPE8rA1muvfkk3MnhntdOLRTlw0TexpAwNGn0_2hy80uFwD6vRPOCzocLZT0FdllgOLYzr4JwXE_G1MIVIgTXnwZB\\",\\"dp\\":\\"P60BtUnExG1zxR6obqGnP5z2yCGtp0LXjrg5tFJa6H6OPv_wALbPSfEf67Dj8IvQTmZnPDVmOT21GRbB2fV7LtqfHMpt0-bTMHlwBkR0BJo47BF0PHwnX_MtepHzvYA36roXkimS_8Oc_PR4DqPa0up3DbsO6Bid0xwBRkcYXCU\\",\\"dq\\":\\"TQ466gqzsiLTQK3VTKg1J-zY4Gp-xocHHPALnrrj96aeHUWMb09zArFxKIMLpzDHs24DN0PxyVC2h6hjQAP-dheSYFRwcQOF5uj1NkfFvyTf19hTzP1pBKTTNm9exMSwAEXel4bJlfqFs89k6NGsFTEuhVnavf7eY7FjRfv-itU\\",\\"e\\":\\"AQAB\\",\\"kid\\":\\"clikid\\",\\"kty\\":\\"RSA\\",\\"n\\":\\"2qBsAlkltTmv-oMoLVsay9B-CAo_3ie5fi8Mg9Aph72w9uR5gEcfz6A-rsPLMH8buNwuUIoKo73NRc-glXBA9XUSvNn86dJiHTEyKAZm9ybm3_qZGSDl0KlgqDNx-qGOi2r5JSN3AQYlAvLi1_qSaIVDOwKQJY7NZR1C7Z2l7jqQfSxEoIRSt_K57Gt9wo7GIHcuOnzr30zTYg1UzSQx_b8bxdoUDWrNgCJYw9NuwmvRkjaBJr___bMbKz0LnqlwfI3eHqCYb8bfcR9YdL17f4vIAtkk_XWXjB-hldoPwQiVpBno4Bz14PXaDFB4p8d3BcrLwKz3ESy6sW6CiZmIQw\\",\\"p\\":\\"-uTjBeriYAs1L11usnn1B763ki0flOK5Lcj_r2nFZ1-qwd52fZqSoIkSKJ06zPmIkYSuVDLzfzTP4mKj_NmWBakxmLAdR2jIsGQ8BU1IdkyzrhgrL7vYmbQ0mlVFe3tphT2lWbOV8fkGJlijMYMEHwxby6Qn4XTsxbYZD6CtakU\\",\\"q\\":\\"3xNtcipbvk3RUDBgjoxhb1HzKvzNSDDTYGf0C2HNl9snjjvF4mp2CfTe7wRd7i7N5_R-zfB_KoZ6XH2aAKuCRiKb61wsHohG3QtJhMtqiSIG4jcuW1cqVt6X4uYSdPfYEcxI-kslTcfQ8ChycZDTaMxRORycgb-Xct5P1JFAVOc\\",\\"qi\\":\\"H7sbm1Vp7BlX5gihmu5s4sA3H2nf-NyG6M01pYBcR5RpyaouwEQEVQK71JGm1VWt3jYfVQ79wNHzYZ6UYVOiLV-U4oFRXz2wAkQMjQvQrQrrdxujlgQ8hRj_S_6ogQnFnxAGd8onm2cdX1LZGoEPCfsEy1QLjUHs_fwCAcq1HNA\\",\\"use\\":\\"enc\\"}"},"state":"created","created":1666365965}]\n'
Figure A.140
# extract first subscription id
data = json.loads(response.text)
id = data[0]['id']
id
Figure A.141
212
Figure A.142
A.13.3. Get subscription status
Example: 5.3
> Get subscription status.
response = requests.get(endpoint_subscriptions + "/" + str(id),
verify=bool(verify_ssl),
headers={'Accept': 'application/json', 'Authorization': 'Bearer ' + access_token})
response.text
Figure A.143
'{"name":"pySubscription","delivery":"mailto:john.doe@company.com","schedule":"* * */1 * *","resources-uri":"https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items","expires":1759104237,"sec-opts":{"x-ogc-callback-key":"string","public-key":"{\\"d\\":\\"GTSwJzYovf79k7JB6gW3ziiTy_VnFHL2PFiVcTTRs_TnNEN0_AgoUPQZ0U2gKM1L2vTiNqbAg1Wzs3CYYf_TJGCELVbikG82x5Pum0yxN3UDHvHXESum8OKdjIuGhhOw1kWbAUD9-haQIKpMUnLy432IC3TLlZ-f1twS-0YQR3zk2qdtsiQF5rIqFps0bjjcJid4F9ifxTQqeeYhaAkdh-SBmO2kikwkA_g4PH3fQdfM57R4iuy32TF6u-uLT5p54qRuQ-wTDZ0B_vzpQZ7jVc6skNvuW-XNmTng2hY9mSaeLoKiOf74QZyIKBSywKgAresxKfVnBuEppQEvdZKbSQ\\",\\"dp\\":\\"YKPZt__yim_TNerZ0inwls-hmmsv4BKzKyZTN2cl7VN_ruw4YCPQXXO5S4CzmUW8NO5g0icih1UHDwTLddTx-4w7nSlMJIv8sY6r46dAKMHtYju1HtF3ayrJoT6M9J5Re4tnLZx0Ns-rLxndbwCzFgS3viJPeaYKZkMUvwRzhbE\\",\\"dq\\":\\"FhWIJ3UroDsWHsLJUlh5MCybYzLsDFt7i8k0qJGHaad_zqdplWl_jkgBI6OSQeZUufhyNhkHsd_jTe-8a8ONuDT_4EUXphdQbnNw0vVGZqVtzcL9Fa-bnNiwrHSlA8UnF-jiDXX65z6jDEHKWD2fM37z112lP8xoueLcti4FvQk\\",\\"e\\":\\"AQAB\\",\\"kid\\":\\"clikid\\",\\"kty\\":\\"RSA\\",\\"n\\":\\"tt88JhkKs-d7tZy7mZGcXMvIQs2UWdufE5K3BfQ-6vvyfI3eHoRKpCqlLVBmSCD39pyv8ML0n7r5ZWUPZpeMJtqaJ_YPMwUX1TBgfEKwcI3ZQguXZbfvPOnpbVBx7zgnPYsdYT-nSeIu19I7A_-3ex29NjIbNXW7l2xEu__a5lJCDZjhXRu0Oy8blZz28WY20lSC79W0FB-gKlaNM_zZvBMWanTGg3IxmZf_YldZjvli37UVzROdDbSdlK02s9FiDQFbyGmpp25BCx5wn76Jue79Lxmo4j_OXqOwkNYx-gTYXb1bNIC5SMz-OYRXmSZEO-rtoM53bk08UrEZ4Qsqpw\\",\\"p\\":\\"xprCRD94cvlh5wjgXQWX3z_KZGIl0fE5H4dAebeiRgtPmuI2RPmAb4UiuJ5cdi1JmjLgfOi1mp-8eOT3hyPJGF-eM_Y_uMe8jGnhKRxFjRf80oY_kRRT6NWCIKhfVDxaLk9uSo6uWnxxmL3PCeQc45jHfhkPG4v8T0rbfcUZDBk\\",\\"q\\":\\"67iL9zdUx744x9WkfNKeIUNb4pO7QjCxwH1u-sEf_J5_Vtt8ct6vcDit7oSqVr9mlE_klpEAnxYQQNXndpN9vRHZMb1JWNkUa5CQXFBxPLL39gbKKOOJG7KDTMWF8BR3SeFlKdyoqSyf5C746dFHl9rywTAOkdSpCf1F7BnYxL8\\",\\"qi\\":\\"h96KLTIDphk0opY3dWep1ooMDTLHdawJ_3B2jOamhUv_feoHkdH6VAxGQETm-5_PMcOijHDIpzsWlZ54C9JhXlw6vEDHsR3FQAvcVWyo6M4XdefwoC4FgTKwJT3GsU71bhK2Q-W-1oaCMDVsg6IIGDzbMx6c-MuGdvN2E4BFBvU\\",\\"use\\":\\"enc\\"}"},"state":"created","created":1666365527}\n'
Figure A.144
A.13.4. Start this subscription
A subscription is started by updating its state to start''. State transitions needed are created'’ → approved'' → ready'’ → started''. State becomes approved'’ when the code'' received by email at creation time is used in the PATCH'’. Status becomes ``ready'’ when the resource-uri is available as well.
Example: 5.4
> Approve subscription (PATCH).
myobj = {
# use here the code you received by email for this subscription id.
"code": "578Z8C"
}
response = requests.patch(endpoint_subscriptions + "/" + str(id), json = myobj,
verify=bool(verify_ssl),
headers={'Accept': 'application/json', 'Authorization': 'Bearer ' + access_token})
response
Figure A.145
<Response [400]>
Figure A.146
Example: 5.5
> Start subscription (PATCH).
Use PATCH to change the subscription from state ready'' → started'’.
myobj = {
"state": "start"
}
response = requests.patch(endpoint_subscriptions + "/" + str(id), json = myobj,
verify=bool(verify_ssl),
headers={'Accept': 'application/json', 'Authorization': 'Bearer ' + access_token})
response
Figure A.147
<Response [400]>
Figure A.148
Check that state is updated to ``start'’.
response = requests.get(endpoint_subscriptions + "/" + str(id),
verify=bool(verify_ssl),
headers={'Accept': 'application/json', 'Authorization': 'Bearer ' + access_token})
response.text
Figure A.149
'{"name":"pySubscription","delivery":"mailto:john.doe@company.com","schedule":"* * */1 * *","resources-uri":"https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items","expires":1759104237,"sec-opts":{"x-ogc-callback-key":"string","public-key":"{\\"d\\":\\"GTSwJzYovf79k7JB6gW3ziiTy_VnFHL2PFiVcTTRs_TnNEN0_AgoUPQZ0U2gKM1L2vTiNqbAg1Wzs3CYYf_TJGCELVbikG82x5Pum0yxN3UDHvHXESum8OKdjIuGhhOw1kWbAUD9-haQIKpMUnLy432IC3TLlZ-f1twS-0YQR3zk2qdtsiQF5rIqFps0bjjcJid4F9ifxTQqeeYhaAkdh-SBmO2kikwkA_g4PH3fQdfM57R4iuy32TF6u-uLT5p54qRuQ-wTDZ0B_vzpQZ7jVc6skNvuW-XNmTng2hY9mSaeLoKiOf74QZyIKBSywKgAresxKfVnBuEppQEvdZKbSQ\\",\\"dp\\":\\"YKPZt__yim_TNerZ0inwls-hmmsv4BKzKyZTN2cl7VN_ruw4YCPQXXO5S4CzmUW8NO5g0icih1UHDwTLddTx-4w7nSlMJIv8sY6r46dAKMHtYju1HtF3ayrJoT6M9J5Re4tnLZx0Ns-rLxndbwCzFgS3viJPeaYKZkMUvwRzhbE\\",\\"dq\\":\\"FhWIJ3UroDsWHsLJUlh5MCybYzLsDFt7i8k0qJGHaad_zqdplWl_jkgBI6OSQeZUufhyNhkHsd_jTe-8a8ONuDT_4EUXphdQbnNw0vVGZqVtzcL9Fa-bnNiwrHSlA8UnF-jiDXX65z6jDEHKWD2fM37z112lP8xoueLcti4FvQk\\",\\"e\\":\\"AQAB\\",\\"kid\\":\\"clikid\\",\\"kty\\":\\"RSA\\",\\"n\\":\\"tt88JhkKs-d7tZy7mZGcXMvIQs2UWdufE5K3BfQ-6vvyfI3eHoRKpCqlLVBmSCD39pyv8ML0n7r5ZWUPZpeMJtqaJ_YPMwUX1TBgfEKwcI3ZQguXZbfvPOnpbVBx7zgnPYsdYT-nSeIu19I7A_-3ex29NjIbNXW7l2xEu__a5lJCDZjhXRu0Oy8blZz28WY20lSC79W0FB-gKlaNM_zZvBMWanTGg3IxmZf_YldZjvli37UVzROdDbSdlK02s9FiDQFbyGmpp25BCx5wn76Jue79Lxmo4j_OXqOwkNYx-gTYXb1bNIC5SMz-OYRXmSZEO-rtoM53bk08UrEZ4Qsqpw\\",\\"p\\":\\"xprCRD94cvlh5wjgXQWX3z_KZGIl0fE5H4dAebeiRgtPmuI2RPmAb4UiuJ5cdi1JmjLgfOi1mp-8eOT3hyPJGF-eM_Y_uMe8jGnhKRxFjRf80oY_kRRT6NWCIKhfVDxaLk9uSo6uWnxxmL3PCeQc45jHfhkPG4v8T0rbfcUZDBk\\",\\"q\\":\\"67iL9zdUx744x9WkfNKeIUNb4pO7QjCxwH1u-sEf_J5_Vtt8ct6vcDit7oSqVr9mlE_klpEAnxYQQNXndpN9vRHZMb1JWNkUa5CQXFBxPLL39gbKKOOJG7KDTMWF8BR3SeFlKdyoqSyf5C746dFHl9rywTAOkdSpCf1F7BnYxL8\\",\\"qi\\":\\"h96KLTIDphk0opY3dWep1ooMDTLHdawJ_3B2jOamhUv_feoHkdH6VAxGQETm-5_PMcOijHDIpzsWlZ54C9JhXlw6vEDHsR3FQAvcVWyo6M4XdefwoC4FgTKwJT3GsU71bhK2Q-W-1oaCMDVsg6IIGDzbMx6c-MuGdvN2E4BFBvU\\",\\"use\\":\\"enc\\"}"},"state":"created","created":1666365527}\n'
Figure A.150
A.13.5. Delete the subscription
Example: 5.6
> Remove subscription (DELETE).
# id = 170
response = requests.delete(endpoint_subscriptions + "/" + str(id),
verify=bool(verify_ssl),
headers={'Authorization': 'Bearer ' + access_token})
response
Figure A.151
<Response [204]>
Figure A.152
A.13.6. Get updated subscription list
response = requests.get(endpoint_subscriptions,
verify=bool(verify_ssl),
headers={'Accept': 'application/dcs+geo', 'Authorization': 'Bearer ' + access_token})
response.text
Figure A.153
'[{"id":213,"name":"pySubscription","delivery":"mailto:john.doe@company.com","schedule":"* * */1 * *","resources-uri":"https://ogc.demo.secure-dimensions.de/pycsw/collections/metadata:main/items","expires":1759104237,"sec-opts":{"x-ogc-callback-key":"string","public-key":"{\\"d\\":\\"_rw1-M-daUJgW80IuhltH3uFpv0lttiSbeIa_A1Gn75mc48w3kaTXH0RHpC6whAz88N0fKxbJwDbmsUs6PJ1BvkZJTu04nOtlTF0GuWj7uhAY5S-zj-Gq5odBUyi72S8aSOpKMFOeiwcYZxWs-L4_attPMJSDgMxTzHtpTjmZvTSSESuD-KYkJPTbvvA7UVBIt43usuNTUhxDVcQY-emGTAYsicOeZGWFGWYo24LjX1RKP95IztCa0Mw2MPEPE8rA1muvfkk3MnhntdOLRTlw0TexpAwNGn0_2hy80uFwD6vRPOCzocLZT0FdllgOLYzr4JwXE_G1MIVIgTXnwZB\\",\\"dp\\":\\"P60BtUnExG1zxR6obqGnP5z2yCGtp0LXjrg5tFJa6H6OPv_wALbPSfEf67Dj8IvQTmZnPDVmOT21GRbB2fV7LtqfHMpt0-bTMHlwBkR0BJo47BF0PHwnX_MtepHzvYA36roXkimS_8Oc_PR4DqPa0up3DbsO6Bid0xwBRkcYXCU\\",\\"dq\\":\\"TQ466gqzsiLTQK3VTKg1J-zY4Gp-xocHHPALnrrj96aeHUWMb09zArFxKIMLpzDHs24DN0PxyVC2h6hjQAP-dheSYFRwcQOF5uj1NkfFvyTf19hTzP1pBKTTNm9exMSwAEXel4bJlfqFs89k6NGsFTEuhVnavf7eY7FjRfv-itU\\",\\"e\\":\\"AQAB\\",\\"kid\\":\\"clikid\\",\\"kty\\":\\"RSA\\",\\"n\\":\\"2qBsAlkltTmv-oMoLVsay9B-CAo_3ie5fi8Mg9Aph72w9uR5gEcfz6A-rsPLMH8buNwuUIoKo73NRc-glXBA9XUSvNn86dJiHTEyKAZm9ybm3_qZGSDl0KlgqDNx-qGOi2r5JSN3AQYlAvLi1_qSaIVDOwKQJY7NZR1C7Z2l7jqQfSxEoIRSt_K57Gt9wo7GIHcuOnzr30zTYg1UzSQx_b8bxdoUDWrNgCJYw9NuwmvRkjaBJr___bMbKz0LnqlwfI3eHqCYb8bfcR9YdL17f4vIAtkk_XWXjB-hldoPwQiVpBno4Bz14PXaDFB4p8d3BcrLwKz3ESy6sW6CiZmIQw\\",\\"p\\":\\"-uTjBeriYAs1L11usnn1B763ki0flOK5Lcj_r2nFZ1-qwd52fZqSoIkSKJ06zPmIkYSuVDLzfzTP4mKj_NmWBakxmLAdR2jIsGQ8BU1IdkyzrhgrL7vYmbQ0mlVFe3tphT2lWbOV8fkGJlijMYMEHwxby6Qn4XTsxbYZD6CtakU\\",\\"q\\":\\"3xNtcipbvk3RUDBgjoxhb1HzKvzNSDDTYGf0C2HNl9snjjvF4mp2CfTe7wRd7i7N5_R-zfB_KoZ6XH2aAKuCRiKb61wsHohG3QtJhMtqiSIG4jcuW1cqVt6X4uYSdPfYEcxI-kslTcfQ8ChycZDTaMxRORycgb-Xct5P1JFAVOc\\",\\"qi\\":\\"H7sbm1Vp7BlX5gihmu5s4sA3H2nf-NyG6M01pYBcR5RpyaouwEQEVQK71JGm1VWt3jYfVQ79wNHzYZ6UYVOiLV-U4oFRXz2wAkQMjQvQrQrrdxujlgQ8hRj_S_6ogQnFnxAGd8onm2cdX1LZGoEPCfsEy1QLjUHs_fwCAcq1HNA\\",\\"use\\":\\"enc\\"}"},"state":"created","created":1666365965}]\n'
Figure A.154
Annex B
(informative)
Revision History
Date | Release | Author | Primary clauses modified | Description |
---|---|---|---|---|
2022-06-02 | 0.1 | Y. Coene | all | Initial draft version |
2022-10-21 | 0.8 | Y. Coene | all | Version addressing review comments from Carl Reed and agentschap Digitaal Vlaanderen. |
Bibliography
[1] OAuth 2.0 Demonstrating Proof-of-Possession at the Application Layer (DPoP), IETF draft, 2022 : https://datatracker.ietf.org/doc/html/draft-ietf-oauth-dpop-11
[2] OAuth 2.0 Security Best Current Practice, IETF draft, 2022 : https://www.ietf.org/archive/id/draft-ietf-oauth-security-topics-20.txt
[3] IOC TF: Technical Guidance for INSPIRE Discovery Services, IOC Task Force for Network Services, Issue 3.1.1, 2011, https://inspire.ec.europa.eu/documents/technical-guidance-implementation-inspire-discovery-services-0
[4] INSPIRE MIG: Technical Guidance for the implementation of INSPIRE dataset and service metadata based on ISO/TS 19139:2007, 2017 https://inspire.ec.europa.eu/id/document/tg/metadata-iso19139
[5] INFORMATIE VLAANDEREN: Richtlijn GDI-Vlaanderen Best Practices voor Metadata V2.0, 2020 https://www.geopunt.be/~/media/geopunt/geowijzer/metadata/documenten/aan_de_slag_2020/gdi_vl_bestpractices_v0_18.pdf
[6] Geonovum: Nederlands metadata profiel op ISO 19115 voor geografie versie 2.1.0, 2020 https://docs.geostandaarden.nl/md/mdprofiel-iso19115
[7] IETF: JWS Clear Text JSON Signature Option (JWS/CT), 2022 https://www.ietf.org/id/draft-jordan-jws-ct-08.html
[8] OGC: INSPIRE and OGC APIs — Part 1: Modernising INSPIRE — https://www.ogc.org/blog/4603.