# Copyright (c) 2015, The MITRE Corporation. All rights reserved.
# See LICENSE.txt for complete terms.
# builtin
import os
import collections
# relative
from .version import __version__ # noqa
# constants
_PKG_DIR = os.path.dirname(__file__)
XSD_ROOT = os.path.abspath(os.path.join(_PKG_DIR, 'xsd'))
# A cache of STIX and CybOX XML validators that speeds up consecutive calls to
# validate_xml() against non-bundled schema directories.
__xml_validators = collections.defaultdict(dict)
# A cache of STIX Profile validators to speed up consecutive calls to
# validate_profile()
__profile_validators = {}
[docs]def validate_xml(doc, version=None, schemas=None, schemaloc=False, klass=None):
"""Performs XML Schema validation against a `STIX`_ or `CybOX`_ document.
.. _STIX: http://stix.mitre.org/language/
.. _CybOX: http://cybox.mitre.org/language/
Args:
doc: A STIX/CybOX document to validate. This can be a filename,
file-like object, ``etree._Element`` or ``etree._ElementTree``
object.
version: The version of the STIX/CybOX document being validated. If
``None`` an attempt will be made to extract the version from `doc`.
schemas: A string path to a directory of STIX/CybOX schemas. If ``None``,
the validation code will leverage its bundled STIX/CybOX schemas.
schemaloc: Use ``xsi:schemaLocation`` attribute on `doc` to perform
validation.
klass: **Internal use only**. The validator klass to use for validating
`doc`.
Note:
The first time running this for a given `schemas` (or no `schemas`)
will take longer than following validation runs due to schema
compilation time.
Returns:
An instance of
:class:`.XmlValidationResults`.
Raises:
IOError: If `doc` is not a valid XML document or there is an issue
processing `schemas`.
.UnknownSTIXVersionError: If `version` is ``None`` and
`doc` does not contain a ``@version`` attribute value.
.UnknownCyboxVersionError: If `version` is ``None`` and `doc` does not
contain CybOX version information.
.InvalidSTIXVersionError: If `version` or the ``version``
attribute in `doc` contains an invalid STIX version number.
.InvalidCyboxVersionError: if `version` or the version information on
`doc` contain an invalid CybOX version number.
.ValidationError: If the class was not initialized with a schema
directory and `schemaloc` is ``False``.
.XMLSchemaImportError: If an error occurs while processing
the schemas required for validation.
.XMLSchemaIncludeError: If an error occurs while
processing ``xs:include`` directives.
"""
import sdv.validators
# Get the validator class required to validate `doc`. I.e., STIX or CybOX?
if not klass:
klass = sdv.validators.get_xml_validator_class(doc)
try:
validator = __xml_validators[klass][schemas]
except KeyError:
validator = klass(schema_dir=schemas)
__xml_validators[klass][schemas] = validator
return validator.validate(doc, version=version, schemaloc=schemaloc)
[docs]def validate_best_practices(doc, version=None):
"""Performs `Best Practices`_ validation against a STIX document.
.. _Best Practices: http://stixproject.github.io/documentation/suggested-practices/
Note:
This should be used together with :meth:`validate_xml` since this only
checks best practices and not schema-conformance.
Args:
doc: A STIX document to validate. This can be a filename, file-like
object, ``etree._Element`` or ``etree._ElementTree`` object.
version: The version of the STIX document being validated. If ``None``
an attempt will be made to extract the version from `doc`.
Returns:
An instance of
:class:`.BestPracticeValidationResults`.
Raises:
IOError: If `doc` is not a valid XML document.
.ValidationError: If `doc` is not a well-formed STIX document.
.UnknownSTIXVersionError: If `version` is ``None`` and
`doc` does not contain version information.
.InvalidSTIXVersionError: If `version` or the ``@version`` attribute
in `doc` contains an invalid STIX version number.
"""
import sdv.validators
validator = sdv.validators.STIXBestPracticeValidator()
return validator.validate(doc, version=version)
[docs]def validate_profile(doc, profile):
"""Performs `STIX Profile`_ validation against a STIX document.
.. _STIX Profile: http://stixproject.github.io/documentation/profiles/
Note:
This should be used together with :meth:`validate_xml` since this only
checks profile-conformance and not schema-conformance.
Args:
doc: A STIX document to validate. This can be a filename, file-like
object, ``etree._Element`` or ``etree._ElementTree`` object.
profile: A filename to a STIX Profile document.
Returns:
An instance of
:class:`.ProfileValidationResults`.
Raises:
IOError: If `doc` is not a valid XML document.
.ValidationError: If the input document is not a well-formed STIX
document.
.ProfileParseError: If an error occurred while attempting to
parse the `profile`.
"""
import sdv.validators
try:
validator = __profile_validators[profile]
except KeyError:
validator = sdv.validators.STIXProfileValidator(profile)
__profile_validators[profile] = validator
return validator.validate(doc)
[docs]def profile_to_xslt(profile):
"""Converts the `STIX Profile`_ `profile` into an XSLT representation.
.. _STIX Profile: http://stixproject.github.io/documentation/profiles/
Args:
profile: A filename to a STIX Profile document.
Returns:
An ``etree._ElementTree`` XSLT representation of `profile`.
Raises:
.ProfileParseError: If an error occurred while attempting to
parse the `profile`.
"""
import sdv.validators
try:
validator = __profile_validators[profile]
except KeyError:
validator = sdv.validators.STIXProfileValidator(profile)
__profile_validators[profile] = validator
return validator.xslt
[docs]def profile_to_schematron(profile):
"""Converts the `STIX Profile`_ `profile` into a Schematron representation.
.. _STIX Profile: http://stixproject.github.io/documentation/profiles/
Args:
profile: A filename to a STIX Profile document.
Returns:
An ``etree._ElementTree`` Schematron representation of `profile`.
Raises:
.ProfileParseError: If an error occurred while attempting to
parse the `profile`.
"""
import sdv.validators
try:
validator = __profile_validators[profile]
except KeyError:
validator = sdv.validators.STIXProfileValidator(profile)
__profile_validators[profile] = validator
return validator.schematron