def signIn(self, user: str, pwd: str, refresh_token: bool = False) -> bool: """ Checks if the current session is authenticated. If not, a token is retrieved (if not available yet) and its value is set in the session X-XSRF-TOKEN header. Finally, the user will be signed in to GeoNetwork. :param user: The basic authentication user name. :param pwd: The basic authentication password. :param refresh_token: If True (default = False), the token will be refreshed. :returns: True if sign in was successful. """ if GeonetworkSession.HEADER_TOKEN in self.headers and self.signedIn and not refresh_token: # We are still signed in: no need to do it again return True if not (user and pwd): return False auth = {'username': user, 'password': pwd} if GeonetworkSession.HEADER_TOKEN not in self.headers or refresh_token: # Obtain cookie token if there is none or we want to refresh it token = self.getToken() if token: # Update session headers with an X-XSRF-TOKEN self.headers[GeonetworkSession.HEADER_TOKEN] = token auth['_csrf'] = self.headers[GeonetworkSession.HEADER_TOKEN] headers = {'Accept': 'application/html'} feedback.logInfo(f'POST {self._signin_url}') # Note: it is **extremely** important to NOT allow redirects here! # Disallowing redirects will sign us in successfully and return a 302 (Found). # A redirect however will result in a 403 (Access Denied), even with valid credentials. result = self.post(self._signin_url, data=auth, headers=headers, allow_redirects=False) status = result.status_code if status >= 400: prefix = f"Failed to sign in to {self._signin_url}" if status == 403: if not refresh_token: # Retry 1 more time with a refreshed token feedback.logWarning(f"{prefix}: retrying with new token") return self.signIn(user, pwd, True) feedback.logError( f"{prefix}: access denied to user '{user}' ({status})") elif status == 401: feedback.logError( f"{prefix}: user '{user}' not authorized (bad credentials)" ) else: feedback.logError( f"{prefix}: server returned {status} (please check server logs)" ) return False return True
def _createMef(uuid, md_filename, mef_filename, thumb_filename): feedback.logInfo(f"Creating MEF file {mef_filename}") z = zipfile.ZipFile(mef_filename, "w") z.write(md_filename, os.path.join(uuid, "metadata", os.path.basename(md_filename))) z.write(thumb_filename, os.path.join(uuid, "public", os.path.basename(thumb_filename))) info = _getInfoXmlContent(uuid, thumb_filename) z.writestr(os.path.join(uuid, "info.xml"), info) z.close()
def loadConfiguredServers() -> bool: """ Reads all configured servers from the QGIS settings and initializes them. """ # Read QGIS Bridge server settings string server_config = QSettings().value(SERVERS_SETTING) if not server_config: feedback.logInfo(f"Could not find existing {meta.getAppName()} setting '{SERVERS_SETTING}'") return False # Deserialize JSON and initialize servers return deserializeServers(server_config)
def getToken(self): """ Requests a session token using POST and reads its value from the cookie. """ headers = {'Content-Type': 'application/xml'} feedback.logInfo(f'POST {self._token_url}') # Note: it is expected that this returns a 403 self.post(self._token_url, headers=headers) token = self.cookies.get(GeonetworkSession.COOKIE_TOKEN) if not token: feedback.logError( f'Did not receive a {GeonetworkSession.COOKIE_TOKEN} cookie!') return token
def signedIn(self) -> bool: """ Returns True if the session is authenticated (i.e. the user has been signed in). """ headers = {'Accept': 'application/xml'} feedback.logInfo(f'GET {self._token_url}') result = self.get(self._token_url, headers=headers) if result.status_code < 400: return parseMe(result) # This should not happen (even unauthenticated responses should return a 200), but we have to handle it feedback.logError( f'Failed to query {self._token_url}: server returned {result.status_code}' ) return False
def _transformMetadata(filename, uuid, api_url, wms, wfs, layer_name): def _ns(n): return f"{{http://www.isotc211.org/2005/gmd}}{n}" def _addServiceElement(root_element, md_layer, service_url, service_type): trans = ET.SubElement(root_element, _ns("transferOptions")) dtrans = ET.SubElement(trans, _ns("MD_DigitalTransferOptions")) online = ET.SubElement(dtrans, _ns("onLine")) cionline = ET.SubElement(online, _ns("CI_OnlineResource")) linkage = ET.SubElement(cionline, _ns("linkage")) url = ET.SubElement(linkage, _ns("URL")) url.text = service_url protocol = ET.SubElement(cionline, _ns("protocol")) cs = ET.SubElement( protocol, "{http://www.isotc211.org/2005/gco}CharacterString") cs.text = f"OGC:{service_type.upper()}" name = ET.SubElement(cionline, _ns("name")) csname = ET.SubElement( name, "{http://www.isotc211.org/2005/gco}CharacterString") csname.text = md_layer iso_filename = tempFileInSubFolder("metadata.xml") feedback.logInfo(f"Creating metadata export file {iso_filename}") out_dom = _transformDom(filename, QMD_TO_ISO19139_XSLT) for ident in out_dom.iter(_ns("fileIdentifier")): ident[0].text = uuid if wms is not None: for root in out_dom.iter(_ns("MD_Distribution")): _addServiceElement(root, layer_name, wms, "wms") if wfs is not None: for root in out_dom.iter(_ns("MD_Distribution")): _addServiceElement(root, layer_name, wfs, "wfs") for root in out_dom.iter(_ns("MD_DataIdentification")): overview = ET.SubElement(root, _ns("graphicOverview")) browse_graphic = ET.SubElement(overview, _ns("MD_BrowseGraphic")) file = ET.SubElement(browse_graphic, _ns("fileName")) cs = ET.SubElement( file, "{http://www.isotc211.org/2005/gco}CharacterString") thumbnail_url = f"{api_url}/records/{uuid}/attachments/thumbnail.png" cs.text = thumbnail_url _writeDom(out_dom, iso_filename) return iso_filename
def _loadMetadataFromFgdcXml(layer, filename): iso_filename = tempFileInSubFolder("fromfgdc.xml") feedback.logInfo(f"Exporting FGDC metadata to {iso_filename}") _convertMetadata(filename, iso_filename, FGDC_TO_ISO19115) _loadMetadataFromEsriXml(layer, iso_filename)
def _loadMetadataFromWrappingEsriXml(layer, filename): iso_filename = tempFileInSubFolder("fromesri.xml") feedback.logInfo(f"Exporting Wrapping-ISO19115 metadata to {iso_filename}") _convertMetadata(filename, iso_filename, WRAPPING_ISO19115_TO_ISO19139_XSLT) _loadMetadataFromIsoXml(layer, iso_filename)
def _loadMetadataFromIsoXml(layer, filename): qmd_filename = tempFileInSubFolder("fromiso.qmd") feedback.logInfo(f"Exporting ISO19193 metadata to {qmd_filename}") _convertMetadata(filename, qmd_filename, ISO19139_TO_QMD_XSLT) layer.loadNamedMetadata(qmd_filename)