This is an automated email from the git hooks/post-receive script.
spichugi pushed a commit to branch 389-ds-base-1.4.0
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.4.0 by this push:
new 2b689f8 Issue 50292 - Fix Plugin CLI and UI issues
2b689f8 is described below
commit 2b689f8b1d6d0fade86ceea0c31ffb7ede9fbfc8
Author: Simon Pichugin <spichugi(a)redhat.com>
AuthorDate: Fri Mar 15 01:00:50 2019 +0100
Issue 50292 - Fix Plugin CLI and UI issues
Description: Fix 'All plugins' tab rendering issue.
Fix nsds5replicalastinitstatus typo.
Fix generic_object_add logic for cases when RDN is in props and BaseDN is supplied.
Add Posix Winsync API plugin
Add PAM PTA plugin
Fix underscore issues in plugin arguments.
Fix Linked Attribute plugin Fixup task arguments and name.
Change a 'print()' function to a 'log.info()' function.
https://pagure.io/389-ds-base/issue/50292
Reviewed by: mreynolds, wibrown (Thanks!)
---
src/cockpit/389-console/src/plugins.jsx | 2 +
src/lib389/lib389/agreement.py | 2 +-
src/lib389/lib389/cli_conf/__init__.py | 17 ++-
src/lib389/lib389/cli_conf/plugin.py | 2 +
.../lib389/cli_conf/plugins/accountpolicy.py | 7 +-
src/lib389/lib389/cli_conf/plugins/attruniq.py | 35 +++--
src/lib389/lib389/cli_conf/plugins/automember.py | 18 +--
src/lib389/lib389/cli_conf/plugins/dna.py | 15 +-
src/lib389/lib389/cli_conf/plugins/linkedattr.py | 15 +-
.../lib389/cli_conf/plugins/managedentries.py | 20 +--
src/lib389/lib389/cli_conf/plugins/memberof.py | 14 +-
.../lib389/cli_conf/plugins/passthroughauth.py | 169 ++++++++++++++++++---
.../lib389/cli_conf/plugins/posix_winsync.py | 53 +++++++
.../lib389/cli_conf/plugins/retrochangelog.py | 10 +-
src/lib389/lib389/cli_conf/plugins/rootdn_ac.py | 8 +-
src/lib389/lib389/plugins.py | 113 ++++++++++++--
src/lib389/lib389/tasks.py | 1 -
17 files changed, 395 insertions(+), 106 deletions(-)
diff --git a/src/cockpit/389-console/src/plugins.jsx
b/src/cockpit/389-console/src/plugins.jsx
index e14b92d..cab8952 100644
--- a/src/cockpit/389-console/src/plugins.jsx
+++ b/src/cockpit/389-console/src/plugins.jsx
@@ -296,6 +296,8 @@ export class Plugins extends React.Component {
}
this.toggleLoading();
});
+ } else {
+ this.pluginList();
}
});
}
diff --git a/src/lib389/lib389/agreement.py b/src/lib389/lib389/agreement.py
index 1f3fefc..128a607 100644
--- a/src/lib389/lib389/agreement.py
+++ b/src/lib389/lib389/agreement.py
@@ -317,7 +317,7 @@ class Agreement(DSLdapObject):
if 'nsds5beginreplicarefresh' not in status_attrs_dict:
status_attrs_dict['nsds5beginreplicarefresh'] = [""]
if 'nsds5replicalastinitstatus' not in status_attrs_dict:
- status_attrs_dict['nsds5replicalastinitstatus'] =
["unavilable"]
+ status_attrs_dict['nsds5replicalastinitstatus'] =
["unavailable"]
if 'nsds5replicachangessentsincestartup' not in status_attrs_dict:
status_attrs_dict['nsds5replicachangessentsincestartup'] =
['0']
if
ensure_str(status_attrs_dict['nsds5replicachangessentsincestartup'][0]) ==
'':
diff --git a/src/lib389/lib389/cli_conf/__init__.py
b/src/lib389/lib389/cli_conf/__init__.py
index 9e1daed..2567f1e 100644
--- a/src/lib389/lib389/cli_conf/__init__.py
+++ b/src/lib389/lib389/cli_conf/__init__.py
@@ -30,18 +30,21 @@ def generic_object_add(dsldap_objects_class, inst, log, args,
arg_to_attr, dn=No
"""
log = log.getChild('generic_object_add')
+ # If Base DN was initially provided then 'props' should contain the RDN
+ # if 'props' doesn't have the RDN - it will fail with the right error
during the validation in the 'create'
+ rdn = None
# Gather the attributes
attrs = _args_to_attrs(args, arg_to_attr)
props.update({attr: value for (attr, value) in attrs.items() if value !=
""})
# Get RDN attribute and Base DN from the DN if Base DN is not specified
- if dn is not None and basedn is None:
- dn_parts = ldap.dn.explode_dn(dn)
-
- rdn = dn_parts[0]
- basedn = ",".join(dn_parts[1:])
- else:
- raise ValueError('If Base DN is not specified - DN parameter should be')
+ if basedn is None:
+ if dn is not None:
+ dn_parts = ldap.dn.explode_dn(dn)
+ rdn = dn_parts[0]
+ basedn = ",".join(dn_parts[1:])
+ else:
+ raise ValueError('If Base DN is not specified - DN parameter should be
specified instead')
new_object = dsldap_objects_class(inst, dn=dn)
new_object.create(rdn=rdn, basedn=basedn, properties=props)
diff --git a/src/lib389/lib389/cli_conf/plugin.py b/src/lib389/lib389/cli_conf/plugin.py
index 9509b84..db2ba58 100644
--- a/src/lib389/lib389/cli_conf/plugin.py
+++ b/src/lib389/lib389/cli_conf/plugin.py
@@ -26,6 +26,7 @@ from lib389.cli_conf.plugins import managedentries as
cli_managedentries
from lib389.cli_conf.plugins import passthroughauth as cli_passthroughauth
from lib389.cli_conf.plugins import retrochangelog as cli_retrochangelog
from lib389.cli_conf.plugins import automember as cli_automember
+from lib389.cli_conf.plugins import posix_winsync as cli_posix_winsync
SINGULAR = Plugin
MANY = Plugins
@@ -111,6 +112,7 @@ def create_parser(subparsers):
cli_managedentries.create_parser(subcommands)
cli_passthroughauth.create_parser(subcommands)
cli_retrochangelog.create_parser(subcommands)
+ cli_posix_winsync.create_parser(subcommands)
list_parser = subcommands.add_parser('list', help="List current
configured (enabled and disabled) plugins")
list_parser.set_defaults(func=plugin_list)
diff --git a/src/lib389/lib389/cli_conf/plugins/accountpolicy.py
b/src/lib389/lib389/cli_conf/plugins/accountpolicy.py
index e2fa1e1..e585d2a 100644
--- a/src/lib389/lib389/cli_conf/plugins/accountpolicy.py
+++ b/src/lib389/lib389/cli_conf/plugins/accountpolicy.py
@@ -55,9 +55,10 @@ def accountpolicy_show_config(inst, basedn, log, args):
raise ldap.NO_SUCH_OBJECT("Entry %s doesn't exists" % targetdn)
if args and args.json:
o_str = config.get_all_attrs_json()
- print(o_str)
+
+ log.info(o_str)
else:
- print(config.display())
+ log.info(config.display())
def accountpolicy_del_config(inst, basedn, log, args):
@@ -69,7 +70,7 @@ def accountpolicy_del_config(inst, basedn, log, args):
def _add_parser_args(parser):
- parser.add_argument('--always-record-login', choices=['yes',
'no'],
+ parser.add_argument('--always-record-login', choices=['yes',
'no'], type=str.lower,
help='Sets that every entry records its last login time
(alwaysRecordLogin)')
parser.add_argument('--alt-state-attr',
help='Provides a backup attribute for the server to reference
'
diff --git a/src/lib389/lib389/cli_conf/plugins/attruniq.py
b/src/lib389/lib389/cli_conf/plugins/attruniq.py
index 17dac15..a26154c 100644
--- a/src/lib389/lib389/cli_conf/plugins/attruniq.py
+++ b/src/lib389/lib389/cli_conf/plugins/attruniq.py
@@ -9,15 +9,16 @@
import json
import ldap
from lib389.plugins import AttributeUniquenessPlugin, AttributeUniquenessPlugins
-from lib389.cli_conf import add_generic_plugin_parsers, generic_object_edit,
generic_object_add
+from lib389.cli_conf import (add_generic_plugin_parsers, generic_object_edit,
generic_object_add,
+ generic_enable, generic_disable, generic_status)
from lib389._constants import DN_PLUGIN
arg_to_attr = {
- 'attr-name': 'uniqueness-attribute-name',
+ 'attr_name': 'uniqueness-attribute-name',
'subtree': 'uniqueness-subtrees',
- 'across-all-subtrees': 'uniqueness-across-all-subtrees',
- 'top-entry-oc': 'uniqueness-top-entry-oc',
- 'subtree-entries-oc': 'uniqueness-subtree-entries-oc'
+ 'across_all_subtrees': 'uniqueness-across-all-subtrees',
+ 'top_entry_oc': 'uniqueness-top-entry-oc',
+ 'subtree_entries_oc': 'uniqueness-subtree-entries-oc'
}
@@ -32,13 +33,13 @@ def attruniq_list(inst, basedn, log, args):
else:
result.append(plugin.rdn)
if args.json:
- print(json.dumps({"type": "list", "items":
result_json}))
+ log.info(json.dumps({"type": "list", "items":
result_json}))
else:
if len(result) > 0:
for i in result:
- print(i)
+ log.info(i)
else:
- print("No Attribute Uniqueness plugin instances")
+ log.info("No Attribute Uniqueness plugin instances")
def attruniq_add(inst, basedn, log, args):
@@ -63,9 +64,9 @@ def attruniq_show(inst, basedn, log, args):
raise ldap.NO_SUCH_OBJECT("Entry %s doesn't exists" % args.name)
if args and args.json:
o_str = plugin.get_all_attrs_json()
- print(o_str)
+ log.info(o_str)
else:
- print(plugin.display())
+ log.info(plugin.display())
def attruniq_del(inst, basedn, log, args):
@@ -85,7 +86,7 @@ def _add_parser_args(parser):
parser.add_argument('--subtree', nargs='+',
help='Sets the DN under which the plug-in checks for
uniqueness of '
'the attributes value. This attribute is multi-valued
(uniqueness-subtrees)')
- parser.add_argument('--across-all-subtrees', choices=['on',
'off'],
+ parser.add_argument('--across-all-subtrees', choices=['on',
'off'], type=str.lower,
help='If enabled (on), the plug-in checks that the attribute
is unique across all subtrees '
'set. If you set the attribute to off, uniqueness is
only enforced within the subtree '
'of the updated entry
(uniqueness-across-all-subtrees)')
@@ -120,3 +121,15 @@ def create_parser(subparsers):
delete = subcommands.add_parser('delete', help='Delete the config
entry')
delete.add_argument('NAME', help='Sets the name of the plug-in
configuration record')
delete.set_defaults(func=attruniq_del)
+
+ enable = subcommands.add_parser('enable', help='enable plugin')
+ enable.add_argument('NAME', help='Sets the name of the plug-in
configuration record')
+ enable.set_defaults(func=generic_enable)
+
+ disable = subcommands.add_parser('disable', help='disable plugin')
+ disable.add_argument('NAME', help='Sets the name of the plug-in
configuration record')
+ disable.set_defaults(func=generic_disable)
+
+ status = subcommands.add_parser('status', help='display plugin
status')
+ status.add_argument('NAME', help='Sets the name of the plug-in
configuration record')
+ status.set_defaults(func=generic_status)
diff --git a/src/lib389/lib389/cli_conf/plugins/automember.py
b/src/lib389/lib389/cli_conf/plugins/automember.py
index d9fe1dd..fbd270a 100644
--- a/src/lib389/lib389/cli_conf/plugins/automember.py
+++ b/src/lib389/lib389/cli_conf/plugins/automember.py
@@ -14,16 +14,16 @@ from lib389.cli_conf import add_generic_plugin_parsers,
generic_object_edit, gen
arg_to_attr_definition = {
- 'default-group': 'autoMemberDefaultGroup',
+ 'default_group': 'autoMemberDefaultGroup',
'filter': 'autoMemberFilter',
- 'grouping-attr': 'autoMemberGroupingAttr',
+ 'grouping_attr': 'autoMemberGroupingAttr',
'scope': 'autoMemberScope'
}
arg_to_attr_regex = {
'exclusive': 'autoMemberExclusiveRegex',
'inclusive': 'autoMemberInclusiveRegex',
- 'target-group': 'autoMemberTargetGroup'
+ 'target_group': 'autoMemberTargetGroup'
}
@@ -42,7 +42,7 @@ def definition_list(inst, basedn, log, args):
log.info("No automember definitions were found")
if args.json:
- print(json.dumps(result))
+ log.info(json.dumps(result))
def definition_add(inst, basedn, log, args):
@@ -68,9 +68,9 @@ def definition_show(inst, basedn, log, args):
raise ldap.NO_SUCH_OBJECT("Entry %s doesn't exists" % args.name)
if args and args.json:
o_str = definition.get_all_attrs_json()
- print(o_str)
+ log.info(o_str)
else:
- print(definition.display())
+ log.info(definition.display())
def definition_del(inst, basedn, log, args):
@@ -98,7 +98,7 @@ def regex_list(inst, basedn, log, args):
log.info("No automember regexes were found")
if args.json:
- print(json.dumps(result))
+ log.info(json.dumps(result))
def regex_add(inst, basedn, log, args):
@@ -129,9 +129,9 @@ def regex_show(inst, basedn, log, args):
raise ldap.NO_SUCH_OBJECT("Entry %s doesn't exists" % args.name)
if args and args.json:
o_str = regex.get_all_attrs_json()
- print(o_str)
+ log.info(o_str)
else:
- print(regex.display())
+ log.info(regex.display())
def regex_del(inst, basedn, log, args):
diff --git a/src/lib389/lib389/cli_conf/plugins/dna.py
b/src/lib389/lib389/cli_conf/plugins/dna.py
index 08f66a4..6033c17 100644
--- a/src/lib389/lib389/cli_conf/plugins/dna.py
+++ b/src/lib389/lib389/cli_conf/plugins/dna.py
@@ -54,7 +54,7 @@ def dna_list(inst, basedn, log, args):
log.info("No DNA configurations were found")
if args.json:
- print(json.dumps(result))
+ log.info(json.dumps(result))
def dna_add(inst, basedn, log, args):
@@ -80,9 +80,9 @@ def dna_show(inst, basedn, log, args):
raise ldap.NO_SUCH_OBJECT("Entry %s doesn't exists" % args.NAME)
if args and args.json:
o_str = config.get_all_attrs_json()
- print(o_str)
+ log.info(o_str)
else:
- print(config.display())
+ log.info(config.display())
def dna_del(inst, basedn, log, args):
@@ -109,7 +109,7 @@ def dna_config_list(inst, basedn, log, args):
log.info("No DNA shared configurations were found")
if args.json:
- print(json.dumps(result))
+ log.info(json.dumps(result))
def dna_config_add(inst, basedn, log, args):
@@ -146,9 +146,9 @@ def dna_config_show(inst, basedn, log, args):
raise ldap.NO_SUCH_OBJECT("Entry %s doesn't exists" % targetdn)
if args and args.json:
o_str = shared_config.get_all_attrs_json()
- print(o_str)
+ log.info(o_str)
else:
- print(shared_config.display())
+ log.info(shared_config.display())
def dna_config_del(inst, basedn, log, args):
@@ -160,7 +160,8 @@ def dna_config_del(inst, basedn, log, args):
def _add_parser_args(parser):
- parser.add_argument('--type', help='Sets which attributes have unique
numbers being generated for them (dnaType)')
+ parser.add_argument('--type', nargs='+',
+ help='Sets which attributes have unique numbers being
generated for them (dnaType)')
parser.add_argument('--prefix', help='Defines a prefix that can be
prepended to the generated '
'number values for the attribute
(dnaPrefix)')
parser.add_argument('--next-value', help='Gives the next available number
which can be assigned (dnaNextValue)')
diff --git a/src/lib389/lib389/cli_conf/plugins/linkedattr.py
b/src/lib389/lib389/cli_conf/plugins/linkedattr.py
index 716f0e2..781767c 100644
--- a/src/lib389/lib389/cli_conf/plugins/linkedattr.py
+++ b/src/lib389/lib389/cli_conf/plugins/linkedattr.py
@@ -30,13 +30,13 @@ def linkedattr_list(inst, basedn, log, args):
else:
result.append(config.rdn)
if args.json:
- print(json.dumps({"type": "list", "items":
result_json}))
+ log.info(json.dumps({"type": "list", "items":
result_json}))
else:
if len(result) > 0:
for i in result:
- print(i)
+ log.info(i)
else:
- print("No Linked Attributes plugin instances")
+ log.info("No Linked Attributes plugin config instances")
def linkedattr_add(inst, basedn, log, args):
@@ -62,9 +62,9 @@ def linkedattr_show(inst, basedn, log, args):
raise ldap.NO_SUCH_OBJECT("Entry %s doesn't exists" % args.name)
if args and args.json:
o_str = config.get_all_attrs_json()
- print(o_str)
+ log.info(o_str)
else:
- print(config.display())
+ log.info(config.display())
def linkedattr_del(inst, basedn, log, args):
@@ -80,7 +80,7 @@ def fixup(inst, basedn, log, args):
log.info('Attempting to add task entry... This will fail if LinkedAttributes
plug-in is not enabled.')
if not plugin.status():
log.error("'%s' is disabled. Fix up task can't be executed"
% plugin.rdn)
- fixup_task = plugin.fixup(args.basedn, args.filter)
+ fixup_task = plugin.fixup(args.linkdn)
fixup_task.wait()
exitcode = fixup_task.get_exit_code()
if exitcode != 0:
@@ -104,8 +104,7 @@ def create_parser(subparsers):
add_generic_plugin_parsers(subcommands, LinkedAttributesPlugin)
fixup_parser = subcommands.add_parser('fixup', help='Run the fix-up task
for linked attributes plugin')
- fixup_parser.add_argument('basedn', help="basedn that contains entries
to fix up")
- fixup_parser.add_argument('-f', '--filter', help='Filter for
entries to fix up linked attributes.')
+ fixup_parser.add_argument('-l', '--linkdn', help="Base DN that
contains entries to fix up")
fixup_parser.set_defaults(func=fixup)
list = subcommands.add_parser('list', help='List available plugin
configs')
diff --git a/src/lib389/lib389/cli_conf/plugins/managedentries.py
b/src/lib389/lib389/cli_conf/plugins/managedentries.py
index cb5235b..071df7b 100644
--- a/src/lib389/lib389/cli_conf/plugins/managedentries.py
+++ b/src/lib389/lib389/cli_conf/plugins/managedentries.py
@@ -48,13 +48,13 @@ def mep_config_list(inst, basedn, log, args):
else:
result.append(config.rdn)
if args.json:
- print(json.dumps({"type": "list", "items":
result_json}))
+ log.info(json.dumps({"type": "list", "items":
result_json}))
else:
if len(result) > 0:
for i in result:
- print(i)
+ log.info(i)
else:
- print("No Linked Attributes plugin instances")
+ log.info("No Linked Attributes plugin instances")
def mep_config_add(inst, basedn, log, args):
@@ -87,9 +87,9 @@ def mep_config_show(inst, basedn, log, args):
raise ldap.NO_SUCH_OBJECT("Entry %s doesn't exists" % args.name)
if args and args.json:
o_str = config.get_all_attrs_json()
- print(o_str)
+ log.info(o_str)
else:
- print(config.display())
+ log.info(config.display())
def mep_config_del(inst, basedn, log, args):
@@ -113,13 +113,13 @@ def mep_template_list(inst, basedn, log, args):
else:
result.append(template.rdn)
if args.json:
- print(json.dumps({"type": "list", "items":
result_json}))
+ log.info(json.dumps({"type": "list", "items":
result_json}))
else:
if len(result) > 0:
for i in result:
- print(i)
+ log.info(i)
else:
- print("No Linked Attributes plugin instances")
+ log.info("No Linked Attributes plugin instances")
def mep_template_add(inst, basedn, log, args):
@@ -148,9 +148,9 @@ def mep_template_show(inst, basedn, log, args):
raise ldap.NO_SUCH_OBJECT("Entry %s doesn't exists" % targetdn)
if args and args.json:
o_str = template.get_all_attrs_json()
- print(o_str)
+ log.info(o_str)
else:
- print(template.display())
+ log.info(template.display())
def mep_template_del(inst, basedn, log, args):
diff --git a/src/lib389/lib389/cli_conf/plugins/memberof.py
b/src/lib389/lib389/cli_conf/plugins/memberof.py
index 666dd74..eb3d5e0 100644
--- a/src/lib389/lib389/cli_conf/plugins/memberof.py
+++ b/src/lib389/lib389/cli_conf/plugins/memberof.py
@@ -56,9 +56,9 @@ def memberof_show_config(inst, basedn, log, args):
raise ldap.NO_SUCH_OBJECT("Entry %s doesn't exists" % targetdn)
if args and args.json:
o_str = config.get_all_attrs_json()
- print(o_str)
+ log.info(o_str)
else:
- print(config.display())
+ log.info(config.display())
def memberof_del_config(inst, basedn, log, args):
@@ -69,10 +69,12 @@ def memberof_del_config(inst, basedn, log, args):
log.info("Successfully deleted the %s", targetdn)
-def fixup(inst, basedn, log, args):
+def do_fixup(inst, basedn, log, args):
plugin = MemberOfPlugin(inst)
- log.info('Attempting to add task entry... This will fail if MemberOf plug-in is
not enabled.')
- assert plugin.status(), "'%s' is disabled. Fix up task can't be
executed" % plugin.rdn
+ log.info('Attempting to add task entry...')
+ if not plugin.status():
+ log.error("'%s' is disabled. Fix up task can't be executed"
% plugin.rdn)
+ return
fixup_task = plugin.fixup(args.DN, args.filter)
fixup_task.wait()
exitcode = fixup_task.get_exit_code()
@@ -132,7 +134,7 @@ def create_parser(subparsers):
del_config_.add_argument('DN', help='The config entry full DN')
fixup = subcommands.add_parser('fixup', help='Run the fix-up task for
memberOf plugin')
- fixup.set_defaults(func=fixup)
+ fixup.set_defaults(func=do_fixup)
fixup.add_argument('DN', help="Base DN that contains entries to fix
up")
fixup.add_argument('-f', '--filter',
help='Filter for entries to fix up.\n If omitted, all entries
with objectclass '
diff --git a/src/lib389/lib389/cli_conf/plugins/passthroughauth.py
b/src/lib389/lib389/cli_conf/plugins/passthroughauth.py
index 616119a..c5d0646 100644
--- a/src/lib389/lib389/cli_conf/plugins/passthroughauth.py
+++ b/src/lib389/lib389/cli_conf/plugins/passthroughauth.py
@@ -8,8 +8,22 @@
import json
import ldap
-from lib389.plugins import PassThroughAuthenticationPlugin
-from lib389.cli_conf import add_generic_plugin_parsers
+from lib389.plugins import (PassThroughAuthenticationPlugin, PAMPassThroughAuthPlugin,
+ PAMPassThroughAuthConfigs, PAMPassThroughAuthConfig)
+
+from lib389.cli_conf import add_generic_plugin_parsers, generic_object_edit,
generic_object_add
+
+arg_to_attr_pam = {
+ 'exclude_suffix': 'pamExcludeSuffix',
+ 'include_suffix': 'pamIncludeSuffix',
+ 'missing_suffix': 'pamMissingSuffix',
+ 'filter': 'pamFilter',
+ 'id_attr': 'pamIDAttr',
+ 'id_map_method': 'pamIDMapMethod',
+ 'fallback': 'pamFallback',
+ 'secure': 'pamSecure',
+ 'service': 'pamService'
+}
def pta_list(inst, basedn, log, args):
@@ -18,13 +32,13 @@ def pta_list(inst, basedn, log, args):
result = []
urls = plugin.get_urls()
if args.json:
- print(json.dumps({"type": "list", "items": urls}))
+ log.info(json.dumps({"type": "list", "items":
urls}))
else:
if len(urls) > 0:
for i in result:
- print(i)
+ log.info(i)
else:
- print("No Pass Through Auth attributes were found")
+ log.info("No Pass Through Auth URLs were found")
def pta_add(inst, basedn, log, args):
@@ -62,27 +76,132 @@ def pta_del(inst, basedn, log, args):
log.info("Successfully deleted %s", args.URL)
+def pam_pta_list(inst, basedn, log, args):
+ log = log.getChild('pam_pta_list')
+ configs = PAMPassThroughAuthConfigs(inst)
+ result = []
+ result_json = []
+ for config in configs.list():
+ if args.json:
+ result_json.append(config.get_all_attrs_json())
+ else:
+ result.append(config.rdn)
+ if args.json:
+ log.info(json.dumps({"type": "list", "items":
result_json}))
+ else:
+ if len(result) > 0:
+ for i in result:
+ log.info(i)
+ else:
+ log.info("No PAM Pass Through Auth plugin config instances")
+
+
+def pam_pta_add(inst, basedn, log, args):
+ log = log.getChild('pam_pta_add')
+ plugin = PAMPassThroughAuthPlugin(inst)
+ props = {'cn': args.NAME}
+ generic_object_add(PAMPassThroughAuthConfig, inst, log, args, arg_to_attr_pam,
basedn=plugin.dn, props=props)
+
+
+def pam_pta_edit(inst, basedn, log, args):
+ log = log.getChild('pam_pta_edit')
+ configs = PAMPassThroughAuthConfigs(inst)
+ config = configs.get(args.NAME)
+ generic_object_edit(config, log, args, arg_to_attr_pam)
+
+
+def pam_pta_show(inst, basedn, log, args):
+ log = log.getChild('pam_pta_show')
+ configs = PAMPassThroughAuthConfigs(inst)
+ config = configs.get(args.NAME)
+
+ if not config.exists():
+ raise ldap.NO_SUCH_OBJECT("Entry %s doesn't exists" % args.name)
+ if args and args.json:
+ o_str = config.get_all_attrs_json()
+ log.info(o_str)
+ else:
+ log.info(config.display())
+
+
+def pam_pta_del(inst, basedn, log, args):
+ log = log.getChild('pam_pta_del')
+ configs = PAMPassThroughAuthConfigs(inst)
+ config = configs.get(args.NAME)
+ config.delete()
+ log.info("Successfully deleted the %s", config.dn)
+
+
+def _add_parser_args_pam(parser):
+ parser.add_argument('--exclude-suffix', nargs='+',
+ help='Specifies a suffix to exclude from PAM authentication
(pamExcludeSuffix)')
+ parser.add_argument('--include-suffix', nargs='+',
+ help='Sets a suffix to include for PAM authentication
(pamIncludeSuffix)')
+ parser.add_argument('--missing-suffix', choices=['ERROR',
'ALLOW', 'IGNORE'],
+ help='Identifies how to handle missing include or exclude
suffixes (pamMissingSuffix)')
+ parser.add_argument('--filter',
+ help='Sets an LDAP filter to use to identify specific entries
within '
+ 'the included suffixes for which to use PAM pass-through
authentication (pamFilter)')
+ parser.add_argument('--id-attr', nargs='+',
+ help='Contains the attribute name which is used to hold the
PAM user ID (pamIDAttr)')
+ parser.add_argument('--id_map_method',
+ help='Gives the method to use to map the LDAP bind DN to a
PAM identity (pamIDMapMethod)')
+ parser.add_argument('--fallback', choices=['TRUE', 'FALSE'],
type=str.upper,
+ help='Sets whether to fallback to regular LDAP authentication
'
+ 'if PAM authentication fails (pamFallback)')
+ parser.add_argument('--secure', choices=['TRUE', 'FALSE'],
type=str.upper,
+ help='Requires secure TLS connection for PAM authentication
(pamSecure)')
+ parser.add_argument('--service',
+ help='Contains the service name to pass to PAM
(pamService)')
+
+
def create_parser(subparsers):
- passthroughauth_parser = subparsers.add_parser('pass-through-auth',
help='Manage and configure Pass-Through Authentication plugin')
+ passthroughauth_parser = subparsers.add_parser('pass-through-auth',
+ help='Manage and configure
Pass-Through Authentication plugins '
+ '(URLs and PAM)')
subcommands = passthroughauth_parser.add_subparsers(help='action')
add_generic_plugin_parsers(subcommands, PassThroughAuthenticationPlugin)
- list = subcommands.add_parser('list', help='List available plugin
configs')
- list.set_defaults(func=pta_list)
-
- add = subcommands.add_parser('add', help='Add the config entry')
- add.add_argument('URL', help='The full LDAP URL in format '
- '"ldap|ldaps://authDS/subtree
maxconns,maxops,timeout,ldver,connlifetime,startTLS". '
- 'If one optional parameter is specified the rest
should be specified too')
- add.set_defaults(func=pta_add)
-
- edit = subcommands.add_parser('modify', help='Edit the config
entry')
- edit.add_argument('OLD_URL', help='The full LDAP URL you get from the
"list" command')
- edit.add_argument('NEW_URL', help='The full LDAP URL in format '
- '"ldap|ldaps://authDS/subtree
maxconns,maxops,timeout,ldver,connlifetime,startTLS". '
- 'If one optional parameter is specified the rest
should be specified too')
- edit.set_defaults(func=pta_edit)
-
- delete = subcommands.add_parser('delete', help='Delete the config
entry')
- delete.add_argument('URL', help='The full LDAP URL you get from the
"list" command')
- delete.set_defaults(func=pta_del)
+ list = subcommands.add_parser('list', help='List pass-though plugin URLs
or PAM configurations.')
+ subcommands_list = list.add_subparsers(help='action')
+ list_urls = subcommands_list.add_parser('urls', help='List URLs.')
+ list_urls.set_defaults(func=pta_list)
+ list_pam = subcommands_list.add_parser('pam-configs', help='List PAM
configurations.')
+ list_pam.set_defaults(func=pam_pta_list)
+
+ url = subcommands.add_parser('url', help='Manage PTA URL
configurations.')
+ subcommands_url = url.add_subparsers(help='action')
+
+ add_url = subcommands_url.add_parser('add', help='Add the config
entry')
+ add_url.add_argument('URL',
+ help='The full LDAP URL in format '
+ '"ldap|ldaps://authDS/subtree
maxconns,maxops,timeout,ldver,connlifetime,startTLS". '
+ 'If one optional parameter is specified the rest should
be specified too')
+ add_url.set_defaults(func=pta_add)
+
+ edit_url = subcommands_url.add_parser('modify', help='Edit the config
entry')
+ edit_url.add_argument('OLD_URL', help='The full LDAP URL you get from the
"list" command')
+ edit_url.add_argument('NEW_URL',
+ help='The full LDAP URL in format '
+ '"ldap|ldaps://authDS/subtree
maxconns,maxops,timeout,ldver,connlifetime,startTLS". '
+ 'If one optional parameter is specified the rest
should be specified too')
+ edit_url.set_defaults(func=pta_edit)
+
+ delete_url = subcommands_url.add_parser('delete', help='Delete the config
entry')
+ delete_url.add_argument('URL', help='The full LDAP URL you get from the
"list" command')
+ delete_url.set_defaults(func=pta_del)
+
+ pam = subcommands.add_parser('pam-config', help='Manage PAM PTA
configurations.')
+ pam.add_argument('NAME', help='The PAM PTA configuration name')
+ subcommands_pam = pam.add_subparsers(help='action')
+
+ add = subcommands_pam.add_parser('add', help='Add the config entry')
+ add.set_defaults(func=pam_pta_add)
+ _add_parser_args_pam(add)
+ edit = subcommands_pam.add_parser('set', help='Edit the config
entry')
+ edit.set_defaults(func=pam_pta_edit)
+ _add_parser_args_pam(edit)
+ show = subcommands_pam.add_parser('show', help='Display the config
entry')
+ show.set_defaults(func=pam_pta_show)
+ delete = subcommands_pam.add_parser('delete', help='Delete the config
entry')
+ delete.set_defaults(func=pam_pta_del)
diff --git a/src/lib389/lib389/cli_conf/plugins/posix_winsync.py
b/src/lib389/lib389/cli_conf/plugins/posix_winsync.py
new file mode 100644
index 0000000..5c5d6cc
--- /dev/null
+++ b/src/lib389/lib389/cli_conf/plugins/posix_winsync.py
@@ -0,0 +1,53 @@
+# --- BEGIN COPYRIGHT BLOCK ---
+# Copyright (C) 2019 Red Hat, Inc.
+# All rights reserved.
+#
+# License: GPL (version 3 or any later version).
+# See LICENSE for details.
+# --- END COPYRIGHT BLOCK ---
+
+from lib389.plugins import POSIXWinsyncPlugin
+from lib389.cli_conf import add_generic_plugin_parsers, generic_object_edit
+
+arg_to_attr = {
+ 'create_memberof_task': 'posixWinsyncCreateMemberOfTask',
+ 'lower_case_uid': 'posixWinsyncLowerCaseUID',
+ 'map_member_uid': 'posixWinsyncMapMemberUID',
+ 'map_nested_grouping': 'posixWinsyncMapNestedGrouping',
+ 'ms_sfu_schema': 'posixWinsyncMsSFUSchema'
+}
+
+
+def winsync_edit(inst, basedn, log, args):
+ log = log.getChild('winsync_edit')
+ plugin = POSIXWinsyncPlugin(inst)
+ generic_object_edit(plugin, log, args, arg_to_attr)
+
+
+def _add_parser_args(parser):
+ parser.add_argument('--create-memberof-task', choices=['true',
'false'], type=str.lower,
+ help=' sets whether to run the memberOf fix-up task
immediately after a sync run in order '
+ 'to update group memberships for synced users
(posixWinsyncCreateMemberOfTask)')
+ parser.add_argument('--lower-case-uid', choices=['true',
'false'], type=str.lower,
+ help='Sets whether to store (and, if necessary, convert) the
UID value in the memberUID '
+ 'attribute in lower
case.(posixWinsyncLowerCaseUID)')
+ parser.add_argument('--map-member-uid', choices=['true',
'false'], type=str.lower,
+ help='Sets whether to map the memberUID attribute in an
Active Directory group to '
+ 'the uniqueMember attribute in a Directory Server group
(posixWinsyncMapMemberUID)')
+ parser.add_argument('--map-nested-grouping', choices=['true',
'false'], type=str.lower,
+ help='Manages if nested groups are updated when memberUID
attributes in '
+ 'an Active Directory POSIX group change
(posixWinsyncMapNestedGrouping)')
+ parser.add_argument('--ms-sfu-schema', choices=['true',
'false'], type=str.lower,
+ help='Sets whether to the older Microsoft System Services for
Unix 3.0 (msSFU30) '
+ 'schema when syncing Posix attributes from Active
Directory (posixWinsyncMsSFUSchema)')
+
+
+def create_parser(subparsers):
+ winsync = subparsers.add_parser('posix-winsync', help='Manage and
configure The Posix Winsync API plugin')
+ subcommands = winsync.add_subparsers(help='action')
+ add_generic_plugin_parsers(subcommands, POSIXWinsyncPlugin)
+
+ edit = subcommands.add_parser('set', help='Edit the plugin')
+ edit.set_defaults(func=winsync_edit)
+ _add_parser_args(edit)
+
diff --git a/src/lib389/lib389/cli_conf/plugins/retrochangelog.py
b/src/lib389/lib389/cli_conf/plugins/retrochangelog.py
index 912c127..e677310 100644
--- a/src/lib389/lib389/cli_conf/plugins/retrochangelog.py
+++ b/src/lib389/lib389/cli_conf/plugins/retrochangelog.py
@@ -10,10 +10,11 @@ from lib389.plugins import RetroChangelogPlugin
from lib389.cli_conf import add_generic_plugin_parsers, generic_object_edit
arg_to_attr = {
- 'is-replicated': 'isReplicated',
+ 'is_replicated': 'isReplicated',
'attribute': 'nsslapd-attribute',
'directory': 'nsslapd-changelogdir',
- 'max-age': 'nsslapd-changelogmaxage',
+ 'max_age': 'nsslapd-changelogmaxage',
+ 'exclude_suffix': 'nsslapd-exclude-suffix'
}
@@ -24,7 +25,7 @@ def retrochangelog_edit(inst, basedn, log, args):
def _add_parser_args(parser):
- parser.add_argument('--is-replicated', choices=['true',
'false'],
+ parser.add_argument('--is-replicated', choices=['true',
'false'], type=str.lower,
help='Sets a flag to indicate on a change in the changelog
whether the change is newly made '
'on that server or whether it was replicated over from
another server (isReplicated)')
parser.add_argument('--attribute',
@@ -36,6 +37,9 @@ def _add_parser_args(parser):
parser.add_argument('--max-age',
help='This attribute specifies the maximum age of any entry
'
'in the changelog (nsslapd-changelogmaxage)')
+ parser.add_argument('--exclude-suffix',
+ help='This attribute specifies the suffix which will be
excluded '
+ 'from the scope of the plugin
(nsslapd-exclude-suffix)')
def create_parser(subparsers):
diff --git a/src/lib389/lib389/cli_conf/plugins/rootdn_ac.py
b/src/lib389/lib389/cli_conf/plugins/rootdn_ac.py
index 63838a9..1bd974d 100644
--- a/src/lib389/lib389/cli_conf/plugins/rootdn_ac.py
+++ b/src/lib389/lib389/cli_conf/plugins/rootdn_ac.py
@@ -27,20 +27,20 @@ def rootdn_edit(inst, basedn, log, args):
def _add_parser_args(parser):
- parser.add_argument('--allow-host',
+ parser.add_argument('--allow-host', nargs='+',
help='Sets what hosts, by fully-qualified domain name, the
root user is allowed to use '
'to access the Directory Server. Any hosts not listed
are implicitly denied '
'(rootdn-allow-host)')
- parser.add_argument('--deny-host',
+ parser.add_argument('--deny-host', nargs='+',
help='Sets what hosts, by fully-qualified domain name, the
root user is not allowed to use '
'to access the Directory Server Any hosts not listed are
implicitly allowed '
'(rootdn-deny-host). If an host address is listed in
both the rootdn-allow-host and '
'rootdn-deny-host attributes, it is denied
access.')
- parser.add_argument('--allow-ip',
+ parser.add_argument('--allow-ip', nargs='+',
help='Sets what IP addresses, either IPv4 or IPv6, for
machines the root user is allowed '
'to use to access the Directory Server Any IP addresses
not listed are implicitly '
'denied (rootdn-allow-ip)')
- parser.add_argument('--deny-ip',
+ parser.add_argument('--deny-ip', nargs='+',
help='Sets what IP addresses, either IPv4 or IPv6, for
machines the root user is not allowed '
'to use to access the Directory Server. Any IP addresses
not listed are implicitly '
'allowed (rootdn-deny-ip) If an IP address is listed in
both the rootdn-allow-ip and '
diff --git a/src/lib389/lib389/plugins.py b/src/lib389/lib389/plugins.py
index 71615e0..0b78c21 100644
--- a/src/lib389/lib389/plugins.py
+++ b/src/lib389/lib389/plugins.py
@@ -122,8 +122,22 @@ class AttributeUniquenessPlugin(Plugin):
:type dn: str
"""
+ _plugin_properties = {
+ 'nsslapd-pluginEnabled': 'off',
+ 'nsslapd-pluginPath': 'libattr-unique-plugin',
+ 'nsslapd-pluginInitfunc': 'NSUniqueAttr_Init',
+ 'nsslapd-pluginType': 'betxnpreoperation',
+ 'nsslapd-plugin-depends-on-type': 'database',
+ 'nsslapd-pluginId': 'NSUniqueAttr',
+ 'nsslapd-pluginVendor': '389 Project',
+ 'nsslapd-pluginVersion': 'none',
+ 'nsslapd-pluginDescription': 'Enforce unique attribute values',
+ }
+
def __init__(self, instance, dn="cn=attribute
uniqueness,cn=plugins,cn=config"):
super(AttributeUniquenessPlugin, self).__init__(instance, dn)
+ self._protected = False
+ self._create_objectclasses = ['top', 'nsslapdplugin',
'extensibleObject']
## These are some wrappers to the important attributes
# This plugin will be "tricky" in that it can have "many"
instance
@@ -170,14 +184,18 @@ class AttributeUniquenessPlugins(DSLdapObjects):
"""
def __init__(self, instance, basedn="cn=plugins,cn=config"):
- super(Plugins, self).__init__(instance=instance)
- self._objectclasses = ['top', 'nsslapdplugin']
+ super(DSLdapObjects, self).__init__(instance)
+ self._instance = instance
+ self._objectclasses = ['top', 'nsslapdplugin',
'extensibleObject']
self._filterattrs = ['cn', 'nsslapd-pluginPath']
self._childobject = AttributeUniquenessPlugin
self._basedn = basedn
# This is used to allow entry to instance to work
self._list_attrlist = ['dn', 'nsslapd-pluginPath']
self._search_filter = "(nsslapd-pluginId=NSUniqueAttr)"
+ self._scope = ldap.SCOPE_SUBTREE
+ self._server_controls = None
+ self._client_controls = None
def list(self):
"""Get a list of all plugin instances where nsslapd-pluginId:
NSUniqueAttr
@@ -215,7 +233,7 @@ class AttributeUniquenessPlugins(DSLdapObjects):
# Filter based on the objectclasses and the basedn
# Based on the selector, we should filter on that too.
# This will yield and & filter for objectClass with as many terms as needed.
- filterstr = "&(cn=%s)%s" % (selector, self._search_filter)
+ filterstr = "(&(cn=%s)%s)" % (selector, self._search_filter)
self._log.debug('_gen_selector filter = %s' % filterstr)
return self._instance.search_ext_s(
base=self._basedn,
@@ -1185,21 +1203,19 @@ class LinkedAttributesPlugin(Plugin):
def __init__(self, instance, dn="cn=Linked
Attributes,cn=plugins,cn=config"):
super(LinkedAttributesPlugin, self).__init__(instance, dn)
- def fixup(self, basedn, _filter=None):
+ def fixup(self, linkdn):
"""Create a fixup linked attributes task
- :param basedn: Basedn to fix up
- :type basedn: str
- :param _filter: a filter for entries to fix up
- :type _filter: str
+ :param linkdn: Link DN to fix up
+ :type linkdn: str
:returns: an instance of Task(DSLdapObject)
"""
task = tasks.FixupLinkedAttributesTask(self._instance)
- task_properties = {'basedn': basedn}
- if _filter is not None:
- task_properties['filter'] = _filter
+ task_properties = {}
+ if linkdn is not None:
+ task_properties['linkdn'] = linkdn
task.create(properties=task_properties)
return task
@@ -1235,6 +1251,7 @@ class LinkedAttributesConfigs(DSLdapObjects):
super(LinkedAttributesConfigs, self).__init__(instance)
self._objectclasses = ['top', 'extensibleObject']
self._filterattrs = ['cn']
+ self._scope = ldap.SCOPE_ONELEVEL
self._childobject = LinkedAttributesConfig
self._basedn = basedn
@@ -1265,6 +1282,80 @@ class PassThroughAuthenticationPlugin(Plugin):
return result
+class POSIXWinsyncPlugin(Plugin):
+ """A single instance of Posix Winsync API plugin entry
+
+ :param instance: An instance
+ :type instance: lib389.DirSrv
+ :param dn: Entry DN
+ :type dn: str
+ """
+
+ def __init__(self, instance, dn="cn=Posix Winsync
API,cn=plugins,cn=config"):
+ super(POSIXWinsyncPlugin, self).__init__(instance, dn)
+
+
+class PAMPassThroughAuthPlugin(Plugin):
+ """A single instance of PAM Pass Through Auth plugin entry
+
+ :param instance: An instance
+ :type instance: lib389.DirSrv
+ :param dn: Entry DN
+ :type dn: str
+ """
+
+ def __init__(self, instance, dn="cn=PAM Pass Through
Auth,cn=plugins,cn=config"):
+ super(PAMPassThroughAuthPlugin, self).__init__(instance, dn)
+
+
+class PAMPassThroughAuthConfig(Plugin):
+ """A single instance of PAM Pass Through Auth config entry
+
+ :param instance: An instance
+ :type instance: lib389.DirSrv
+ :param dn: Entry DN
+ :type dn: str
+ """
+
+ _plugin_properties = {
+ 'cn' : 'USN',
+ 'nsslapd-pluginEnabled': 'off',
+ 'nsslapd-pluginPath': 'libpam-passthru-plugin',
+ 'nsslapd-pluginInitfunc': 'pam_passthruauth_init',
+ 'nsslapd-pluginType': 'betxnpreoperation',
+ 'nsslapd-plugin-depends-on-type': 'database',
+ 'nsslapd-pluginId': 'PAM',
+ 'nsslapd-pluginVendor': '389 Project',
+ 'nsslapd-pluginVersion': '1.3.7.0',
+ 'nsslapd-pluginDescription': 'PAM Pass Through Auth plugin'
+ }
+
+ def __init__(self, instance, dn=None):
+ super(PAMPassThroughAuthConfig, self).__init__(instance, dn)
+ self._rdn_attribute = 'cn'
+ self._must_attributes = ['cn']
+ self._create_objectclasses = ['top', 'extensibleObject',
'nsslapdplugin', 'pamConfig']
+ self._protected = False
+
+
+class PAMPassThroughAuthConfigs(DSLdapObjects):
+ """A DSLdapObjects entity which represents PAM Pass Through Auth
config entry
+
+ :param instance: An instance
+ :type instance: lib389.DirSrv
+ :param basedn: Base DN for all account entries below
+ :type basedn: str
+ """
+
+ def __init__(self, instance, basedn="cn=PAM Pass Through
Auth,cn=plugins,cn=config"):
+ super(PAMPassThroughAuthConfigs, self).__init__(instance)
+ self._objectclasses = ['top', 'extensibleObject',
'nsslapdplugin', 'pamConfig']
+ self._filterattrs = ['cn']
+ self._scope = ldap.SCOPE_ONELEVEL
+ self._childobject = PAMPassThroughAuthConfig
+ self._basedn = basedn
+
+
class USNPlugin(Plugin):
"""A single instance of USN (Update Sequence Number) plugin entry
diff --git a/src/lib389/lib389/tasks.py b/src/lib389/lib389/tasks.py
index d98b3e0..b55c29f 100644
--- a/src/lib389/lib389/tasks.py
+++ b/src/lib389/lib389/tasks.py
@@ -131,7 +131,6 @@ class FixupLinkedAttributesTask(Task):
dn = "cn=" + self.cn + "," + DN_FIXUP_LINKED_ATTIBUTES
super(FixupLinkedAttributesTask, self).__init__(instance, dn)
- self._must_attributes.extend(['basedn'])
class MemberOfFixupTask(Task):
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.