nhairs / parsedmarc-fork

Experimental fork of PraseDMARC
https://nhairs.github.io/parsedmarc-fork/
Apache License 2.0
0 stars 1 forks source link

Cannot parse reports with empty <auth_results> XML field. #41

Closed nhairs closed 1 month ago

nhairs commented 1 month ago

The following error is throw in the unit tests.

>           auth_results = record["auth_results"].copy()
E           AttributeError: 'str' object has no attribute 'copy'

https://github.com/nhairs/parsedmarc-fork/blob/c37573fa60adc0ea35da4d1e6d0c36b02c2ea1fb/src/parsedmarc/parser.py#L490

Example XML snippet:

  <record>
    <row>
      <source_ip>199.230.200.36</source_ip>
      <count>1</count>
      <policy_evaluated>
        <disposition>none</disposition>
        <dkim>fail</dkim>
        <spf>fail</spf>
      </policy_evaluated>
    </row>
    <identifiers>
      <envelope_from></envelope_from>
      <header_from>example.com</header_from>
    </identifiers>
    <auth_results>
    </auth_results>
  </record>

The following samples contain this:

It looks like each of these reports will parse the "empty" auth_results element as a string rather than a list of empty fields.

In theory these are invalid reports as per the RFC there should always be at least a spf element.

   <xs:complexType name="SPFAuthResultType">
     <xs:all>
       <!-- The checked domain. -->
       <xs:element name="domain" type="xs:string" minOccurs="1"/>
       <!-- The scope of the checked domain. -->
       <xs:element name="scope" type="SPFDomainScope" minOccurs="1"/>
       <!-- The SPF verification result. -->
       <xs:element name="result" type="SPFResultType"
                   minOccurs="1"/>
     </xs:all>
   </xs:complexType>

   <!-- This element contains DKIM and SPF results, uninterpreted
        with respect to DMARC. -->
   <xs:complexType name="AuthResultType">
     <xs:sequence>
       <!-- There may be no DKIM signatures, or multiple DKIM
            signatures. -->
       <xs:element name="dkim" type="DKIMAuthResultType"
         minOccurs="0" maxOccurs="unbounded"/>
       <!-- There will always be at least one SPF result. -->
       <xs:element name="spf" type="SPFAuthResultType" minOccurs="1"
                   maxOccurs="unbounded"/>
     </xs:sequence>
   </xs:complexType>

   <!-- This element contains all the authentication results that
        were evaluated by the receiving system for the given set of
        messages. -->
   <xs:complexType name="RecordType">
     <xs:sequence>
       <xs:element name="row" type="RowType"/>
       <xs:element name="identifiers" type="IdentifierType"/>
       <xs:element name="auth_results" type="AuthResultType"/>
     </xs:sequence>
   </xs:complexType>

Related: I suspect that something is broken with running the unit tests in my local environment because these all pass (which suggests that this is fixed upstream and I'm somehow using that version rather than my forked version).

nhairs commented 1 month ago

@seanthegeek - FYI it looks like parsedmarc is also affected by this:

https://github.com/domainaware/parsedmarc/blob/92b12eaacfc707d04bfdfbe637a545e2a6778358/parsedmarc/__init__.py#L172