parsing, but need to finish extended value validations for confparser and then get to work actually making the stuff go
This commit is contained in:
parent
7c0c7bf5c0
commit
0682137b21
@ -645,6 +645,13 @@
|
||||
<xs:attribute name="keyid" type="t_gpg_keyid" use="required"/>
|
||||
<xs:attribute name="publish" type="xs:boolean" use="optional"/>
|
||||
<xs:attribute name="prompt_passphrase" type="xs:boolean" use="required"/>
|
||||
<xs:attribute name="passphrase" use="optional">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="[!"#$%&\\'\(\)\*\+,\-\./0123456789:;<=>\?@ABCDEFGHIJKLMNOPQRSTUVWXYZ\[\]\^_`abcdefghijklmnopqrstuvwxyz\{\|\}~ ]+"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="gnupghome" use="optional">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
|
@ -56,7 +56,7 @@ class Conf(object):
|
||||
self.cfg = {}
|
||||
if validate_cfg:
|
||||
# Validation post-substitution
|
||||
self.validate()
|
||||
self.validate(parsed = False)
|
||||
|
||||
def get_pki_obj(self, pki, pki_type):
|
||||
elem = {}
|
||||
@ -82,8 +82,7 @@ class Conf(object):
|
||||
return(elem)
|
||||
|
||||
def get_source(self, source, item, _source):
|
||||
_source_item = {'flags': [],
|
||||
'fname': None}
|
||||
_source_item = {'flags': [], 'fname': None}
|
||||
elem = source.xpath('./{0}'.format(item))[0]
|
||||
if item == 'checksum':
|
||||
if elem.get('explicit', False):
|
||||
@ -132,6 +131,8 @@ class Conf(object):
|
||||
return(_source_item)
|
||||
|
||||
def get_xsd(self):
|
||||
if isinstance(self.xsd, lxml.etree.XMLSchema):
|
||||
return(self.xsd)
|
||||
if not self.xsd:
|
||||
path = os.path.join(os.path.dirname(__file__), 'bdisk.xsd')
|
||||
else:
|
||||
@ -231,10 +232,12 @@ class Conf(object):
|
||||
for e in self.profile.xpath(_xpath):
|
||||
for se in e:
|
||||
if not isinstance(se, lxml.etree._Comment):
|
||||
self.cfg[t][se.tag] = se.text
|
||||
self.cfg[t][se.tag] = transform.xml2py(se.text,
|
||||
attrib = False)
|
||||
for e in ('desc', 'uri', 'ver', 'max_recurse'):
|
||||
_xpath = './meta/{0}/text()'.format(e)
|
||||
self.cfg[e] = self.profile.xpath(_xpath)[0]
|
||||
self.cfg[e] = transform.xml2py(self.profile.xpath(_xpath)[0],
|
||||
attrib = False)
|
||||
# HERE is where we would handle regex patterns.
|
||||
# But we don't, because they're in self.xml_suppl.btags['regex'].
|
||||
#self.cfg['regexes'] = {}
|
||||
@ -249,7 +252,7 @@ class Conf(object):
|
||||
self.cfg['pki'] = {'clients': []}
|
||||
elem = self.profile.xpath('./pki')[0]
|
||||
self.cfg['pki']['overwrite'] = transform.xml2py(
|
||||
elem.get('overwrite', 'no'))
|
||||
elem.get('overwrite', 'false'))
|
||||
ca = elem.xpath('./ca')[0]
|
||||
clients = elem.xpath('./client')
|
||||
self.cfg['pki']['ca'] = self.get_pki_obj(ca, 'ca')
|
||||
@ -266,7 +269,9 @@ class Conf(object):
|
||||
'uuid': None}
|
||||
for a in self.cfg['profile']:
|
||||
if a in self.profile.attrib:
|
||||
self.cfg['profile'][a] = self.profile.attrib[a]
|
||||
self.cfg['profile'][a] = transform.xml2py(
|
||||
self.profile.attrib[a],
|
||||
attrib = True)
|
||||
return()
|
||||
|
||||
def parse_sources(self):
|
||||
@ -306,13 +311,49 @@ class Conf(object):
|
||||
attrib = False)
|
||||
return()
|
||||
|
||||
def validate(self):
|
||||
# TODO: perform further validations that we can't do in XSD.
|
||||
def validate(self, parsed = False):
|
||||
xsd = self.get_xsd()
|
||||
self.xsd = etree.XMLSchema(xsd)
|
||||
if not isinstance(xsd, lxml.etree.XMLSchema):
|
||||
self.xsd = etree.XMLSchema(xsd)
|
||||
else:
|
||||
pass
|
||||
# This would return a bool if it validates or not.
|
||||
#self.xsd.validate(self.xml)
|
||||
# We want to get a more detailed exception.
|
||||
xml = etree.fromstring(self.xml_suppl.return_full())
|
||||
self.xsd.assertValid(xml)
|
||||
if parsed:
|
||||
# TODO: perform further validations that we can't do in XSD.
|
||||
# We wait until after it's parsed to evaluate because otherwise we
|
||||
# can't use utils.valid().
|
||||
# We only bother with stuff that would hinder building, though -
|
||||
# e.g. we don't check that profile's UUID is a valid UUID4.
|
||||
# URLs
|
||||
for url in (self.cfg['uri'], self.cfg['dev']['website']):
|
||||
if not valid.url(url):
|
||||
raise ValueError('{0} is not a valid URL.'.format(url))
|
||||
# Emails
|
||||
for k in self.cfg['gpg']['keys']:
|
||||
if not valid.email(k['email']):
|
||||
raise ValueError(
|
||||
'GPG key {0}: {1} is not a valid email '
|
||||
'address'.format(k['name'], k['email']))
|
||||
if not valid.email(self.cfg['dev']['email']):
|
||||
raise ValueError('{0} is not a valid email address'.format(
|
||||
self.cfg['dev']['email']))
|
||||
if self.cfg['pki']:
|
||||
if 'subject' in self.cfg['pki']['ca']:
|
||||
if not valid.email(
|
||||
self.cfg['pki']['ca']['subject']['emailAddress']):
|
||||
raise ValueError('{0} is not a valid email '
|
||||
'address'.format(
|
||||
self.cfg['pki']['ca']['subject']['emailAddress']))
|
||||
|
||||
if not self.cfg['pki'][x]['subject']:
|
||||
continue
|
||||
if not valid.email(
|
||||
self.cfg['pki'][x]['subject']['emailAddress']):
|
||||
raise ValueError('{0} is not a valid email '
|
||||
'address'.format(
|
||||
self.cfg['pki'][x]['subject']['email']))
|
||||
return()
|
||||
|
@ -77,6 +77,8 @@ class detect(object):
|
||||
|
||||
def password_hash_salt(self, salted_hash):
|
||||
_hash_list = salted_hash.split('$')
|
||||
if len(_hash_list) < 3:
|
||||
return(None)
|
||||
salt = _hash_list[2]
|
||||
return(salt)
|
||||
|
||||
@ -630,10 +632,28 @@ class transform(object):
|
||||
if _hash:
|
||||
acct['hash_algo'] = _hash
|
||||
else:
|
||||
raise ValueError(
|
||||
'Invalid salted password hash: {0}'.format(
|
||||
elem.text)
|
||||
)
|
||||
acct['hash_algo'] = None
|
||||
# We no longer raise ValueError. Per shadow(5):
|
||||
#######################################################
|
||||
# If the password field contains some string that is
|
||||
# not a valid result of crypt(3), for instance ! or *,
|
||||
# the user will not be able to use a unix password to
|
||||
# log in (but the user may log in the system by other
|
||||
# means).
|
||||
# This field may be empty, in which case no passwords
|
||||
# are required to authenticate as the specified login
|
||||
# name. However, some applications which read the
|
||||
# /etc/shadow file may decide not to permit any access
|
||||
# at all if the password field is empty.
|
||||
# A password field which starts with an exclamation
|
||||
# mark means that the password is locked. The remaining
|
||||
# characters on the line represent the password field
|
||||
# before the password was locked.
|
||||
#######################################################
|
||||
# raise ValueError(
|
||||
# 'Invalid salted password hash: {0}'.format(
|
||||
# elem.text)
|
||||
# )
|
||||
acct['salt_hash'] = elem.text
|
||||
acct['passphrase'] = None
|
||||
else:
|
||||
@ -873,13 +893,13 @@ class xml_supplicant(object):
|
||||
return(cfg)
|
||||
|
||||
def _parse_regexes(self):
|
||||
for regex in self.profile.xpath('//meta/regexes/pattern'):
|
||||
for regex in self.profile.xpath('./meta/regexes/pattern'):
|
||||
_key = 'regex%{0}'.format(regex.attrib['id'])
|
||||
self.btags['regex'][_key] = regex.text
|
||||
return()
|
||||
|
||||
def _parse_variables(self):
|
||||
for variable in self.profile.xpath('//meta/variables/variable'):
|
||||
for variable in self.profile.xpath('./meta/variables/variable'):
|
||||
self.btags['variable'][
|
||||
'variable%{0}'.format(variable.attrib['id'])
|
||||
] = variable.text
|
||||
@ -976,7 +996,6 @@ class xml_supplicant(object):
|
||||
return(path)
|
||||
|
||||
def return_full(self):
|
||||
#nsmap = self.return_naked_ns()
|
||||
# https://stackoverflow.com/a/22553145/733214
|
||||
local_xml = lxml.etree.Element('bdisk',
|
||||
nsmap = self.orig_xml.nsmap,
|
||||
|
@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
xmllint -schema ../bdisk/bdisk.xsd ../docs/examples/multi_profile.xml --noout
|
||||
xmllint -schema /opt/dev/bdisk/bdisk/bdisk.xsd /opt/dev/bdisk/docs/examples/multi_profile.xml --noout
|
||||
|
@ -43,10 +43,10 @@
|
||||
<!-- Salted/hashed password is "test" -->
|
||||
<rootpass hashed="true">$6$7KfIdtHTcXwVrZAC$LZGNeMNz7v5o/cYuA48FAxtZynpIwO5B1CPGXnOW5kCTVpXVt4SypRqfM.AoKkFt/O7MZZ8ySXJmxpELKmdlF1</rootpass>
|
||||
<user sudo="true">
|
||||
<username>{xpath%//meta/names/uxname/text()}</username>
|
||||
<username>{xpath%../../../meta/names/uxname/text()}</username>
|
||||
<!-- You can also use substitution from different profiles in this same configuration: -->
|
||||
<!-- <username>{xpath%//profile[@name='another_profile']/meta/names/uxname"}</username> -->
|
||||
<comment>{xpath%//meta/dev/author/text()}</comment>
|
||||
<comment>{xpath%../../../meta/dev/author/text()}</comment>
|
||||
<password hashed="false"
|
||||
hash_algo="sha512"
|
||||
salt="auto">testpassword</password>
|
||||
@ -153,7 +153,7 @@
|
||||
</subject>
|
||||
</client>
|
||||
</pki>
|
||||
<!-- If prompt_passphrase is "no" and passphrase attribute is not given for a gpg element, we will try to use a
|
||||
<!-- If prompt_passphrase is "false" and passphrase attribute is not given for a gpg element, we will try to use a
|
||||
blank passphrase for all operations. -->
|
||||
<gpg keyid="none"
|
||||
gnupghome="none"
|
||||
|
Loading…
Reference in New Issue
Block a user