def proxy(self) -> Response: if self.user is not None: # We have a user logged in. We need to set group_id and # possible layer_name in the params. We set layer_name # when either QUERY_PARAMS or LAYERS is set in the # WMS params, i.e. for GetMap and GetFeatureInfo # requests. For GetLegendGraphic requests we do not # send layer_name, but MapServer should not use the DATA # string for GetLegendGraphic. roles = self.user.roles if len(roles): if self.ogc_server.auth == main.OGCSERVER_AUTH_STANDARD: self.params["role_ids"] = \ "-1" if len(roles) == 0 else ",".join([str(r.id) for r in roles]) # In some application we want to display the features owned by a user # than we need his id. self.params["user_id"] = self.user.id # pragma: no cover else: # pragma nocover log.warning("The user '%s' has no role", self.user.username) # do not allows direct variable substitution for k in list(self.params.keys()): if k[:2].capitalize() == "S_": log.warning( "Direct substitution not allowed ({0!s}={1!s}).".format( k, self.params[k])) del self.params[k] # add functionalities params self.params.update(get_mapserver_substitution_params(self.request)) # get method method = self.request.method # we want the browser to cache GetLegendGraphic and # DescribeFeatureType requests use_cache = False if method == "GET": # For GET requests, params are added only if the self.request # parameter is actually provided. if "request" not in self.lower_params: self.params = {} # pragma: no cover else: if self.ogc_server.type != main.OGCSERVER_TYPE_QGISSERVER or \ "user_id" not in self.params: use_cache = self.lower_params["request"] in ( "getlegendgraphic", ) # no user_id and role_id or cached queries if use_cache and "user_id" in self.params: del self.params["user_id"] if use_cache and "role_ids" in self.params: del self.params["role_ids"] if "service" in self.lower_params and self.lower_params[ "service"] == "wfs": _url = self._get_wfs_url() else: _url = self._get_wms_url() else: # POST means WFS _url = self._get_wfs_url() cache_control = PRIVATE_CACHE if method == "GET" and \ "service" in self.lower_params and \ self.lower_params["service"] == "wms": if self.lower_params["request"] in ("getmap", "getfeatureinfo"): cache_control = NO_CACHE elif self.lower_params["request"] == "getlegendgraphic": cache_control = PUBLIC_CACHE elif method == "GET" and \ "service" in self.lower_params and \ self.lower_params["service"] == "wfs": if self.lower_params["request"] == "getfeature": cache_control = NO_CACHE elif method != "GET": cache_control = NO_CACHE headers = self._get_headers() # Add headers for Geoserver if self.ogc_server.auth == main.OGCSERVER_AUTH_GEOSERVER and \ self.user is not None: headers["sec-username"] = self.user.username headers["sec-roles"] = ";".join([r.name for r in roles]) response = self._proxy_callback(self.user, cache_control, url=_url, params=self.params, cache=use_cache, headers=headers, body=self.request.body) if self.lower_params.get("request") == "getmap" and \ not response.content_type.startswith('image/') and \ response.status_code < 400: response.status_code = 400 return response
async def _wms_getcap_cached( self, ogc_server: main.OGCServer ) -> Tuple[Optional[Url], Optional[bytes], Set[str]]: errors: Set[str] = set() url = get_url2(f"The OGC server '{ogc_server.name}'", ogc_server.url, self.request, errors) if errors or url is None: return url, None, errors # Add functionality params if ( ogc_server.auth == main.OGCSERVER_AUTH_STANDARD and ogc_server.type == main.OGCSERVER_TYPE_MAPSERVER ): url.add_query(get_mapserver_substitution_params(self.request)) url.add_query( { "SERVICE": "WMS", "VERSION": "1.1.1", "REQUEST": "GetCapabilities", "ROLE_IDS": "0", "USER_ID": "0", }, ) LOG.debug("Get WMS GetCapabilities for URL: %s", url) # Forward request to target (without Host Header) headers = dict(self.request.headers) # Add headers for Geoserver if ogc_server.auth == main.OGCSERVER_AUTH_GEOSERVER: headers["sec-username"] = "******" headers["sec-roles"] = "root" if url.hostname != "localhost" and "Host" in headers: headers.pop("Host") headers = restrict_headers(headers, self.headers_whitelist, self.headers_blacklist) try: content, content_type = await asyncio.get_event_loop().run_in_executor( None, get_http_cached, self.http_options, url, headers ) except Exception: error = f"Unable to GetCapabilities from URL {url}" errors.add(error) LOG.error(error, exc_info=True) return url, None, errors # With wms 1.3 it returns text/xml also in case of error :-( if content_type.split(";")[0].strip() not in [ "application/vnd.ogc.wms_xml", "text/xml", ]: error = ( f"GetCapabilities from URL '{url}' returns a wrong Content-Type: {content_type}\n" f"{content.decode()}" ) errors.add(error) LOG.error(error) return url, None, errors return url, content, errors
async def _wms_getcap_cached(self, ogc_server, _): """ _ is just for cache on the role id """ errors: Set[str] = set() url = get_url2("The OGC server '{}'".format(ogc_server.name), ogc_server.url, self.request, errors) if errors or url is None: # pragma: no cover return url, None, errors # Add functionality params sparams = get_mapserver_substitution_params(self.request) url = add_url_params(url, sparams) url = add_url_params( url, { "SERVICE": "WMS", "VERSION": "1.1.1", "REQUEST": "GetCapabilities", "ROLE_ID": "0", "USER_ID": "0", }, ) LOG.debug("Get WMS GetCapabilities for url: %s", url) # Forward request to target (without Host Header) headers = dict(self.request.headers) # Add headers for Geoserver if ogc_server.auth == main.OGCSERVER_AUTH_GEOSERVER: headers["sec-username"] = "******" headers["sec-roles"] = "root" if urllib.parse.urlsplit( url ).hostname != "localhost" and "Host" in headers: # pragma: no cover headers.pop("Host") try: response = await asyncio.get_event_loop().run_in_executor( None, get_http_cached, self.http_options, url, headers) except Exception: # pragma: no cover error = "Unable to GetCapabilities from URL {}".format(url) errors.add(error) LOG.error(error, exc_info=True) return url, None, errors if not response.ok: # pragma: no cover error = "GetCapabilities from URL {} return the error: {:d} {}".format( url, response.status_code, response.reason) errors.add(error) LOG.error(error) return url, None, errors # With wms 1.3 it returns text/xml also in case of error :-( if response.headers.get("Content-Type", "").split(";")[0].strip() not in [ "application/vnd.ogc.wms_xml", "text/xml", ]: error = "GetCapabilities from URL {} returns a wrong Content-Type: {}\n{}".format( url, response.headers.get("Content-Type", ""), response.text) errors.add(error) LOG.error(error) return url, None, errors return url, response.content, errors
def proxy(self) -> Response: if self.user is None and "authentication_required" in self.request.params: LOG.debug("proxy() detected authentication_required") raise HTTPUnauthorized(headers={"WWW-Authenticate": 'Basic realm="Access to restricted layers"'}) # We have a user logged in. We need to set group_id and possible layer_name in the params. We set # layer_name when either QUERY_PARAMS or LAYERS is set in the WMS params, i.e. for GetMap and # GetFeatureInfo requests. For GetLegendGraphic requests we do not send layer_name, but MapServer # should not use the DATA string for GetLegendGraphic. if self.ogc_server.auth == main.OGCSERVER_AUTH_STANDARD: self.params["role_ids"] = ",".join([str(e) for e in get_roles_id(self.request)]) # In some application we want to display the features owned by a user than we need his id. self.params["user_id"] = self.user.id if self.user is not None else "-1" # pragma: no cover # Do not allows direct variable substitution for k in list(self.params.keys()): if k[:2].capitalize() == "S_": LOG.warning("Direct substitution not allowed (%s=%s).", k, self.params[k]) del self.params[k] # add functionalities params self.params.update(get_mapserver_substitution_params(self.request)) # get method method = self.request.method # we want the browser to cache GetLegendGraphic and # DescribeFeatureType requests use_cache = False if method == "GET": # For GET requests, params are added only if the self.request # parameter is actually provided. if "request" not in self.lower_params: self.params = {} # pragma: no cover else: if self.ogc_server.type != main.OGCSERVER_TYPE_QGISSERVER or "user_id" not in self.params: use_cache = self.lower_params["request"] in ("getlegendgraphic",) # no user_id and role_id or cached queries if use_cache and "user_id" in self.params: del self.params["user_id"] if use_cache and "role_ids" in self.params: del self.params["role_ids"] if "service" in self.lower_params and self.lower_params["service"] == "wfs": _url = self._get_wfs_url() else: _url = self._get_wms_url() else: # POST means WFS _url = self._get_wfs_url() cache_control = PRIVATE_CACHE if method == "GET" and "service" in self.lower_params and self.lower_params["service"] == "wms": if self.lower_params.get("request") in ("getmap", "getfeatureinfo"): cache_control = NO_CACHE elif self.lower_params.get("request") == "getlegendgraphic": cache_control = PUBLIC_CACHE elif method == "GET" and "service" in self.lower_params and self.lower_params["service"] == "wfs": if self.lower_params.get("request") == "getfeature": cache_control = NO_CACHE elif method != "GET": cache_control = NO_CACHE headers = self._get_headers() # Add headers for Geoserver if self.ogc_server.auth == main.OGCSERVER_AUTH_GEOSERVER: headers["sec-username"] = self.user.username headers["sec-roles"] = ";".join(get_roles_name(self.request)) response = self._proxy_callback( cache_control, url=_url, params=self.params, cache=use_cache, headers=headers, body=self.request.body, ) if ( self.lower_params.get("request") == "getmap" and not response.content_type.startswith("image/") and response.status_code < 400 ): response.status_code = 400 return response
def proxy(self) -> Response: if self.user is not None: # We have a user logged in. We need to set group_id and # possible layer_name in the params. We set layer_name # when either QUERY_PARAMS or LAYERS is set in the # WMS params, i.e. for GetMap and GetFeatureInfo # requests. For GetLegendGraphic requests we do not # send layer_name, but MapServer should not use the DATA # string for GetLegendGraphic. role = self.user.role if role is not None: if self._get_ogc_server().auth == OGCSERVER_AUTH_STANDARD: self.params["role_id"] = role.id # In some application we want to display the features owned by a user # than we need his id. self.params["user_id"] = self.user.id # pragma: no cover else: # pragma nocover log.warning("The user '%s' has no role", self.user.name) # do not allows direct variable substitution for k in list(self.params.keys()): if k[:2].capitalize() == "S_": log.warning("Direct substitution not allowed ({0!s}={1!s}).".format(k, self.params[k])) del self.params[k] # add functionalities params self.params.update(get_mapserver_substitution_params(self.request)) # get method method = self.request.method # we want the browser to cache GetLegendGraphic and # DescribeFeatureType requests use_cache = False if method == "GET": # For GET requests, params are added only if the self.request # parameter is actually provided. if "request" not in self.lower_params: self.params = {} # pragma: no cover else: use_cache = self.lower_params["request"] in ( "getcapabilities", "getlegendgraphic", "describelayer", "describefeaturetype", ) # no user_id and role_id or cached queries if use_cache and "user_id" in self.params: del self.params["user_id"] if use_cache and "role_id" in self.params: del self.params["role_id"] if "service" in self.lower_params and self.lower_params["service"] == "wfs": _url = self._get_wfs_url() else: _url = self._get_wms_url() else: # POST means WFS _url = self._get_wfs_url() cache_control = PRIVATE_CACHE if method == "GET" and \ "service" in self.lower_params and \ self.lower_params["service"] == "wms": if self.lower_params["request"] in ("getmap", "getfeatureinfo"): cache_control = NO_CACHE elif self.lower_params["request"] == "getlegendgraphic": cache_control = PUBLIC_CACHE elif method == "GET" and \ "service" in self.lower_params and \ self.lower_params["service"] == "wfs": if self.lower_params["request"] == "getfeature": cache_control = NO_CACHE elif method != "GET": cache_control = NO_CACHE role = None if self.user is None else self.user.role headers = self._get_headers() # Add headers for Geoserver if self._get_ogc_server().auth == OGCSERVER_AUTH_GEOSERVER and \ self.user is not None: headers["sec-username"] = self.user.username headers["sec-roles"] = role.name response = self._proxy_callback( role.id if role is not None else None, cache_control, url=_url, params=self.params, cache=use_cache, headers=headers, body=self.request.body ) return response