def test_log_base_dn_when_invalid_attr_request(topology_st, disable_access_log_buffering): """Test that DS correctly logs the base dn when a search with invalid attribute request is performed :id: 859de962-c261-4ffb-8705-97bceab1ba2c :setup: Standalone instance :steps: 1. Disable the accesslog-logbuffering config parameter 2. Delete the previous access log 3. Perform a base search on the DEFAULT_SUFFIX, using ten empty attribute requests 4. Check the access log file for 'invalid attribute request' 5. Check the access log file for 'SRCH base="\(null\)"' 6. Check the access log file for 'SRCH base="DEFAULT_SUFFIX"' :expectedresults: 1. Operations are visible in the access log in real time 2. Fresh new access log is created 3. The search operation raises a Protocol error 4. The access log should have an 'invalid attribute request' message 5. The access log should not have "\(null\)" as value for the Search base dn 6. The access log should have the value of DEFAULT_SUFFIX as Search base dn """ entry = DSLdapObject(topology_st.standalone, DEFAULT_SUFFIX) log.info('delete the previous access logs to get a fresh new one') topology_st.standalone.deleteAccessLogs() log.info( "Search the default suffix, with invalid '\"\" \"\"' attribute request" ) log.info( "A Protocol error exception should be raised, see https://github.com/389ds/389-ds-base/issues/3028" ) # A ldap.PROTOCOL_ERROR exception is expected after 10 empty values with pytest.raises(ldap.PROTOCOL_ERROR): assert entry.get_attrs_vals_utf8( ['', '', '', '', '', '', '', '', '', '', '']) # Search for appropriate messages in the access log log.info('Check the access logs for correct messages') # We should find the 'invalid attribute request' information assert topology_st.standalone.ds_access_log.match( r'.*invalid attribute request.*') # We should not find a "(null)" base dn mention assert not topology_st.standalone.ds_access_log.match( r'.*SRCH base="\(null\)".*') # We should find the base dn for the search assert topology_st.standalone.ds_access_log.match( r'.*SRCH base="{}".*'.format(DEFAULT_SUFFIX))
class DatabaseConfig(DSLdapObject): """Backend Database configuration The entire database configuration consists of the main global configuration entry, and the underlying DB library configuration: whither BDB or LMDB. The combined configuration should be presented as a single entity so the end user does not need to worry about what library is being used, and just focus on the configuration. :param instance: An instance :type instance: lib389.DirSrv :param dn: Entry DN :type dn: str """ def __init__(self, instance, dn="cn=config,cn=ldbm database,cn=plugins,cn=config"): super(DatabaseConfig, self).__init__(instance, dn) self._rdn_attribute = 'cn' self._must_attributes = ['cn'] self._global_attrs = [ 'nsslapd-lookthroughlimit', 'nsslapd-mode', 'nsslapd-idlistscanlimit', 'nsslapd-directory', 'nsslapd-import-cachesize', 'nsslapd-idl-switch', 'nsslapd-search-bypass-filter-test', 'nsslapd-search-use-vlv-index', 'nsslapd-exclude-from-export', 'nsslapd-serial-lock', 'nsslapd-subtree-rename-switch', 'nsslapd-pagedlookthroughlimit', 'nsslapd-pagedidlistscanlimit', 'nsslapd-rangelookthroughlimit', 'nsslapd-backend-opt-level', 'nsslapd-backend-implement', ] self._db_attrs = { 'bdb': [ 'nsslapd-dbcachesize', 'nsslapd-db-logdirectory', 'nsslapd-db-home-directory', 'nsslapd-db-durable-transaction', 'nsslapd-db-transaction-wait', 'nsslapd-db-checkpoint-interval', 'nsslapd-db-compactdb-interval', 'nsslapd-db-page-size', 'nsslapd-db-transaction-batch-val', 'nsslapd-db-transaction-batch-min-wait', 'nsslapd-db-transaction-batch-max-wait', 'nsslapd-db-logbuf-size', 'nsslapd-db-locks', 'nsslapd-db-private-import-mem', 'nsslapd-import-cache-autosize', 'nsslapd-cache-autosize', 'nsslapd-cache-autosize-split', 'nsslapd-import-cachesize', 'nsslapd-search-bypass-filter-test', 'nsslapd-serial-lock', 'nsslapd-db-deadlock-policy', ], 'lmdb': [] } self._create_objectclasses = ['top', 'extensibleObject'] self._protected = True # This could be "bdb" or "lmdb", use what we have configured in the global config self._db_lib = self.get_attr_val_utf8_l('nsslapd-backend-implement') self._dn = "cn=config,cn=ldbm database,cn=plugins,cn=config" self._db_dn = f"cn={self._db_lib},cn=config,cn=ldbm database,cn=plugins,cn=config" self._globalObj = DSLdapObject(self._instance, dn=self._dn) self._dbObj = DSLdapObject(self._instance, dn=self._db_dn) # Assert there is no overlap in different config sets assert_c( len( set(self._global_attrs).intersection( set(self._db_attrs['bdb']), set(self._db_attrs['lmdb']))) == 0) def get(self): """Get the combined config entries""" # Get and combine both sets of attributes global_attrs = self._globalObj.get_attrs_vals_utf8(self._global_attrs) db_attrs = self._dbObj.get_attrs_vals_utf8( self._db_attrs[self._db_lib]) combined_attrs = {**global_attrs, **db_attrs} return combined_attrs def display(self): """Display the combined configuration""" global_attrs = self._globalObj.get_attrs_vals_utf8(self._global_attrs) db_attrs = self._dbObj.get_attrs_vals_utf8( self._db_attrs[self._db_lib]) combined_attrs = {**global_attrs, **db_attrs} for (k, vo) in combined_attrs.items(): if len(vo) == 0: vo = "" else: vo = vo[0] self._instance.log.info(f'{k}: {vo}') def get_db_lib(self): """Return the backend library, bdb, lmdb, etc""" return self._db_lib def set(self, value_pairs): for attr, val in value_pairs: attr = attr.lower() if attr in self._global_attrs: global_config = DSLdapObject(self._instance, dn=self._dn) global_config.replace(attr, val) elif attr in self._db_attrs['bdb']: db_config = DSLdapObject(self._instance, dn=self._db_dn) db_config.replace(attr, val) elif attr in self._db_attrs['lmdb']: pass else: # Unknown attribute raise ValueError( "Can not update database configuration with unknown attribute: " + attr)