#50769 Ticket 50727 - correct mistaken options in filter validation patch
Closed 3 years ago by spichugi. Opened 4 years ago by firstyear.
firstyear/389-ds-base 50727-warn-strict-filter-validation  into  master

@@ -9,14 +9,29 @@ 

  

  import pytest

  import ldap

- from lib389.topologies import topology_st

+ from lib389.topologies import topology_st as topology_st_pre

  from lib389.dirsrv_log import DirsrvAccessLog

  from lib389._mapped_object import DSLdapObjects

  from lib389._constants import DEFAULT_SUFFIX

+ from lib389.extensibleobject import UnsafeExtensibleObjects

  

- def _check_value(inst_cfg, value):

+ def _check_value(inst_cfg, value, exvalue=None):

+     if exvalue is None:

+         exvalue = value

      inst_cfg.set('nsslapd-verify-filter-schema', value)

-     assert(inst_cfg.get_attr_val_utf8('nsslapd-verify-filter-schema') == value)

+     assert(inst_cfg.get_attr_val_utf8('nsslapd-verify-filter-schema') == exvalue)

+ 

+ @pytest.fixture(scope="module")

+ def topology_st(topology_st_pre):

+     raw_objects = UnsafeExtensibleObjects(topology_st_pre.standalone, basedn=DEFAULT_SUFFIX)

+     # Add an object that won't be able to be queried due to invalid attrs.

+     raw_objects.create(properties = {

+         "cn": "test_obj",

+         "a": "a",

+         "b": "b",

+         "uid": "foo"

+     })

+     return topology_st_pre

  

  

  @pytest.mark.ds50349
@@ -51,8 +66,14 @@ 

  

      initial_value = inst_cfg.get_attr_val_utf8('nsslapd-verify-filter-schema')

  

-     _check_value(inst_cfg, "on")

-     _check_value(inst_cfg, "warn")

+     # Check legacy values that may have been set

+     _check_value(inst_cfg, "on", "reject-invalid")

+     _check_value(inst_cfg, "warn", "process-safe")

+     _check_value(inst_cfg, "off")

+     # Check the more descriptive values

+     _check_value(inst_cfg, "reject-invalid")

+     _check_value(inst_cfg, "process-safe")

+     _check_value(inst_cfg, "warn-invalid")

      _check_value(inst_cfg, "off")

  

      # This should fail
@@ -85,7 +106,7 @@ 

      inst = topology_st.standalone

  

      # In case the default has changed, we set the value to warn.

-     inst.config.set("nsslapd-verify-filter-schema", "on")

+     inst.config.set("nsslapd-verify-filter-schema", "reject-invalid")

      raw_objects = DSLdapObjects(inst, basedn=DEFAULT_SUFFIX)

  

      # Check a good query has no errors.
@@ -104,9 +125,9 @@ 

  

  

  @pytest.mark.ds50349

- def test_filter_validation_warning(topology_st):

+ def test_filter_validation_warn_safe(topology_st):

      """Test that queries which are invalid, are correctly marked as "notes=F" in

-     the access log.

+     the access log, and return no entries or partial sets.

  

      :id: 8b2b23fe-d878-435c-bc84-8c298be4ca1f

      :setup: Standalone instance
@@ -122,7 +143,7 @@ 

      inst = topology_st.standalone

  

      # In case the default has changed, we set the value to warn.

-     inst.config.set("nsslapd-verify-filter-schema", "warn")

+     inst.config.set("nsslapd-verify-filter-schema", "process-safe")

      # Set the access log to un-buffered so we get it immediately.

      inst.config.set("nsslapd-accesslog-logbuffering", "off")

  
@@ -139,20 +160,93 @@ 

  

      # Check a good query has no warnings.

      r = raw_objects.filter("(objectClass=*)")

+     assert(len(r) > 0)

      r_s1 = access_log.match(".*notes=F.*")

      # Should be the same number of log lines IE 0.

      assert(len(r_init) == len(r_s1))

  

      # Check a bad one DOES emit a warning.

      r = raw_objects.filter("(a=a)")

+     assert(len(r) == 0)

      r_s2 = access_log.match(".*notes=F.*")

      # Should be the greate number of log lines IE +1

      assert(len(r_init) + 1 == len(r_s2))

  

      # Check a bad complex one does emit a warning.

      r = raw_objects.filter("(&(a=a)(b=b)(objectClass=*))")

+     assert(len(r) == 0)

      r_s3 = access_log.match(".*notes=F.*")

      # Should be the greate number of log lines IE +2

      assert(len(r_init) + 2 == len(r_s3))

  

+     # Check that we can still get things when partial

+     r = raw_objects.filter("(|(a=a)(b=b)(uid=foo))")

+     assert(len(r) == 1)

+     r_s4 = access_log.match(".*notes=F.*")

+     # Should be the greate number of log lines IE +2

+     assert(len(r_init) + 3 == len(r_s4))

+ 

+ 

+ @pytest.mark.ds50349

+ def test_filter_validation_warn_unsafe(topology_st):

+     """Test that queries which are invalid, are correctly marked as "notes=F" in

+     the access log, and uses the legacy query behaviour to return unsafe sets.

+ 

+     :id: 8b2b23fe-d878-435c-bc84-8c298be4ca1f

+     :setup: Standalone instance

+     :steps:

+         1. Search a well formed query

+         2. Search a poorly formed query

+         3. Search a poorly formed complex (and/or) query

+     :expectedresults:

+         1. No warnings

+         2. notes=F is present

+         3. notes=F is present

+     """

+     inst = topology_st.standalone

+ 

+     # In case the default has changed, we set the value to warn.

+     inst.config.set("nsslapd-verify-filter-schema", "warn-invalid")

+     # Set the access log to un-buffered so we get it immediately.

+     inst.config.set("nsslapd-accesslog-logbuffering", "off")

+ 

+     # Setup the query object.

+     # Now we don't care if there are any results, we only care about good/bad queries.

+     # To do this we have to bypass some of the lib389 magic, and just emit raw queries

+     # to check them. Turns out lib389 is well designed and this just works as expected

+     # if you use a single DSLdapObjects and filter. :)

+     raw_objects = DSLdapObjects(inst, basedn=DEFAULT_SUFFIX)

+ 

+     # Find any initial notes=F

+     access_log = DirsrvAccessLog(inst)

+     r_init = access_log.match(".*notes=(U,)?F.*")

+ 

+     # Check a good query has no warnings.

+     r = raw_objects.filter("(objectClass=*)")

+     assert(len(r) > 0)

+     r_s1 = access_log.match(".*notes=(U,)?F.*")

+     # Should be the same number of log lines IE 0.

+     assert(len(r_init) == len(r_s1))

+ 

+     # Check a bad one DOES emit a warning.

+     r = raw_objects.filter("(a=a)")

+     assert(len(r) == 1)

+     # NOTE: Unlike warn-process-safely, these become UNINDEXED and show in the logs.

+     r_s2 = access_log.match(".*notes=(U,)?F.*")

+     # Should be the greate number of log lines IE +1

+     assert(len(r_init) + 1 == len(r_s2))

+ 

+     # Check a bad complex one does emit a warning.

+     r = raw_objects.filter("(&(a=a)(b=b)(objectClass=*))")

+     assert(len(r) == 1)

+     r_s3 = access_log.match(".*notes=(U,)?F.*")

+     # Should be the greate number of log lines IE +2

+     assert(len(r_init) + 2 == len(r_s3))

+ 

+     # Check that we can still get things when partial

+     r = raw_objects.filter("(|(a=a)(b=b)(uid=foo))")

+     assert(len(r) == 1)

+     r_s4 = access_log.match(".*notes=(U,)?F.*")

+     # Should be the greate number of log lines IE +2

+     assert(len(r_init) + 3 == len(r_s4))

  

@@ -223,13 +223,15 @@ 

  

      switch (ftype) {

      case LDAP_FILTER_GE:

-         if (f->f_flags & SLAPI_FILTER_INVALID_ATTR) {

+         if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_WARN) {

              /*

               * REMEMBER: this flag is only set on WARN levels. If the filter verify

               * is on strict, we reject in search.c, if we ar off, the flag will NOT

               * be set on the filter at all!

               */

              slapi_pblock_set_flag_operation_notes(pb, SLAPI_OP_NOTE_FILTER_INVALID);

+         }

+         if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_UNDEFINE) {

              idl = idl_alloc(0);

          } else {

              idl = range_candidates(pb, be, type, bval, NULL, err, &sattr, allidslimit);
@@ -239,13 +241,15 @@ 

          goto done;

          break;

      case LDAP_FILTER_LE:

-         if (f->f_flags & SLAPI_FILTER_INVALID_ATTR) {

+         if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_WARN) {

              /*

               * REMEMBER: this flag is only set on WARN levels. If the filter verify

               * is on strict, we reject in search.c, if we ar off, the flag will NOT

               * be set on the filter at all!

               */

              slapi_pblock_set_flag_operation_notes(pb, SLAPI_OP_NOTE_FILTER_INVALID);

+         }

+         if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_UNDEFINE) {

              idl = idl_alloc(0);

          } else {

              idl = range_candidates(pb, be, type, NULL, bval, err, &sattr, allidslimit);
@@ -293,13 +297,15 @@ 

          ptr[1] = NULL;

          ivals = ptr;

  

-         if (f->f_flags & SLAPI_FILTER_INVALID_ATTR) {

+         if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_WARN) {

              /*

               * REMEMBER: this flag is only set on WARN levels. If the filter verify

               * is on strict, we reject in search.c, if we ar off, the flag will NOT

               * be set on the filter at all!

               */

              slapi_pblock_set_flag_operation_notes(pb, SLAPI_OP_NOTE_FILTER_INVALID);

+         }

+         if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_UNDEFINE) {

              idl = idl_alloc(0);

          } else {

              slapi_attr_assertion2keys_ava_sv(&sattr, &tmp, (Slapi_Value ***)&ivals, LDAP_FILTER_EQUALITY_FAST);
@@ -326,13 +332,15 @@ 

              slapi_ch_free((void **)&ivals);

          }

      } else {

-         if (f->f_flags & SLAPI_FILTER_INVALID_ATTR) {

+         if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_WARN) {

              /*

               * REMEMBER: this flag is only set on WARN levels. If the filter verify

               * is on strict, we reject in search.c, if we ar off, the flag will NOT

               * be set on the filter at all!

               */

              slapi_pblock_set_flag_operation_notes(pb, SLAPI_OP_NOTE_FILTER_INVALID);

+         }

+         if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_UNDEFINE) {

              idl = idl_alloc(0);

          } else {

              slapi_value_init_berval(&sv, bval);
@@ -382,13 +390,15 @@ 

      }

      slapi_pblock_get(pb, SLAPI_TXN, &txn.back_txn_txn);

  

-     if (f->f_flags & SLAPI_FILTER_INVALID_ATTR) {

+     if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_WARN) {

          /*

           * REMEMBER: this flag is only set on WARN levels. If the filter verify

           * is on strict, we reject in search.c, if we ar off, the flag will NOT

           * be set on the filter at all!

           */

          slapi_pblock_set_flag_operation_notes(pb, SLAPI_OP_NOTE_FILTER_INVALID);

+     }

+     if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_UNDEFINE) {

          idl = idl_alloc(0);

      } else {

          idl = index_read_ext_allids(pb, be, type, indextype_PRESENCE,
@@ -485,13 +495,15 @@ 

                          slapi_pblock_get(pb, SLAPI_PLUGIN_MR_KEYS, &keys)) {

                          /* something went wrong.  bail. */

                          break;

-                     } else if (f->f_flags & SLAPI_FILTER_INVALID_ATTR) {

+                     } else if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_WARN) {

                          /*

                           * REMEMBER: this flag is only set on WARN levels. If the filter verify

                           * is on strict, we reject in search.c, if we ar off, the flag will NOT

                           * be set on the filter at all!

                           */

                          slapi_pblock_set_flag_operation_notes(pb, SLAPI_OP_NOTE_FILTER_INVALID);

+                     }

+                     if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_UNDEFINE) {

                          idl = idl_alloc(0);

                      } else if (keys == NULL || keys[0] == NULL) {

                          /* no keys */
@@ -986,13 +998,15 @@ 

       * look up each key in the index, ANDing the resulting

       * IDLists together.

       */

-     if (f->f_flags & SLAPI_FILTER_INVALID_ATTR) {

+     if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_WARN) {

          /*

           * REMEMBER: this flag is only set on WARN levels. If the filter verify

           * is on strict, we reject in search.c, if we ar off, the flag will NOT

           * be set on the filter at all!

           */

          slapi_pblock_set_flag_operation_notes(pb, SLAPI_OP_NOTE_FILTER_INVALID);

+     }

+     if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_UNDEFINE) {

          idl = idl_alloc(0);

      } else {

          slapi_pblock_get(pb, SLAPI_TXN, &txn.back_txn_txn);

file modified
+51 -33
@@ -166,7 +166,7 @@ 

      CONFIG_SPECIAL_VALIDATE_CERT_SWITCH, /* maps strings to an enumeration */

      CONFIG_SPECIAL_UNHASHED_PW_SWITCH,   /* unhashed pw: on/off/nolog */

      CONFIG_SPECIAL_TLS_CHECK_CRL,        /* maps enum tls_check_crl_t to char * */

-     CONFIG_ON_OFF_WARN,                  /* maps to a config on/warn/off enum */

+     CONFIG_SPECIAL_FILTER_VERIFY,      /* maps to a config strict/warn-strict/warn/off enum */

  } ConfigVarType;

  

  static int32_t config_set_onoff(const char *attrname, char *value, int32_t *configvalue, char *errorbuf, int apply);
@@ -256,7 +256,7 @@ 

  slapi_onoff_t init_extract_pem;

  slapi_onoff_t init_ignore_vattrs;

  slapi_onoff_t init_enable_upgrade_hash;

- slapi_onwarnoff_t init_verify_filter_schema;

+ slapi_special_filter_verify_t init_verify_filter_schema;

  

  static int

  isInt(ConfigVarType type)
@@ -1248,7 +1248,7 @@ 

      {CONFIG_VERIFY_FILTER_SCHEMA, config_set_verify_filter_schema,

       NULL, 0,

       (void **)&global_slapdFrontendConfig.verify_filter_schema,

-      CONFIG_ON_OFF_WARN, (ConfigGetFunc)config_get_verify_filter_schema,

+      CONFIG_SPECIAL_FILTER_VERIFY, (ConfigGetFunc)config_get_verify_filter_schema,

       &init_verify_filter_schema},

      /* End config */

      };
@@ -1783,7 +1783,7 @@ 

       * scheme set in cn=config

       */

      init_enable_upgrade_hash = cfg->enable_upgrade_hash = LDAP_ON;

-     init_verify_filter_schema = cfg->verify_filter_schema = SLAPI_WARN;

+     init_verify_filter_schema = cfg->verify_filter_schema = SLAPI_WARN_SAFE;

  

      /* Done, unlock!  */

      CFG_UNLOCK_WRITE(cfg);
@@ -7659,18 +7659,21 @@ 

  }

  

  static char *

- config_initvalue_to_onwarnoff(struct config_get_and_set *cgas, char *initvalbuf, size_t initvalbufsize) {

+ config_initvalue_to_special_filter_verify(struct config_get_and_set *cgas, char *initvalbuf, size_t initvalbufsize) {

      char *retval = NULL;

-     if (cgas->config_var_type == CONFIG_ON_OFF_WARN) {

-         slapi_onwarnoff_t *value = (slapi_onwarnoff_t *)(intptr_t)cgas->initvalue;

+     if (cgas->config_var_type == CONFIG_SPECIAL_FILTER_VERIFY) {

+         slapi_special_filter_verify_t *value = (slapi_special_filter_verify_t *)(intptr_t)cgas->initvalue;

          if (value != NULL) {

-             if (*value == SLAPI_ON) {

-                 PR_snprintf(initvalbuf, initvalbufsize, "%s", "on");

+             if (*value == SLAPI_STRICT) {

+                 PR_snprintf(initvalbuf, initvalbufsize, "%s", "reject-invalid");

                  retval = initvalbuf;

-             } else if (*value == SLAPI_WARN) {

-                 PR_snprintf(initvalbuf, initvalbufsize, "%s", "warn");

+             } else if (*value == SLAPI_WARN_SAFE) {

+                 PR_snprintf(initvalbuf, initvalbufsize, "%s", "process-safe");

                  retval = initvalbuf;

-             } else if (*value == SLAPI_OFF) {

+             } else if (*value == SLAPI_WARN_UNSAFE) {

+                 PR_snprintf(initvalbuf, initvalbufsize, "%s", "warn-invalid");

+                 retval = initvalbuf;

+             } else if (*value == SLAPI_OFF_UNSAFE) {

                  PR_snprintf(initvalbuf, initvalbufsize, "%s", "off");

                  retval = initvalbuf;

              }
@@ -7680,7 +7683,7 @@ 

  }

  

  static int32_t

- config_set_onoffwarn(slapdFrontendConfig_t *slapdFrontendConfig, slapi_onwarnoff_t *target, const char *attrname, char *value, char *errorbuf, int apply) {

+ config_set_specialfilterverify(slapdFrontendConfig_t *slapdFrontendConfig, slapi_special_filter_verify_t *target, const char *attrname, char *value, char *errorbuf, int apply) {

      if (target == NULL) {

          return LDAP_OPERATIONS_ERROR;

      }
@@ -7689,17 +7692,25 @@ 

          return LDAP_OPERATIONS_ERROR;

      }

  

-     slapi_onwarnoff_t p_val = SLAPI_OFF;

+     slapi_special_filter_verify_t p_val = SLAPI_WARN_SAFE;

  

+     /* on/warn/off retained for legacy reasons due to wbrown making terrible mistakes :( :( */

      if (strcasecmp(value, "on") == 0) {

-         p_val = SLAPI_ON;

+         p_val = SLAPI_STRICT;

      } else if (strcasecmp(value, "warn") == 0) {

-         p_val = SLAPI_WARN;

+         p_val = SLAPI_WARN_SAFE;

+     /* The new fixed/descriptive names */

+     } else if (strcasecmp(value, "reject-invalid") == 0) {

+         p_val = SLAPI_STRICT;

+     } else if (strcasecmp(value, "process-safe") == 0) {

+         p_val = SLAPI_WARN_SAFE;

+     } else if (strcasecmp(value, "warn-invalid") == 0) {

+         p_val = SLAPI_WARN_UNSAFE;

      } else if (strcasecmp(value, "off") == 0) {

-         p_val = SLAPI_OFF;

+         p_val = SLAPI_OFF_UNSAFE;

      } else {

          slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,

-                               "%s: invalid value \"%s\". Valid values are \"on\", \"warn\" or \"off\".", attrname, value);

+                               "%s: invalid value \"%s\". Valid values are \"reject-invalid\", \"process-safe\", \"warn-invalid\" or \"off\". If in doubt, choose \"process-safe\"", attrname, value);

          return LDAP_OPERATIONS_ERROR;

      }

  
@@ -7718,14 +7729,14 @@ 

  int32_t

  config_set_verify_filter_schema(const char *attrname, char *value, char *errorbuf, int apply) {

      slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();

-     slapi_onwarnoff_t *target = &(slapdFrontendConfig->verify_filter_schema);

-     return config_set_onoffwarn(slapdFrontendConfig, target, attrname, value, errorbuf, apply);

+     slapi_special_filter_verify_t *target = &(slapdFrontendConfig->verify_filter_schema);

+     return config_set_specialfilterverify(slapdFrontendConfig, target, attrname, value, errorbuf, apply);

  }

  

  Slapi_Filter_Policy

  config_get_verify_filter_schema()

  {

-     slapi_onwarnoff_t retVal;

+     slapi_special_filter_verify_t retVal;

      slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();

      CFG_LOCK_READ(slapdFrontendConfig);

      retVal = slapdFrontendConfig->verify_filter_schema;
@@ -7733,10 +7744,13 @@ 

  

      /* Now map this to a policy that the fns understand. */

      switch (retVal) {

-     case SLAPI_ON:

+     case SLAPI_STRICT:

          return FILTER_POLICY_STRICT;

          break;

-     case SLAPI_WARN:

+     case SLAPI_WARN_SAFE:

+         return FILTER_POLICY_PROTECT;

+         break;

+     case SLAPI_WARN_UNSAFE:

          return FILTER_POLICY_WARNING;

          break;

      default:
@@ -7794,8 +7808,8 @@ 

              void *initval = cgas->initvalue;

              if (cgas->config_var_type == CONFIG_ON_OFF) {

                  initval = (void *)config_initvalue_to_onoff(cgas, initvalbuf, sizeof(initvalbuf));

-             } else if (cgas->config_var_type == CONFIG_ON_OFF_WARN) {

-                 initval = (void *)config_initvalue_to_onwarnoff(cgas, initvalbuf, sizeof(initvalbuf));

+             } else if (cgas->config_var_type == CONFIG_SPECIAL_FILTER_VERIFY) {

+                 initval = (void *)config_initvalue_to_special_filter_verify(cgas, initvalbuf, sizeof(initvalbuf));

              }

              if (cgas->setfunc) {

                  retval = (cgas->setfunc)(cgas->attr_name, initval, errorbuf, apply);
@@ -8021,20 +8035,24 @@ 

  

          break;

  

-     case CONFIG_ON_OFF_WARN:

+     case CONFIG_SPECIAL_FILTER_VERIFY:

          /* Is this the right default here? */

          if (!value) {

-             slapi_entry_attr_set_charptr(e, cgas->attr_name, "off");

+             slapi_entry_attr_set_charptr(e, cgas->attr_name, "process-safe");

              break;

          }

  

-         if (*((slapi_onwarnoff_t *)value) == SLAPI_ON) {

-             slapi_entry_attr_set_charptr(e, cgas->attr_name, "on");

-         } else if (*((slapi_onwarnoff_t *)value) == SLAPI_WARN) {

-             slapi_entry_attr_set_charptr(e, cgas->attr_name, "warn");

-         } else {

+         if (*((slapi_special_filter_verify_t *)value) == SLAPI_STRICT) {

+             slapi_entry_attr_set_charptr(e, cgas->attr_name, "reject-invalid");

+         } else if (*((slapi_special_filter_verify_t *)value) == SLAPI_WARN_SAFE) {

+             slapi_entry_attr_set_charptr(e, cgas->attr_name, "process-safe");

+         } else if (*((slapi_special_filter_verify_t *)value) == SLAPI_WARN_UNSAFE) {

+             slapi_entry_attr_set_charptr(e, cgas->attr_name, "warn-invalid");

+         } else if (*((slapi_special_filter_verify_t *)value) == SLAPI_OFF_UNSAFE) {

              slapi_entry_attr_set_charptr(e, cgas->attr_name, "off");

-             /* Default to off. */

+         } else {

+             /* Default to safe warn-proccess-safely */

+             slapi_entry_attr_set_charptr(e, cgas->attr_name, "process-safe");

          }

  

          break;

file modified
+19 -7
@@ -698,7 +698,7 @@ 

  }

  

  static Slapi_Filter_Result

- slapi_filter_schema_check_inner(Slapi_Filter *f) {

+ slapi_filter_schema_check_inner(Slapi_Filter *f, slapi_filter_flags flags) {

      /*

       * Default response to Ok. If any more severe things happen we

       * alter this to reflect it. IE we bubble up more severe errors
@@ -712,26 +712,26 @@ 

      case LDAP_FILTER_LE:

      case LDAP_FILTER_APPROX:

          if (!attr_syntax_exist_by_name_nolock(f->f_avtype)) {

-             f->f_flags |= SLAPI_FILTER_INVALID_ATTR;

+             f->f_flags |= flags;

              r = FILTER_SCHEMA_WARNING;

          }

          break;

      case LDAP_FILTER_PRESENT:

          if (!attr_syntax_exist_by_name_nolock(f->f_type)) {

-             f->f_flags |= SLAPI_FILTER_INVALID_ATTR;

+             f->f_flags |= flags;

              r = FILTER_SCHEMA_WARNING;

          }

          break;

      case LDAP_FILTER_SUBSTRINGS:

          if (!attr_syntax_exist_by_name_nolock(f->f_sub_type)) {

-             f->f_flags |= SLAPI_FILTER_INVALID_ATTR;

+             f->f_flags |= flags;

              r = FILTER_SCHEMA_WARNING;

          }

          break;

      case LDAP_FILTER_EXTENDED:

          /* I don't have any examples of this, so I'm not 100% on how to check it */

          if (!attr_syntax_exist_by_name_nolock(f->f_mr_type)) {

-             f->f_flags |= SLAPI_FILTER_INVALID_ATTR;

+             f->f_flags |= flags;

              r = FILTER_SCHEMA_WARNING;

          }

          break;
@@ -740,7 +740,7 @@ 

      case LDAP_FILTER_NOT:

          /* Recurse and check all elemments of the filter */

          for (Slapi_Filter *f_child = f->f_list; f_child != NULL; f_child = f_child->f_next) {

-             Slapi_Filter_Result ri = slapi_filter_schema_check_inner(f_child);

+             Slapi_Filter_Result ri = slapi_filter_schema_check_inner(f_child, flags);

              if (ri > r) {

                  r = ri;

              }
@@ -770,11 +770,23 @@ 

      }

  

      /*

+      * There are two possible warning types - it's not up to us to warn into

+      * the logs, that's the backends job. So we have to flag a hint into the

+      * filter about what it should do. This is why there are two FILTER_INVALID

+      * types in filter_flags, one for logging it, and one for actually doing

+      * the rejection.

+      */

+     slapi_filter_flags flags = SLAPI_FILTER_INVALID_ATTR_WARN;

+     if (fp == FILTER_POLICY_PROTECT) {

+         flags |= SLAPI_FILTER_INVALID_ATTR_UNDEFINE;

+     }

+ 

+     /*

       * Filters are nested, recursive structures, so we actually have to call an inner

       * function until we have a result!

       */

      attr_syntax_read_lock();

-     Slapi_Filter_Result r = slapi_filter_schema_check_inner(f);

+     Slapi_Filter_Result r = slapi_filter_schema_check_inner(f, flags);

      attr_syntax_unlock_read();

  

      /* If any warning occured, ensure we fail it. */

file modified
+11 -10
@@ -457,12 +457,12 @@ 

      TLS_CHECK_ALL = 2,

  } tls_check_crl_t;

  

- typedef enum _slapi_onwarnoff_t {

-     SLAPI_OFF = 0,

-     SLAPI_WARN = 1,

-     SLAPI_ON = 2,

- } slapi_onwarnoff_t;

- 

+ typedef enum _slapi_special_filter_verify_t {

+     SLAPI_STRICT = 0,

+     SLAPI_WARN_SAFE = 1,

+     SLAPI_WARN_UNSAFE = 2,

+     SLAPI_OFF_UNSAFE = 3,

+ } slapi_special_filter_verify_t;

  

  struct subfilt

  {
@@ -2547,11 +2547,12 @@ 

      slapi_onoff_t enable_upgrade_hash; /* If on, upgrade hashes for PW at bind */

      /*

       * Do we verify the filters we recieve by schema?

-      * on - yes, and reject if attribute not found

-      * warn - yes, and warn that the attribute is unknown and unindexed

-      * off - no, do whatever (old status-quo)

+      * reject-invalid - reject filter if there is anything invalid

+      * process-safe - allow the filter, warn about what's invalid, and then idl_alloc(0) with rfc compliance

+      * warn-invalid - allow the filter, warn about the invalid, and then do a ALLIDS (may lead to full table scan)

+      * off - don't warn, just allow anything. This is the legacy behaviour.

       */

-     slapi_onwarnoff_t verify_filter_schema;

+     slapi_special_filter_verify_t verify_filter_schema;

  } slapdFrontendConfig_t;

  

  /* possible values for slapdFrontendConfig_t.schemareplace */

@@ -1571,6 +1571,7 @@ 

  typedef enum {

      FILTER_POLICY_OFF,

      FILTER_POLICY_WARNING,

+     FILTER_POLICY_PROTECT,

      FILTER_POLICY_STRICT,

  } Slapi_Filter_Policy;

  

@@ -54,7 +54,8 @@ 

      SLAPI_FILTER_RUV = 4,

      SLAPI_FILTER_NORMALIZED_TYPE = 8,

      SLAPI_FILTER_NORMALIZED_VALUE = 16,

-     SLAPI_FILTER_INVALID_ATTR = 32,

+     SLAPI_FILTER_INVALID_ATTR_UNDEFINE = 32,

+     SLAPI_FILTER_INVALID_ATTR_WARN = 64,

  } slapi_filter_flags;

  

  #define SLAPI_ENTRY_LDAPSUBENTRY 2

@@ -0,0 +1,53 @@ 

+ # --- BEGIN COPYRIGHT BLOCK ---

+ # Copyright (C) 2019, William Brown <william at blackhats.net.au>

+ # All rights reserved.

+ #

+ # License: GPL (version 3 or any later version).

+ # See LICENSE for details.

+ # --- END COPYRIGHT BLOCK ---

+ 

+ from lib389._mapped_object import DSLdapObject, DSLdapObjects

+ from lib389.utils import ensure_str

+ 

+ class UnsafeExtensibleObject(DSLdapObject):

+     """A single instance of an extensible object. Extensible object by it's

+     nature is unsafe, eliminating rules around attribute checking. It may

+     cause unsafe or other unknown behaviour if not handled correctly.

+ 

+     :param instance: An instance

+     :type instance: lib389.DirSrv

+     :param dn: Entry DN

+     :type dn: str

+     """

+ 

+     def __init__(self, instance, dn=None):

+         super(UnsafeExtensibleObject, self).__init__(instance, dn)

+         self._rdn_attribute = "cn"

+         # Can I generate these from schema?

+         self._must_attributes = []

+         self._create_objectclasses = [

+             'top',

+             'extensibleObject',

+         ]

+         self._protected = False

+ 

+ class UnsafeExtensibleObjects(DSLdapObjects):

+     """DSLdapObjects that represents all extensible objects. Extensible Objects

+     are unsafe in their nature, disabling many checks around schema and attribute

+     handling. You should really really REALLY not use this unless you have specific

+     needs for testing.

+ 

+     :param instance: An instance

+     :type instance: lib389.DirSrv

+     :param basedn: Base DN for all group entries below

+     :type basedn: str

+     """

+ 

+     def __init__(self, instance, basedn):

+         super(UnsafeExtensibleObjects, self).__init__(instance)

+         self._objectclasses = [

+             'extensibleObject',

+         ]

+         self._filterattrs = ["cn"]

+         self._childobject = UnsafeExtensibleObject

+         self._basedn = ensure_str(basedn)

Bug Description: Because William of the past missed (forgot) to make
some agreed upon changes, we shipped the feature for filter validation
in a state that was a bit unclear for users.

Fix Description: Fix the options to now be clearer in what is
expected/demaned from admins. We now have 4 possible states for
the value of the config:

  • reject-invalid (prev on)
  • warn-process-safely (prev warn)
  • warn-allow-unsafe
  • off-allow-unsafe (prev off)

These behave as:

  • reject-invalid - reject queries that contain unknown attributes
  • warn-process-safely - log a notes=F that an attr is missing, and idl_alloc(0)
    the missing attribute for RFC4511 compliance.
  • warn-allow-unsafe - log a notes=F that an attr is missing, and process
    as ALLIDS (the legacy behaviour)
  • off-allow-unsafe - process as ALLIDs (the legacy behaviour)

The default is "warn-process-safely".

https://pagure.io/389-ds-base/issue/50727

Author: William Brown william@blackhats.net.au

Review by: ???

The comment should use new naming like warn-process-safely

Except the minor comment the patch looks good to me. ACK

I also think that the patch is ok, but I am not fully happy with the naming of the options.

The warn-process-safely does change behavior by enforcing rfc compliance, that it logs some info in the access log is an additional feature, but it is not a "warning" option. I would prefer something like:

off (was off)
reject (was strict)
process-warn-only (new)
process-strict or process-rfc-safely or ... (was warn)

good point @lkrispen I also had mixed feeling with the naming but rather because I found them too long. An other suggestion could be

off (was off)
warn (new)
strict (was warn)
reject (was strict)

good point @lkrispen I also had mixed feeling with the naming but rather because I found them too long. An other suggestion could be
off (was off)
warn (new)
strict (was warn)
reject (was strict)

This could have been a valid setting, but since it would change the meaning of warn and strict it would no longer be possible to do a "legacy" processing, so the new names need to be different (except off)

good point @lkrispen I also had mixed feeling with the naming but rather because I found them too long. An other suggestion could be
off (was off)
warn (new)
strict (was warn)
reject (was strict)

This could have been a valid setting, but since it would change the meaning of warn and strict it would no longer be possible to do a "legacy" processing, so the new names need to be different (except off)

This hasn't really been released or documented yet. So we should be able to use whatever values we want even if it is conflicting from the first version of this fix. But I do like Thierry's names as I'm not a huge fan of the original settings use of the word "safe" in them. It's a bit misleading/alarming IMHO

There is a trend in a lot of apis and configurations now to have "hints" about configuration risks in the name. Having settings that open you to denial of service risks certainly speaks of "unsafe" to me.

As @lkrispen rightly points out, we can't reuse the warn/off/strict names to have new meanings, they have to stay with the old meanings. That's why I made all the new names more descriptive.

Having the value be "long" isn't necessarily a bad thing. We hint what is valid in the error if it's not set correctly, so it's easy to discover the valid settings. Having the settings be descriptive is good because it can hint to admins what's a good setting or what's risky, and they are then able to look at documentation about why. A lot of settings don't really indicate what's a good or bad state to be in, so having more descriptive values like this IMO does help.

So I'd tend to want to keep the names I put here, but I'll change them if it's really a problem to people. I'm not going to resist "too hard", I just wanted to state my case.

If I was to change them, I prefer @lkrispen's suggestion, as it's the "closest" to what I want in terms of communicating risks and positive/negative options:

off (was off)
reject (was strict)
process-warn-only (new)
process-strict or process-rfc-safely or ... (was warn)

I have a mixed feeling regarding DOS. There are several options for an attacker to trigger unindexed search even with valid attributetypes (e.g. "(objectclass=*)" or "(FTPQuotaMBytes=123)" where FTPQuotaMBytes is likely not indexed). In additional, even if the attribute is unknown in the schema, you can index it and use it to index a search. So if I understand correctly this RFE it is more oriented to RFC compliance than security.

Regarding the names, I agree with the legacy concern. I am not fan with 'process' header but I understand the will to give a "hint" with good option name. Could it be something like 'warn-only' and 'strict-rfc'. @mmuehlfeldrh any suggestion ?

This hasn't really been released or documented yet. So we should be able to use
whatever values we want even if it is conflicting from the first version of this fix.

ACK. If this was never seen by a user, I would not care about name conflicts with the old names.

But I do like Thierry's names as I'm not a huge fan of the original settings use
of the word "safe" in them. It's a bit misleading/alarming IMHO

I agree that "safe" can be misleading.

There is a trend in a lot of apis and configurations now to have "hints"
about configuration risks in the name.

I agree that this would be nice, but I'm unsure if the suggested names (reject-invalid, warn-process-safely, warn-allow-unsafe, off-allow-unsafe) are descriptive enough. According to the patch, the name of the attribute is "nsslapd-verify-filter-schema". Based on that:

  • I can imagine what "reject-invalid" does.

  • "warn-process-safely" sounds like only the valid filter schema part is processed and a filter that can cause trouble is ignored and a warning logged.

  • I'm really unsure what the difference is between "warn-allow-unsafe" and "off-allow-unsafe". Both seem to allow something that is unsafe, but what is the difference between "warn" and "off" in the two value's names? Does one allow unsafe filters but doesn't log a warning (off)?

1) As someone who is not familiar with the topic, it took me a few minutes to think about these value names and their possible meaning. This means, they were not very self-explaining and it would be faster to look up the possible values and their meanings in the Config Reference Guide rather than guessing.

2) Additionally: Do user see all these options somewhere (e. g. in the logs) so that they can easily find out, for example, what causes the warning and what other values they can set? If I only see the current value (e. g. "warn-process-safely"), then it gives me a glue why this warning is logged, but to find out what other values I can set to fix the problem, I still need the docs. It would be more helpful for me if the warning is descriptive and contains the attribute's name, so that I can look up the details in the docs.

Because of 1) and 2), I think that the long names are nice, but not really necessary. I would prefer the short option names and a good description in the docs. But that's just my opinion. :-)

I have a mixed feeling regarding DOS. There are several options for an attacker to trigger unindexed search even with valid attributetypes (e.g. "(objectclass=*)" or "(FTPQuotaMBytes=123)" where FTPQuotaMBytes is likely not indexed). In additional, even if the attribute is unknown in the schema, you can index it and use it to index a search. So if I understand correctly this RFE it is more oriented to RFC compliance than security.

It was about security and stability because FreeIPA was creating queries that caused huge query times, and I have seen this create a DOS situation when I was previously an Admin. So this is a real problem.

I agree that "safe" can be misleading.

It's not misleading in this case. I don't know why everyone seems to gloss over the fact I've seen this cause production outages when I was an admin ... at the time I didn't know how to solve it or express the problem verbally, but now everyone seems to be ignoring this experience and saying "ohh it's not so bad".

Because of 1) and 2), I think that the long names are nice, but not really necessary. I would prefer the short option names and a good description in the docs. But that's just my opinion. :-)

Yeah that's fair.

So I'm going to say this suggestion is what we go with, taking into account Marc's comment about how it appears next to the config name.

nsslapd-verify-filter-schema: off
nsslapd-verify-filter-schema: reject-invalid
nsslapd-verify-filter-schema: warn-invalid
nsslapd-verify-filter-schema: process-safe

@firstyear, I have no admin experience. Thanks for you explanations I have no doubt that it exists a risk (application using unknown attribute) that production can be severely impacted without immediate explanation/workaround.

So the proposed values set (off, reject-invalid...) looks good to me.

The default value (process-safe) looks the good one considering risk/impact.

FreeIPA used unknown attribute in their requests. I hope it is no longer the case else it will break. By any chance do you remember example of those bad filter ?

On 10 Dec 2019, at 20:44, thierry bordaz pagure@pagure.io wrote:
=20
=20
tbordaz commented on the pull-request: Ticket 50727 - correct = mistaken options in filter validation patch that you are following:
``
@firstyear, I have no admin experience. Thanks for you explanations I =
have no doubt that it exists a risk (application using unknown =
attribute) that production can be severely impacted without immediate =
explanation/workaround.
=20
So the proposed values set (off, reject-invalid...) looks good to me.
=20
The default value (process-safe) looks the good one considering =
risk/impact.
=20
FreeIPA used unknown attribute in their requests. I hope it is no =
longer the case else it will break. By any chance do you remember =
example of those bad filter ?

They were requesting something like:

(|
(objectClass=3Dreferral)
(&
(|
(usercertificate;binary=3D...)
=
(ipaCertMapData=3Dx509:o=3Ddev.blackhats.net.au,cn=3Dcertificate =
authority<s>o=3Ddev.blackhats.net.au,cn=3Dipauser1)
=
(altsecurityidentities=3DX509:O=3DDEV.BLACKHATS.NET.AU,CN=3DCertificate=
Authority<S>O=3DDEV.BLACKHATS.NET.AU,CN=3Dipauser1)
)
(objectClass=3Dposixaccount)
(uid=3D)
(uidNumber=3D
)
(!
(uidNumber=3D0)
)
)
)

The "intent" was to get accounts where a cert name is <CN>, and SSSD was =
emiting a filter that would work on both ipa and ad.

However, in reality, when processed this would cause the inner OR =
condition (ipacertmapdata=3D<CN>)(altsecurityidentites=3D<CN>), due to =
the altsecurityidentiies (from active directory) being unknown to be =
ALLIDS, which makes the OR ALLIDS, so then the filter is bascially =
becoming this index (idl)

(|
(objectClass=3Dreferral)
(&
(objectClass=3D) <<-- the all IDS
(objectClass=3Dposixaccount)
(uid=3D
)
(uidNumber=3D*)
(!
(uidNumber=3D0)
)
)
)

And then the apply filter has to happen "after" to do the actual =
assertion about the certname.

So in a test env they would get the right result, because =
objectClass=3Daccount would be say less than 20 entries, which isn't =
hitting any limits.

But on a production machine, this would become a filter that either:

  • Uses a lot of resources as you have to filter test "up to" the filter =
    test limit of allids
  • Or the limits are hit and this "magically" returns no entries, much to =
    users frustration and disappointment that their system silently breaks.

In the production case I saw it was similar - VMware would do an ldap =
search for users with both posix and AD attributes to find users, which =
again became ALLIDS and caused both production LDAP servers to grind to =
a halt when enabled. That's because by default our lookthrough limit (I =
think it is) for allids cases is actually really really high, probably =
much too high for secure operations.=20

``
=20
To reply, visit the link below or just reply to this email
https://pagure.io/389-ds-base/pull-request/50769

=E2=80=94
Sincerely,

William Brown

Senior Software Engineer, 389 Directory Server
SUSE Labs

rebased onto 9104539a0f24bf15a0cb1818f356a950480d263d

4 years ago

@tbordaz Updated based on your feedback :)

Thank for the info. ipaCertMapData and altSecurityIdentities are now part of FreeIPA 73certmap.ldif schema definition, so the use of those definitions will not hit the change of behavior.

You have my ACK. Please wait for @lkrispen and @mreynolds feedback.

Sorry I have not been following this closely as I am out of the office this week. The main question is are we changing the default behavior with this patch? If there is a risk of that I would like this PR to be run through the IPA tests to make sure we are not introducing any regressions.

We aren't changing the behaviour by default. It's the same as we have shipped for the last few months.

PS: if there are IPA regressions with this feature set to process-safe that indicates a bug in IPA, not DS.

Also thanks for the ack @tbordaz I'll give them a few days to comment then I'll probably look to merge early next week :)

@mreynolds, @abiagion kindly accepted to run NR IPA tests on a test build. @firstyear please hold on the PR until those tests complete.

I've built a custom box for testing with freeipa-pr-ci, here it is the test run:
https://github.com/freeipa-pr-ci2/freeipa/pull/95

It's executing the same set of tests we run weekly with copr repo @389ds/389-ds-base-nightly enabled.

Possible failures in test_caless_* are known and already reported.

@abiagion thank you very much for the run. It helps a lot.
@mreynolds the PR does not trigger any IPA regression (NR run) and original problematic definitions (ipaCertMapData and altSecurityIdentities) are now part of IPA. IMHO the change of behavior (default=process-safe) may create concerns for some customers but it is expected so to protect the production and at the same time do our best to answer requests.

The default value (process-safe) looks the good one considering risk/impact.

IMHO, there should be a grace period when we introduce a new breaking change. Debugging missing search results can be frustrating.
warn-invalid should be a default for now. This change should be communicated in the release notes and support should be aware of the upcoming change (KCS article). I would also add a warning in the errors log (sans dragons) on a startup about this just to be on a safe side.
And in the next release (1.4.3?) we can switch it to process-safe, again highlighting it in the release notes. WDYT?

WDIT ?. I think that you are a wise advocate of users :)

At the moment, there is a warning logged in access logs (notes=F + explanation). Adding one warning in error logs (and KCS) is a good idea as we expect to change default behavior in upcoming version. Do you think we should log only at startup ? Making it noisy at each will help detection.

Regarding IPA, we may open a ticket so that it is configured with process-safe sooner

WDIT ?. I think that you are a wise advocate of users :)
At the moment, there is a warning logged in access logs (notes=F + explanation). Adding one warning in error logs (and KCS) is a good idea as we expect to change default behavior in upcoming version. Do you think we should log only at startup ? Making it noisy at each will help detection.
Regarding IPA, we may open a ticket so that it is configured with process-safe sooner

I think this is best way forward. For 1.4.2 (upstream) & 1.4.3 we use warn-invalid, then in 1.4.4 we change it to: process-safe.

For elaborate on this time line, 1.4.2 is what is going into RHEL 8.2, but we can no longer add enhancements to 8.2. So as this is an enhancement it's going to land downstream in 1.4.3 (RHEL 8.3), then we can release note the initial change/enhancement, and in 8.4 (1.4.4) we set the default to "process-safe".

nsslapd-verify-filter-schema feature is already in RHEL 8.2 (was part of the rebase to 1.4.2) and changes the default behavior. So I'd like to see this fix land also in 8.2 (we still have time for bug fixes).
And then we can switch to process-safe in 1.4.3 (RHEL 8.3).

nsslapd-verify-filter-schema feature is already in RHEL 8.2 (was part of the rebase to 1.4.2) and changes the default behavior. So I'd like to see this fix land also in 8.2 (we still have time for bug fixes).
And then we can switch to process-safe in 1.4.3 (RHEL 8.3).

Sorry I didn't know it was already in 8.2 Cool, so yeah we change the default in 8.2 and release note it, and then change it again in 8.3 (1.4.3).

The default value (process-safe) looks the good one considering risk/impact.

IMHO, there should be a grace period when we introduce a new breaking change. Debugging missing search results can be frustrating.
warn-invalid should be a default for now. This change should be communicated in the release notes and support should be aware of the upcoming change (KCS article). I would also add a warning in the errors log (sans dragons) on a startup about this just to be on a safe side.
And in the next release (1.4.3?) we can switch it to process-safe, again highlighting it in the release notes. WDYT?

There are two issues with this:
Everyone becomes afraid/hesitant to make the further step to make it enforce or change the behaviour as we'll forever cite "breaking" applications as the reason to stall meaningful improvements
Users don't "prepare" their applications because they aren't looking through access log for notes= fields (this goes for IPA too), so they will not notice the upcoming change.
People read release notes after* something goes wrong. Not before.

So I actually disagree, I think that when we make changes like this, we ship with the default that affects behaviour, people notice the behavioural change and then can make an informed decision to disable the feature OR to fix their applications. People should be testing in staging or dev first, and most ops people are well disciplined to do this and find issues before production.

Anyway, I'm going to merge this to 1.4.3 and 1.4.2, and then we can follow up to change the default if there is a strong case for it (merging will keep the exsiting behaviour of process-safe).

rebased onto 9327a33

4 years ago

Pull-Request has been merged by firstyear

4 years ago

commit 60c1831 (HEAD -> 389-ds-base-1.4.2, origin/389-ds-base-1.4.2)

To ssh://pagure.io/389-ds-base.git
35ae7f9..60c1831 389-ds-base-1.4.2 -> 389-ds-base-1.4.2

https://github.com/marcus2376/389wiki/pull/21 <<-- updates the design doc with the finalised names.

Anyway, I'm going to merge this to 1.4.3 and 1.4.2, and then we can follow up to change the default if there is a strong case for it (merging will keep the exsiting behaviour of process-safe).

Our strong case is that this can break our customers as it is unexpectedly changing the current behavior. You do not have to deal with these "regressions" (which is what they will call it when they open escalations), but we do. Waiting one release to flip the switch should have been perfectly acceptable. We all agreed we need to document it first, but you went rogue and merged it anyway. I'm a bit speechless to be honest :-( We'll discuss this later...

This patch is to fix the variable names, it's not about the default value of what this configuration should be - changing the default is one line, and despite the merge, that doesn't mean this patch is going to customers yet ... so the default option can still be discussed, and changed.

I misinterpretted something thierry had commented and the passing ipa tests as ack so I apologise for that. :( That was my fault and I shouldn't have merged it - but as mentioned - it's not changing any behaviour at all.

Finally - this behaviour that is being discussed already has gone to customers, and has gone to production, it was reviewed months ago, and we discussed the changes. It's PR https://pagure.io/389-ds-base/pull-request/50379 . It was merged 4 months ago. The default in that PR is "warn" which is now named "process-safe", so nothing changes by this PR.

This ticket is not changing that functionality, it's not "breaking things". It's simply renaming the config options. The "breaking" happened 4 months ago when we all accepted this and merged it.

Anyway, the change if you want to disable by default will be:

https://pagure.io/389-ds-base/blob/master/f/ldap/servers/slapd/libglobs.c#_1786

Change that one line to

    init_verify_filter_schema = cfg->verify_filter_schema = SLAPI_WARN_UNSAFE;

That will give "warn-invalid" without the "breaking" behaviour. I wasn't kidding when I said oneline change ...

So I actually disagree, I think that when we make changes like this, we ship with the default that affects behaviour, people notice the behavioural change and then can make an informed decision to disable the feature OR to fix their applications. People should be testing in staging or dev first, and most ops people are well disciplined to do this and find issues before production.

We have to be sure to cover our bases and do our due diligence before we introduce a change in behavior to save us from unnecessary escalations (which cost developers time that they could've spend on new features). Especially if it can be easily avoided by having a contingency plan: feature documentation, release notes and a grace period before we flip the switch. And if users still complain about "sudden" change after we exhausted our ways to communicate it, the onus would be on them.

Finally - this behaviour that is being discussed already has gone to customers, and has gone to production, it was reviewed months ago, and we discussed the changes. It's PR https://pagure.io/389-ds-base/pull-request/50379 . It was merged 4 months ago. The default in that PR is "warn" which is now named "process-safe", so nothing changes by this PR.

It was not shipped in RHEL or RHDS builds, so it didn't affect our paying customers.
It was in Fedora and a regression was found: https://bugzilla.redhat.com/show_bug.cgi?id=1759709. People rightfully complained about missing documentation for this change. So as we're moving towards the next releases of RHEL and RHDS, we need to do our best to not repeat the same mistake as we did in Fedora.

As mentioned last night - I'm not really going to debate more on this, I'll defer to your experience. I'm going to make the changes as discussed to 1.4.2/1.4.3 to the default settings, and look at other improvements to communicate the change.

I'll follow up on https://pagure.io/389-ds-base/issue/50727 and once again sorry for the confusion caused by my mistakes :(

As mentioned last night - I'm not really going to debate more on this, I'll defer to your experience.

I would just like to say that it is okay to disagree on issues. Everyone here had valid points about why their approach was better. In the end the team decided to go in the direction of being cautious of breaking existing customers with a potentially disruptive change to search filter behaviour. So sometimes we all just have to agree to disagree, as long as we do it as a team.

As mentioned last night - I'm not really going to debate more on this, I'll defer to your experience.

I would just like to say that it is okay to disagree on issues. Everyone here had valid points about why their approach was better. In the end the team decided to go in the direction of being cautious of breaking existing customers with a potentially disruptive change to search filter behaviour. So sometimes we all just have to agree to disagree, as long as we do it as a team.

My choice of words could have been better, but basically, I said poorly what you said here :)

389-ds-base is moving from Pagure to Github. This means that new issues and pull requests
will be accepted only in 389-ds-base's github repository.

This pull request has been cloned to Github as issue and is available here:
- https://github.com/389ds/389-ds-base/issues/3824

If you want to continue to work on the PR, please navigate to the github issue,
download the patch from the attachments and file a new pull request.

Thank you for understanding. We apologize for all inconvenience.

Pull-Request has been closed by spichugi

3 years ago