zoom: allow / in user and password db args MP-592
[metaproxy-moved-to-github.git] / src / filter_zoom.cpp
index 69a25b8..67eb01e 100644 (file)
@@ -52,6 +52,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include <yaz/tokenizer.h>
 #include <yaz/zoom.h>
 #include <yaz/otherinfo.h>
+#include <yaz/match_glob.h>
 
 namespace mp = metaproxy_1;
 namespace yf = mp::filter;
@@ -62,6 +63,7 @@ namespace metaproxy_1 {
           public:
             std::string authentication;
             std::string authenticationMode;
+            std::string contentAuthentication;
             std::string cfAuth;
             std::string cfProxy;
             std::string cfSubDB;
@@ -80,6 +82,7 @@ namespace metaproxy_1 {
             std::string sortStrategy;
             std::string extraArgs;
             std::string rpn2cql_fname;
+            std::string retry_on_failure;
             bool use_turbomarc;
             bool piggyback;
             CCL_bibset ccl_bibset;
@@ -103,6 +106,7 @@ namespace metaproxy_1 {
             xmlDoc *explain_doc;
             std::string m_proxy;
             cql_transform_t cqlt;
+            std::string retry_on_failure;
         public:
             Backend();
             ~Backend();
@@ -218,7 +222,9 @@ namespace metaproxy_1 {
             std::string torus_searchable_url;
             std::string torus_content_url;
             std::string torus_auth_url;
+            std::string torus_allow_ip;
             std::string default_realm;
+            std::string torus_auth_hostname;
             std::map<std::string,std::string> fieldmap;
             std::string xsldir;
             std::string file_path;
@@ -488,6 +494,7 @@ yf::Zoom::Searchable::Searchable(CCL_bibset base)
     piggyback = true;
     use_turbomarc = true;
     sortStrategy = "embed";
+    retry_on_failure = "1"; // existing default (should have been false)
     ccl_bibset = ccl_qual_dup(base);
 }
 
@@ -590,6 +597,11 @@ yf::Zoom::SearchablePtr yf::Zoom::Impl::parse_torus_record(const xmlNode *ptr)
             s->authenticationMode = mp::xml::get_text(ptr);
         }
         else if (!strcmp((const char *) ptr->name,
+                         "contentAuthentication"))
+        {
+            s->contentAuthentication = mp::xml::get_text(ptr);
+        }
+        else if (!strcmp((const char *) ptr->name,
                          "cfAuth"))
         {
             s->cfAuth = mp::xml::get_text(ptr);
@@ -699,6 +711,11 @@ yf::Zoom::SearchablePtr yf::Zoom::Impl::parse_torus_record(const xmlNode *ptr)
         }
         else if (!strcmp((const char *) ptr->name, "rpn2cql"))
             s->rpn2cql_fname = mp::xml::get_text(ptr);
+        else if (!strcmp((const char *) ptr->name,
+                          "retryOnFailure"))
+        {
+            s->retry_on_failure = mp::xml::get_text(ptr);
+        }
     }
     return s;
 }
@@ -776,8 +793,12 @@ void yf::Zoom::Impl::configure(const xmlNode *ptr, bool test_only,
                     torus_content_url = mp::xml::get_text(attr->children);
                 else if (!strcmp((const char *) attr->name, "auth_url"))
                     torus_auth_url = mp::xml::get_text(attr->children);
+                else if (!strcmp((const char *) attr->name, "allow_ip"))
+                    torus_allow_ip = mp::xml::get_text(attr->children);
                 else if (!strcmp((const char *) attr->name, "realm"))
                     default_realm = mp::xml::get_text(attr->children);
+                else if (!strcmp((const char *) attr->name, "auth_hostname"))
+                    torus_auth_hostname = mp::xml::get_text(attr->children);
                 else if (!strcmp((const char *) attr->name, "xsldir"))
                     xsldir = mp::xml::get_text(attr->children);
                 else if (!strcmp((const char *) attr->name, "element_transform"))
@@ -1119,8 +1140,6 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases(
     else
         torus_db = database;
 
-    std::string authentication;
-    std::string content_authentication;
     std::string content_proxy;
     std::string realm = session_realm;
     if (realm.length() == 0)
@@ -1131,6 +1150,7 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases(
     const char *param_content_user = 0;
     const char *param_content_password = 0;
     const char *param_nocproxy = 0;
+    const char *param_retry = 0;
     int no_parms = 0;
 
     char **names;
@@ -1166,6 +1186,8 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases(
             content_proxy = value;
         else if (!strcmp(name, "nocproxy"))
             param_nocproxy = value;
+        else if (!strcmp(name, "retry"))
+            param_retry = value;
         else if (!strcmp(name, "proxy"))
         {
             char **dstr;
@@ -1232,19 +1254,6 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases(
         return m_backend;
     }
 
-    if (param_user)
-    {
-        authentication = std::string(param_user);
-        if (param_password)
-            authentication += "/" + std::string(param_password);
-    }
-    if (param_content_user)
-    {
-        content_authentication = std::string(param_content_user);
-        if (param_content_password)
-            content_authentication += "/" + std::string(param_content_password);
-    }
-
     if (torus_db.compare("IR-Explain---1") == 0)
         return explain_search(package, database, error, addinfo, odr, torus_url,
                               torus_db, realm);
@@ -1426,6 +1435,11 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases(
     b->m_frontend_database = database;
     b->enable_cproxy = param_nocproxy ? false : true;
 
+    if (param_retry)
+        b->retry_on_failure = param_retry;
+    else
+        b->retry_on_failure = b->sptr->retry_on_failure;
+
     if (sptr->query_encoding.length())
         b->set_option("rpnCharset", sptr->query_encoding);
 
@@ -1441,8 +1455,20 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases(
                                         maximumRecords > 0 */
     b->set_option("piggyback", sptr->piggyback ? "1" : "0");
 
-    if (authentication.length() == 0)
-        authentication = sptr->authentication;
+    std::string authentication = sptr->authentication;
+    if (param_user)
+    {
+        authentication = std::string(param_user);
+        if (param_password)
+            authentication += "/" + std::string(param_password);
+    }
+    std::string content_authentication = sptr->contentAuthentication;
+    if (param_content_user)
+    {
+        content_authentication = std::string(param_content_user);
+        if (param_content_password)
+            content_authentication += "/" + std::string(param_content_password);
+    }
 
     if (proxy.length() == 0)
         proxy = sptr->cfProxy;
@@ -1452,7 +1478,17 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases(
     {
         // A CF target
         b->set_option("user", sptr->cfAuth);
-        if (authentication.length())
+        if (param_user)
+        {
+            out_names[no_out_args] = "user";
+            out_values[no_out_args++] = odr_strdup(odr, param_user);
+            if (param_password)
+            {
+                out_names[no_out_args] = "password";
+                out_values[no_out_args++] = odr_strdup(odr, param_password);
+            }
+        }
+        else if (authentication.length())
         {
             size_t found = authentication.find('/');
             if (found != std::string::npos)
@@ -2075,7 +2111,7 @@ static bool wait_conn(COMSTACK cs, int secs)
     struct yaz_poll_fd pfd;
 
     yaz_poll_add(pfd.input_mask, yaz_poll_except);
-    if (cs->io_pending && CS_WANT_WRITE)
+    if (cs->io_pending & CS_WANT_WRITE)
         yaz_poll_add(pfd.input_mask, yaz_poll_write);
     if (cs->io_pending & CS_WANT_READ)
         yaz_poll_add(pfd.input_mask, yaz_poll_read);
@@ -2147,7 +2183,8 @@ bool yf::Zoom::Frontend::retry(mp::Package &package,
         error = YAZ_BIB1_PROXY_FAILURE;
         *addinfo = odr_strdup(odr, b->m_proxy.c_str());
     }
-    else if (same_retries == 0 && proxy_retries == 0)
+    else if (b && b->retry_on_failure.compare("0")
+             && same_retries == 0 && proxy_retries == 0)
     {
         log_diagnostic(package, error, *addinfo);
         same_retries++;
@@ -2622,13 +2659,31 @@ void yf::Zoom::Frontend::auth(mp::Package &package, Z_InitRequest *req,
     }
 
     Z_OtherInformation **oi = &req->otherInfo;
-    const char *ip =
+    const char *ip_cstr =
         yaz_oi_get_string_oid(oi, yaz_oid_userinfo_client_ip, 1, 0);
-    if (!ip)
-        ip = package.origin().get_address().c_str();
+    std::string ip;
+    if (ip_cstr)
+        ip = ip_cstr;
+    else
+        ip = package.origin().get_address();
 
-    yaz_log(YLOG_LOG, "IP=%s", ip);
+    yaz_log(YLOG_LOG, "IP=%s", ip.c_str());
 
+    {
+        NMEM nmem = nmem_create();
+        char **darray;
+        int i, num;
+        nmem_strsplit_blank(nmem, m_p->torus_allow_ip.c_str(), &darray, &num);
+        for (i = 0; i < num; i++)
+        {
+            yaz_log(YLOG_LOG, "check against %s+%s", darray[i], ip.c_str());
+            if (yaz_match_glob(darray[i], ip.c_str()))
+                break;
+        }
+        nmem_destroy(nmem);
+        if (i < num)
+            return;  /* allow this IP */
+    }
     std::string torus_query;
     int failure_code;
 
@@ -2643,6 +2698,13 @@ void yf::Zoom::Frontend::auth(mp::Package &package, Z_InitRequest *req,
         torus_query = "ipRanges encloses/net.ipaddress \"";
         torus_query += escape_cql_term(std::string(ip));
         torus_query += "\"";
+
+        if (m_p->torus_auth_hostname.length())
+        {
+            torus_query += " AND hostName == \"";
+            torus_query += escape_cql_term(m_p->torus_auth_hostname);
+            torus_query += "\"";
+        }
         failure_code = YAZ_BIB1_INIT_AC_BLOCKED_NETWORK_ADDRESS;
     }