From 68804df4b5ccc251c788a99b5682bb9aba973cb9 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Thu, 17 Jan 2013 12:53:20 -0500 Subject: read default Path metadata from config file properly --- src/lib/Bcfg2/Server/Plugin/helpers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/lib/Bcfg2/Server/Plugin/helpers.py') diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index acf6af1f8..41c450b4e 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -25,6 +25,7 @@ except ImportError: #: A dict containing default metadata for Path entries from bcfg2.conf DEFAULT_FILE_METADATA = Bcfg2.Options.OptionParser(dict( + configfile=Bcfg2.Options.CFILE, owner=Bcfg2.Options.MDATA_OWNER, group=Bcfg2.Options.MDATA_GROUP, mode=Bcfg2.Options.MDATA_MODE, @@ -32,8 +33,9 @@ DEFAULT_FILE_METADATA = Bcfg2.Options.OptionParser(dict( important=Bcfg2.Options.MDATA_IMPORTANT, paranoid=Bcfg2.Options.MDATA_PARANOID, sensitive=Bcfg2.Options.MDATA_SENSITIVE)) -DEFAULT_FILE_METADATA.parse(sys.argv[1:]) +DEFAULT_FILE_METADATA.parse([Bcfg2.Options.CFILE.cmd, Bcfg2.Options.CFILE]) del DEFAULT_FILE_METADATA['args'] +del DEFAULT_FILE_METADATA['configfile'] LOGGER = logging.getLogger(__name__) -- cgit v1.2.3-1-g7c22 From 9be9cfec322518f764be9766b27d24132fc6a66f Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Wed, 16 Jan 2013 13:28:06 -0500 Subject: added module-level OptionParser to avoid passing it as an argument or global all over --- src/lib/Bcfg2/Server/Plugin/helpers.py | 35 +++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'src/lib/Bcfg2/Server/Plugin/helpers.py') diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index 41c450b4e..0df568045 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -23,20 +23,6 @@ try: except ImportError: HAS_DJANGO = False -#: A dict containing default metadata for Path entries from bcfg2.conf -DEFAULT_FILE_METADATA = Bcfg2.Options.OptionParser(dict( - configfile=Bcfg2.Options.CFILE, - owner=Bcfg2.Options.MDATA_OWNER, - group=Bcfg2.Options.MDATA_GROUP, - mode=Bcfg2.Options.MDATA_MODE, - secontext=Bcfg2.Options.MDATA_SECONTEXT, - important=Bcfg2.Options.MDATA_IMPORTANT, - paranoid=Bcfg2.Options.MDATA_PARANOID, - sensitive=Bcfg2.Options.MDATA_SENSITIVE)) -DEFAULT_FILE_METADATA.parse([Bcfg2.Options.CFILE.cmd, Bcfg2.Options.CFILE]) -del DEFAULT_FILE_METADATA['args'] -del DEFAULT_FILE_METADATA['configfile'] - LOGGER = logging.getLogger(__name__) #: a compiled regular expression for parsing info and :info files @@ -51,7 +37,20 @@ INFO_REGEX = re.compile('owner:(\s)*(?P\S+)|' + 'mtime:(\s)*(?P\w+)|') -def bind_info(entry, metadata, infoxml=None, default=DEFAULT_FILE_METADATA): +def default_path_metadata(): + """ Get the default Path entry metadata from the config. + + :returns: dict of metadata attributes and their default values + """ + attrs = Bcfg2.Options.PATH_METADATA_OPTIONS.keys() + setup = Bcfg2.Options.get_option_parser() + if not set(attrs).issubset(setup.keys()): + setup.add_options(Bcfg2.Options.PATH_METADATA_OPTIONS) + setup.reparse(argv=[Bcfg2.Options.CFILE.cmd, Bcfg2.Options.CFILE]) + return dict([(k, setup[k]) for k in attrs]) + + +def bind_info(entry, metadata, infoxml=None, default=None): """ Bind the file metadata in the given :class:`Bcfg2.Server.Plugin.helpers.InfoXML` object to the given entry. @@ -68,6 +67,8 @@ def bind_info(entry, metadata, infoxml=None, default=DEFAULT_FILE_METADATA): :returns: None :raises: :class:`Bcfg2.Server.Plugin.exceptions.PluginExecutionError` """ + if default is None: + default = default_path_metadata() for attr, val in list(default.items()): entry.set(attr, val) if infoxml: @@ -1156,7 +1157,7 @@ class EntrySet(Debuggable): self.path = path self.entry_type = entry_type self.entries = {} - self.metadata = DEFAULT_FILE_METADATA.copy() + self.metadata = default_path_metadata() self.infoxml = None self.encoding = encoding @@ -1378,7 +1379,7 @@ class EntrySet(Debuggable): if event.filename == 'info.xml': self.infoxml = None elif event.filename in [':info', 'info']: - self.metadata = DEFAULT_FILE_METADATA.copy() + self.metadata = default_path_metadata() def bind_info_to_entry(self, entry, metadata): """ Shortcut to call :func:`bind_info` with the base -- cgit v1.2.3-1-g7c22 From 1a031fc131d950dd49dc425ac1726337d8e93910 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Thu, 17 Jan 2013 08:01:44 -0500 Subject: abstracted encryption support from Properties/CfgPrivateKeyCreator to StructFile --- src/lib/Bcfg2/Server/Plugin/helpers.py | 64 +++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) (limited to 'src/lib/Bcfg2/Server/Plugin/helpers.py') diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index 0df568045..c8e09d3d1 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -17,6 +17,12 @@ from Bcfg2.Server.Plugin.interfaces import Generator from Bcfg2.Server.Plugin.exceptions import SpecificityError, \ PluginExecutionError +try: + import Bcfg2.Encryption + HAS_CRYPTO = True +except ImportError: + HAS_CRYPTO = False + try: import django # pylint: disable=W0611 HAS_DJANGO = True @@ -571,13 +577,69 @@ class XMLFileBacked(FileBacked): class StructFile(XMLFileBacked): """ StructFiles are XML files that contain a set of structure file formatting logic for handling ```` and ```` - tags. """ + tags. + + .. ----- + .. autoattribute:: __identifier__ + """ #: If ``__identifier__`` is not None, then it must be the name of #: an XML attribute that will be required on the top-level tag of #: the file being cached __identifier__ = None + #: Whether or not encryption support is enabled in this file + encryption = True + + def __init__(self, filename, fam=None, should_monitor=False): + XMLFileBacked.__init__(self, filename, fam=fam, + should_monitor=should_monitor) + self.setup = Bcfg2.Options.get_option_parser() + + def Index(self): + Bcfg2.Server.Plugin.XMLFileBacked.Index(self) + if self.encryption: + strict = self.xdata.get( + "decrypt", + self.setup.cfp.get(Bcfg2.Encryption.CFG_SECTION, "decrypt", + default="strict")) == "strict" + for el in self.xdata.xpath("//*[@encrypted]"): + if not HAS_CRYPTO: + raise PluginExecutionError("Properties: M2Crypto is not " + "available: %s" % self.name) + try: + el.text = self._decrypt(el).encode('ascii', + 'xmlcharrefreplace') + except UnicodeDecodeError: + LOGGER.info("%s: Decrypted %s to gibberish, skipping" % + (self.name, el.tag)) + except Bcfg2.Encryption.EVPError: + msg = "Failed to decrypt %s element in %s" % (el.tag, + self.name) + if strict: + raise PluginExecutionError(msg) + else: + LOGGER.warning(msg) + Index.__doc__ = XMLFileBacked.Index.__doc__ + + def _decrypt(self, element): + """ Decrypt a single encrypted properties file element """ + if not element.text or not element.text.strip(): + return + passes = Bcfg2.Encryption.get_passphrases() + try: + passphrase = passes[element.get("encrypted")] + try: + return Bcfg2.Encryption.ssl_decrypt(element.text, passphrase) + except Bcfg2.Encryption.EVPError: + # error is raised below + pass + except KeyError: + # bruteforce_decrypt raises an EVPError with a sensible + # error message, so we just let it propagate up the stack + return Bcfg2.Encryption.bruteforce_decrypt(element.text) + raise Bcfg2.Encryption.EVPError("Failed to decrypt") + def _include_element(self, item, metadata): """ determine if an XML element matches the metadata """ if isinstance(item, lxml.etree._Comment): # pylint: disable=W0212 -- cgit v1.2.3-1-g7c22 From f8b31cfa1596a17b248e28b82362e2d5e542b8ff Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Thu, 17 Jan 2013 09:27:58 -0500 Subject: StructFile: minor cleanup --- src/lib/Bcfg2/Server/Plugin/helpers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/lib/Bcfg2/Server/Plugin/helpers.py') diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index c8e09d3d1..399ab6679 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -597,7 +597,7 @@ class StructFile(XMLFileBacked): self.setup = Bcfg2.Options.get_option_parser() def Index(self): - Bcfg2.Server.Plugin.XMLFileBacked.Index(self) + XMLFileBacked.Index(self) if self.encryption: strict = self.xdata.get( "decrypt", @@ -605,8 +605,8 @@ class StructFile(XMLFileBacked): default="strict")) == "strict" for el in self.xdata.xpath("//*[@encrypted]"): if not HAS_CRYPTO: - raise PluginExecutionError("Properties: M2Crypto is not " - "available: %s" % self.name) + raise PluginExecutionError("%s: M2Crypto is not available" + % self.name) try: el.text = self._decrypt(el).encode('ascii', 'xmlcharrefreplace') -- cgit v1.2.3-1-g7c22