HOME


Mini Shell 1.0
DIR:/lib/python3.9/site-packages/authres/
Upload File :
Current File : //lib/python3.9/site-packages/authres/tests
# coding: utf-8

# Copyright © 2011-2012 Julian Mehnle <julian@mehnle.net>,
# Copyright © 2011-2013 Scott Kitterman <scott@kitterman.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#  https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Package for parsing ``Authentication-Results`` headers as defined in RFC 5451.
Optional support for authentication methods defined in RFCs 5617, 6008, 6212,
7489 and draft-ietf-dmarc-arc-protocol-05.
>>> import authres
>>> str(authres.AuthenticationResultsHeader('test.example.org', version=1))
'Authentication-Results: test.example.org 1; none'

Non-RFC example of no authentication with comment:
>>> import authres
>>> str(authres.AuthenticationResultsHeader(authserv_id = 'test.example.org',
... results = [authres.NoneAuthenticationResult(comment = 'SPF not checked for localhost')]))
'Authentication-Results: test.example.org; none (SPF not checked for localhost)'

>>> import authres
>>> arobj = authres.AuthenticationResultsHeader.parse('Authentication-Results: example.com; spf=pass smtp.mailfrom=example.net')
>>> str(arobj.authserv_id)
'example.com'
>>> str(arobj.results[0])
'spf=pass smtp.mailfrom=example.net'
>>> str(arobj.results[0].method)
'spf'
>>> str(arobj.results[0].result)
'pass'
>>> str(arobj.results[0].smtp_mailfrom)
'example.net'
>>> str(arobj.results[0].smtp_helo)
'None'
>>> str(arobj.results[0].reason)
'None'
>>> str(arobj.results[0].properties[0].type)
'smtp'
>>> str(arobj.results[0].properties[0].name)
'mailfrom'
>>> str(arobj.results[0].properties[0].value)
'example.net'

# Missing parsing header comment.
#FIXME
>>> import authres
>>> arobj = authres.AuthenticationResultsHeader.parse('Authentication-Results: example.com; auth=pass (cram-md5) smtp.auth=sender@example.net; spf=pass smtp.mailfrom=example.net')
>>> str(arobj.authserv_id)
'example.com'
>>> str(arobj.results[0])
'auth=pass smtp.auth=sender@example.net'
>>> str(arobj.results[0].method)
'auth'
>>> str(arobj.results[0].result)
'pass'
>>> str(arobj.results[0].smtp_auth)
'sender@example.net'
>>> str(arobj.results[0].properties[0].type)
'smtp'
>>> str(arobj.results[0].properties[0].name)
'auth'
>>> str(arobj.results[0].properties[0].value)
'sender@example.net'
>>> str(arobj.results[1])
'spf=pass smtp.mailfrom=example.net'
>>> str(arobj.results[1].method)
'spf'
>>> str(arobj.results[1].result)
'pass'
>>> str(arobj.results[1].smtp_mailfrom)
'example.net'
>>> str(arobj.results[1].properties[0].type)
'smtp'
>>> str(arobj.results[1].properties[0].name)
'mailfrom'
>>> str(arobj.results[1].properties[0].value)
'example.net'

>>> import authres
>>> arobj = authres.AuthenticationResultsHeader.parse('Authentication-Results: example.com; sender-id=pass header.from=example.com')
>>> str(arobj.authserv_id)
'example.com'
>>> str(arobj.results[0])
'sender-id=pass header.from=example.com'
>>> str(arobj.results[0].method)
'sender-id'
>>> str(arobj.results[0].result)
'pass'
>>> str(arobj.results[0].header_from)
'example.com'
>>> try:
...     str(arobj.results[0].smtp_mailfrom)
... except AttributeError as x:
...     print(x)
'SenderIDAuthenticationResult' object has no attribute 'smtp_mailfrom'
>>> str(arobj.results[0].properties[0].type)
'header'
>>> str(arobj.results[0].properties[0].name)
'from'
>>> str(arobj.results[0].properties[0].value)
'example.com'

# Missing parsing header comment.
#FIXME
>>> import authres
>>> arobj = authres.AuthenticationResultsHeader.parse('Authentication-Results: example.com; sender-id=fail header.from=example.com; dkim=pass (good signature) header.i=sender@example.com')
>>> str(arobj.authserv_id)
'example.com'
>>> str(arobj.results[0])
'sender-id=fail header.from=example.com'
>>> str(arobj.results[0].method)
'sender-id'
>>> str(arobj.results[0].result)
'fail'
>>> str(arobj.results[0].header_from)
'example.com'
>>> str(arobj.results[0].properties[0].type)
'header'
>>> str(arobj.results[0].properties[0].name)
'from'
>>> str(arobj.results[0].properties[0].value)
'example.com'
>>> str(arobj.results[1])
'dkim=pass header.i=sender@example.com'
>>> str(arobj.results[1].method)
'dkim'
>>> str(arobj.results[1].result)
'pass'
>>> str(arobj.results[1].header_i)
'sender@example.com'
>>> str(arobj.results[1].properties[0].type)
'header'
>>> str(arobj.results[1].properties[0].name)
'i'
>>> str(arobj.results[1].properties[0].value)
'sender@example.com'

RFC 5451 B.6(1) modified to use d= instead of i=
>>> import authres
>>> dar_pass = authres.DKIMAuthenticationResult(result = 'pass', result_comment = 'good signature',
... header_d = 'mail-router.example.net')
>>> dar_fail = authres.DKIMAuthenticationResult(result = 'fail',
... header_d = 'newyork.example.com', result_comment = 'bad signature')
>>> str(authres.AuthenticationResultsHeader(authserv_id = 'example.com',
... results = [dar_pass, dar_fail]))
'Authentication-Results: example.com; dkim=pass (good signature) header.d=mail-router.example.net; dkim=fail (bad signature) header.d=newyork.example.com'
>>> dar_pass.match_signature('mail-router.example.net')
True
>>> dar_fail.match_signature('mail-router.example.net')
False

RFC 5451 B.6(1) modified to use d= instead of i= with header.a and header.s added
>>> import authres
>>> dsr_pass = authres.DKIMAuthenticationResult(result = 'pass', result_comment = 'good signature',
... header_d = 'mail-router.example.net', header_a = 'rsa-sha256', header_s = 'default')
>>> dsr_fail = authres.DKIMAuthenticationResult(result = 'fail',
... header_d = 'newyork.example.com', result_comment = 'bad signature')
>>> str(authres.AuthenticationResultsHeader(authserv_id = 'example.com',
... results = [dsr_pass, dsr_fail]))
'Authentication-Results: example.com; dkim=pass (good signature) header.d=mail-router.example.net header.a=rsa-sha256 header.s=default; dkim=fail (bad signature) header.d=newyork.example.com'
>>> dsr_pass.match_signature_algorithm('mail-router.example.net', 'rsa-sha256')
True
>>> dsr_fail.match_signature_algorithm('mail-router.example.net', 'rsa-sha256')
False

Header from dcrup testing
>>> import authres
>>> dss_pass = authres.DKIMAuthenticationResult(result = 'pass', result_comment = 'Good 256 bit ed25519-sha256 signature.',
... header_d = 'example.com', header_i = '@example.com', header_a = 'ed25519-sha256')
>>> dss_fail = authres.DKIMAuthenticationResult(result = 'fail', result_comment = 'Bad 1024 bit rsa-sha256 signature.',
... header_d = 'example.com', header_i = '@example.com', header_a = 'rsa-sha256')
>>> str(authres.AuthenticationResultsHeader(authserv_id = 'relay02.example.org',
... results = [dss_pass, dss_fail]))
'Authentication-Results: relay02.example.org; dkim=pass (Good 256 bit ed25519-sha256 signature.) header.d=example.com header.i=@example.com header.a=ed25519-sha256; dkim=fail (Bad 1024 bit rsa-sha256 signature.) header.d=example.com header.i=@example.com header.a=rsa-sha256'

# Missing parsing header comment.
#FIXME
>>> import authres
>>> arobj = authres.AuthenticationResultsHeader.parse('Authentication-Results: example.com; dkim=pass (good signature) header.i=@mail-router.example.net; dkim=fail (bad signature) header.i=@newyork.example.com')
>>> str(arobj.results[0])
'dkim=pass header.i=@mail-router.example.net'
>>> str(arobj.results[0].method)
'dkim'
>>> str(arobj.results[0].result)
'pass'
>>> str(arobj.results[0].header_i)
'@mail-router.example.net'
>>> str(arobj.results[0].properties[0].type)
'header'
>>> str(arobj.results[0].properties[0].name)
'i'
>>> str(arobj.results[0].properties[0].value)
'@mail-router.example.net'
>>> str(arobj.results[1])
'dkim=fail header.i=@newyork.example.com'
>>> str(arobj.results[1].method)
'dkim'
>>> str(arobj.results[1].result)
'fail'
>>> str(arobj.results[1].header_i)
'@newyork.example.com'
>>> str(arobj.results[1].properties[0].type)
'header'
>>> str(arobj.results[1].properties[0].name)
'i'
>>> str(arobj.results[1].properties[0].value)
'@newyork.example.com'

RFC 5451bis C.6(1) modified to use d= instead of i=
>>> import authres
>>> dar_pass = authres.DKIMAuthenticationResult(result = 'pass', reason = 'good signature',
... header_d = 'mail-router.example.net')
>>> dar_fail = authres.DKIMAuthenticationResult(result = 'fail',
... header_d = 'newyork.example.com', reason = 'bad signature')
>>> str(authres.AuthenticationResultsHeader(authserv_id = 'example.com',
... results = [dar_pass, dar_fail]))
'Authentication-Results: example.com; dkim=pass reason="good signature" header.d=mail-router.example.net; dkim=fail reason="bad signature" header.d=newyork.example.com'
>>> dar_pass.match_signature('mail-router.example.net')
True
>>> dar_fail.match_signature('mail-router.example.net')
False

# Missing parsing header comment.
#FIXME
>>> import authres
>>> arobj = authres.AuthenticationResultsHeader.parse('Authentication-Results: example.com; dkim=pass reason="good signature" header.i=@mail-router.example.net; dkim=fail reason="bad signature" header.i=@newyork.example.com')
>>> str(arobj.results[0])
'dkim=pass reason="good signature" header.i=@mail-router.example.net'
>>> str(arobj.results[0].method)
'dkim'
>>> str(arobj.results[0].result)
'pass'
>>> str(arobj.results[0].reason)
'good signature'
>>> str(arobj.results[0].header_i)
'@mail-router.example.net'
>>> str(arobj.results[0].properties[0].type)
'header'
>>> str(arobj.results[0].properties[0].name)
'i'
>>> str(arobj.results[0].properties[0].value)
'@mail-router.example.net'
>>> str(arobj.results[1])
'dkim=fail reason="bad signature" header.i=@newyork.example.com'
>>> str(arobj.results[1].method)
'dkim'
>>> str(arobj.results[1].result)
'fail'
>>> str(arobj.results[1].reason)
'bad signature'
>>> str(arobj.results[1].header_i)
'@newyork.example.com'
>>> str(arobj.results[1].properties[0].type)
'header'
>>> str(arobj.results[1].properties[0].name)
'i'
>>> str(arobj.results[1].properties[0].value)
'@newyork.example.com'

RFC 5451 B.6(2)
>>> import authres
>>> str(authres.AuthenticationResultsHeader(authserv_id = 'example.net',
... results = [authres.DKIMAuthenticationResult(result = 'pass', result_comment = 'good signature',
... header_i = '@newyork.example.com')]))
'Authentication-Results: example.net; dkim=pass (good signature) header.i=@newyork.example.com'

# Missing parsing header comment.
#FIXME
import authres
>>> arobj = authres.AuthenticationResultsHeader.parse('Authentication-Results: example.net; dkim=pass (good signature) header.i=@newyork.example.com')
>>> str(arobj.results[0])
'dkim=pass header.i=@newyork.example.com'
>>> str(arobj.results[0].method)
'dkim'
>>> str(arobj.results[0].result)
'pass'
>>> str(arobj.results[0].header_i)
'@newyork.example.com'
>>> str(arobj.results[0].properties[0].type)
'header'
>>> str(arobj.results[0].properties[0].name)
'i'
>>> str(arobj.results[0].properties[0].value)
'@newyork.example.com'

RFC 6008 A.1
>>> import authres
>>> import authres.dkim_b
>>> authres_context = authres.FeatureContext(authres.dkim_b)
>>> dar_b = authres.dkim_b.DKIMAuthenticationResult(result = 'pass', result_comment = 'good signature',
... header_d = 'newyork.example.com', header_b = 'oINEO8hg')
>>> str(authres_context.header(authserv_id = 'mail-router.example.net',
... results = [dar_b, authres.dkim_b.DKIMAuthenticationResult(result = 'fail',
... header_d = 'newyork.example.com', result_comment = 'bad signature', header_b = 'EToRSuvU')]))
'Authentication-Results: mail-router.example.net; dkim=pass (good signature) header.d=newyork.example.com header.b=oINEO8hg; dkim=fail (bad signature) header.d=newyork.example.com header.b=EToRSuvU'

RFC 6008 section 4
>>> authres.dkim_b.DKIMAuthenticationResult.match_signature(dar_b,'newyork.example.com','oINEO8h')
False
>>> authres.dkim_b.DKIMAuthenticationResult.match_signature(dar_b,'newyork.example.com','oINEO8hg')
True
>>> authres.dkim_b.DKIMAuthenticationResult.match_signature(dar_b,'newyork.example.com','oINEO8hq')
False
>>> authres.dkim_b.DKIMAuthenticationResult.match_signature(dar_b,'newyork.example.com','oINEO8hq1')
False
>>> dar_b2 = authres.dkim_b.DKIMAuthenticationResult(result = 'pass', result_comment = 'good signature',
... header_d = 'newyork.example.com', header_b = 'oINEO8')
>>> authres.dkim_b.DKIMAuthenticationResult.match_signature(dar_b2,'newyork.example.com','oINEO8')
True
>>> authres.dkim_b.DKIMAuthenticationResult.match_signature(dar_b2,'newyork.example.com','oINEO8hq')
False
>>> authres.dkim_b.DKIMAuthenticationResult.match_signature(dar_b2,'newyork.example.com', None)
False
>>> authres.dkim_b.DKIMAuthenticationResult.match_signature(dar_b2,'newyork.example.com', None)
False
>>> dar_b_none = authres.dkim_b.DKIMAuthenticationResult(result = 'pass', result_comment = 'good signature',
... header_d = 'newyork.example.com')
>>> authres.dkim_b.DKIMAuthenticationResult.match_signature(dar_b_none,'newyork.example.com', None)
True
>>> authres.dkim_b.DKIMAuthenticationResult.match_signature(dar_b_none,'newyork.example.com', None, strict=True)
False
>>> authres.dkim_b.DKIMAuthenticationResult.match_signature(dar_b_none,'newyork.example.com','oINEO8hq')
True
>>> authres.dkim_b.DKIMAuthenticationResult.match_signature(dar_b_none,'newjersey.example.com', None)
False

# Missing parsing header comment.
#FIXME
>>> arobj = authres_context.parse('Authentication-Results: mail-router.example.net; dkim=pass (good signature) header.d=newyork.example.com header.b=oINEO8hg; dkim=fail (bad signature) header.d=newyork.example.com header.b=EToRSuvU')
>>> str(arobj.results[0])
'dkim=pass header.d=newyork.example.com header.b=oINEO8hg'
>>> str(arobj.results[0].method)
'dkim'
>>> str(arobj.results[0].result)
'pass'
>>> str(arobj.results[0].header_d)
'newyork.example.com'
>>> str(arobj.results[0].properties[0].type)
'header'
>>> str(arobj.results[0].properties[0].name)
'd'
>>> str(arobj.results[0].properties[0].value)
'newyork.example.com'
>>> str(arobj.results[0].header_b)
'oINEO8hg'
>>> str(arobj.results[0].properties[1].type)
'header'
>>> str(arobj.results[0].properties[1].name)
'b'
>>> str(arobj.results[0].properties[1].value)
'oINEO8hg'
>>> str(arobj.results[1].method)
'dkim'
>>> str(arobj.results[1].result)
'fail'
>>> str(arobj.results[1].header_d)
'newyork.example.com'
>>> str(arobj.results[1].properties[0].type)
'header'
>>> str(arobj.results[1].properties[0].name)
'd'
>>> str(arobj.results[1].properties[0].value)
'newyork.example.com'
>>> str(arobj.results[1].header_b)
'EToRSuvU'
>>> str(arobj.results[1].properties[1].type)
'header'
>>> str(arobj.results[1].properties[1].name)
'b'
>>> str(arobj.results[1].properties[1].value)
'EToRSuvU'

# RFC 5617 (based on RFC text, no examples provided)
>>> import authres
>>> import authres.dkim_adsp
>>> authres_context = authres.FeatureContext(authres.dkim_adsp)
>>> str(authres_context.header(authserv_id = 'example.com',
... results = [authres.DKIMAuthenticationResult(result = 'fail', result_comment = 'bad signature',
... header_d = 'bank.example.net'), authres.dkim_adsp.DKIMADSPAuthenticationResult(result = 'discard',
... header_from = 'phish@bank.example.com', result_comment = 'From domain and d= domain match')]))
'Authentication-Results: example.com; dkim=fail (bad signature) header.d=bank.example.net; dkim-adsp=discard (From domain and d= domain match) header.from=phish@bank.example.com'

# Missing parsing header comment.
#FIXME
>>> arobj = authres_context.parse('Authentication-Results: example.com; dkim=fail (bad signature) header.d=bank.example.net; dkim-adsp=discard (From domain and d= domain match) header.from=phish@bank.example.com')
>>> str(arobj.results[1])
'dkim-adsp=discard header.from=phish@bank.example.com'
>>> str(arobj.results[1].method)
'dkim-adsp'
>>> str(arobj.results[1].result)
'discard'
>>> str(arobj.results[1].header_from)
'phish@bank.example.com'
>>> str(arobj.results[1].properties[0].type)
'header'
>>> str(arobj.results[1].properties[0].name)
'from'
>>> str(arobj.results[1].properties[0].value)
'phish@bank.example.com'

RFC 6212 A.1
>>> import authres
>>> import authres.dkim_b, authres.vbr
>>> authres_context = authres.FeatureContext(authres.dkim_b, authres.vbr)
>>> str(authres_context.header(authserv_id = 'mail-router.example.net',
... results = [authres.dkim_b.DKIMAuthenticationResult(result = 'pass', result_comment = 'good signature',
... header_d = 'newyork.example.com', header_b = 'oINEO8hg'), authres.vbr.VBRAuthenticationResult(result = 'pass',
... header_md = 'newyork.example.com', result_comment = 'voucher.example.net',
... header_mv = 'voucher.example.org')]))
'Authentication-Results: mail-router.example.net; dkim=pass (good signature) header.d=newyork.example.com header.b=oINEO8hg; vbr=pass (voucher.example.net) header.md=newyork.example.com header.mv=voucher.example.org'

# Missing parsing header comment.
#FIXME
>>> arobj = authres_context.parse('Authentication-Results: mail-router.example.net; dkim=pass (good signature) header.d=newyork.example.com header.b=oINEO8hg; vbr=pass (voucher.example.net) header.md=newyork.example.com header.mv=voucher.example.org')
>>> str(arobj.results[1])
'vbr=pass header.md=newyork.example.com header.mv=voucher.example.org'
>>> str(arobj.results[1].method)
'vbr'
>>> str(arobj.results[1].result)
'pass'
>>> str(arobj.results[1].header_md)
'newyork.example.com'
>>> str(arobj.results[1].properties[0].type)
'header'
>>> str(arobj.results[1].properties[0].name)
'md'
>>> str(arobj.results[1].properties[0].value)
'newyork.example.com'
>>> str(arobj.results[1].header_mv)
'voucher.example.org'
>>> str(arobj.results[1].properties[1].type)
'header'
>>> str(arobj.results[1].properties[1].name)
'mv'
>>> str(arobj.results[1].properties[1].value)
'voucher.example.org'

# RFC 7489 DMARC example from opendmarc
>>> import authres
>>> import authres.dmarc
>>> new_context = authres.FeatureContext(authres.dmarc)
>>> str(new_context.header(authserv_id = 'mail-router.example.net',
... results = [authres.dmarc.DMARCAuthenticationResult(result = 'pass',
... header_from = 'example.com')]))
'Authentication-Results: mail-router.example.net; dmarc=pass header.from=example.com'

# Missing parsing header comment.
#FIXME
>>> newarobj = new_context.parse('Authentication-Results: mail-router.example.net; dmarc=pass header.from=example.com')
>>> str(newarobj.results[0])
'dmarc=pass header.from=example.com'
>>> str(newarobj.results[0].method)
'dmarc'
>>> str(newarobj.results[0].result)
'pass'
>>> str(newarobj.results[0].header_from)
'example.com'
>>> str(newarobj.results[0].properties[0].type)
'header'
>>> str(newarobj.results[0].properties[0].name)
'from'
>>> str(newarobj.results[0].properties[0].value)
'example.com'

# Non-RFC DMARC example with policy included
>>> import authres
>>> import authres.dmarc
>>> new_context = authres.FeatureContext(authres.dmarc)
>>> str(new_context.header(authserv_id='mail-router.example.net',
... results = [authres.dmarc.DMARCAuthenticationResult(result='pass', policy='none',
... header_from='example.com')]))
'Authentication-Results: mail-router.example.net; dmarc=pass header.from=example.com policy.dmarc=none'

# Non-RFC - SPF with localpart in pvalue
>>> import authres
>>> arobj = authres.AuthenticationResultsHeader.parse('Authentication-Results: example.com; spf=pass smtp.mailfrom=authenticated@example.net')
>>> str(arobj.authserv_id)
'example.com'
>>> str(arobj.results[0])
'spf=pass smtp.mailfrom=authenticated@example.net'
>>> str(arobj.results[0].method)
'spf'
>>> str(arobj.results[0].result)
'pass'
>>> str(arobj.results[0].smtp_mailfrom)
'authenticated@example.net'
>>> str(arobj.results[0].smtp_helo)
'None'
>>> str(arobj.results[0].reason)
'None'
>>> str(arobj.results[0].properties[0].type)
'smtp'
>>> str(arobj.results[0].properties[0].name)
'mailfrom'
>>> str(arobj.results[0].properties[0].value)
'authenticated@example.net'

# None RFC - Separate reporting of SPF Mail From and HELO results
>>> import authres
>>> arobj = authres.AuthenticationResultsHeader.parse('Authentication-Results: example.com; spf=pass smtp.mailfrom=authenticated@example.net; spf=none smtp.helo=mailserver.example.net')
>>> str(arobj.authserv_id)
'example.com'
>>> str(arobj.results[0])
'spf=pass smtp.mailfrom=authenticated@example.net'
>>> str(arobj.results[0].method)
'spf'
>>> str(arobj.results[0].result)
'pass'
>>> str(arobj.results[0].smtp_mailfrom)
'authenticated@example.net'
>>> str(arobj.results[0].smtp_helo)
'None'
>>> str(arobj.results[0].reason)
'None'
>>> str(arobj.results[0].properties[0].type)
'smtp'
>>> str(arobj.results[0].properties[0].name)
'mailfrom'
>>> str(arobj.results[0].properties[0].value)
'authenticated@example.net'
>>> str(arobj.results[1])
'spf=none smtp.helo=mailserver.example.net'
>>> str(arobj.results[1].method)
'spf'
>>> str(arobj.results[1].result)
'none'
>>> str(arobj.results[1].smtp_mailfrom)
'None'
>>> str(arobj.results[1].smtp_helo)
'mailserver.example.net'
>>> str(arobj.results[1].reason)
'None'
>>> str(arobj.results[1].properties[0].type)
'smtp'
>>> str(arobj.results[1].properties[0].name)
'helo'
>>> str(arobj.results[1].properties[0].value)
'mailserver.example.net'

# Create header field with multiple SPF results
>>> import authres
>>> mfrom_pass = authres.SPFAuthenticationResult(result = 'pass',
... smtp_mailfrom = 'authenticated@example.net')
>>> helo_none = authres.SPFAuthenticationResult(result = 'none',
... smtp_helo = 'mailserver.example.net', reason = 'No SPF record for HELO')
>>> str(authres.AuthenticationResultsHeader(authserv_id = 'example.com',
... results = [mfrom_pass, helo_none]))
'Authentication-Results: example.com; spf=pass smtp.mailfrom=authenticated@example.net; spf=none reason="No SPF record for HELO" smtp.helo=mailserver.example.net'

# Create header field with ARC results (draft-ietf-dmarc-arc-protocol-18)
>>> import authres
>>> import authres.arc
>>> arc_pass = authres.arc.ARCAuthenticationResult(result = 'pass',
... header_ams_d = 'example.net', header_ams_s='valimail2016', header_as_d="example.com", header_as_s="valimail2017", header_oldest_pass='1', smtp_remote_ip='203.0.113.1')
>>> str(authres.AuthenticationResultsHeader(authserv_id = 'example.com',
... results = [arc_pass]))
'Authentication-Results: example.com; arc=pass header.ams-d=example.net header.ams-s=valimail2016 header.as-d=example.com header.as-s=valimail2017 header.oldest-pass=1 smtp.remote-ip=203.0.113.1'

# Parsing IP6 address.
>>> arobj = authres_context.parse('Authentication-Results: mail.bmsi.com; iprev=pass policy.iprev="2001:748:100:40::2:2" (mout0.freenet.de); spf=none smtp.mailfrom=markuslaudi@freenet.de')
>>> str(arobj.results[0])
'iprev=pass policy.iprev="2001:748:100:40::2:2"'
>>> arobj.results[0].policy_iprev
'2001:748:100:40::2:2'

# Parsing iprev with unquoted IP6 address should fail.
>>> try:
...   arobj = authres.AuthenticationResultsHeader.parse('Authentication-Results: mail.bmsi.com; iprev=pass policy.iprev=2001:748:100:40::2:2 (mout0.freenet.de); spf=none smtp.mailfrom=markuslaudi@freenet.de')
... except authres.SyntaxError as x:
...   print(x)
Syntax error: Expected end of text at: :748:100:40::2:2 (mout0.freenet.de); spf...

# Generating iprev with IP6 address.
>>> iprev_pass = authres.IPRevAuthenticationResult(result = 'pass', policy_iprev = '2001:db8:ea1::dead:beef', policy_iprev_comment='yummy.example.net')
>>> str(authres.AuthenticationResultsHeader(authserv_id='example.com',results = [iprev_pass]))
'Authentication-Results: example.com; iprev=pass policy.iprev="2001:db8:ea1::dead:beef" (yummy.example.net)'

# RFC 7281, Authentication-Results Registration for S/MIME Signature Verification

>>> import authres.smime
>>> mimearobj = authres_context.parse('Authentication-Results: example.net; smime=fail (certificate is revoked by CRL) body.smime-identifier=aliceDss@example.com body.smime-part=2')
>>> str(mimearobj.results[0])
'smime=fail body.smime-identifier=aliceDss@example.com body.smime-part=2'
>>> str(mimearobj.authserv_id)
'example.net'
>>> str(mimearobj.results[0].method)
'smime'
>>> str(mimearobj.results[0].result)
'fail'
>>> str(mimearobj.results[0].reason)
'None'
>>> str(mimearobj.results[0].properties[0].type)
'body'
>>> str(mimearobj.results[0].properties[0].name)
'smime-identifier'
>>> str(mimearobj.results[0].properties[0].value)
'aliceDss@example.com'
>>> str(mimearobj.results[0].properties[1].type)
'body'
>>> str(mimearobj.results[0].properties[1].name)
'smime-part'
>>> str(mimearobj.results[0].properties[1].value)
'2'

>>> import authres.smime
>>> smime_fail = authres.smime.SMIMEAuthenticationResult(result = 'fail', result_comment = 'certificate is revoked by CRL', body_smime_identifier = 'aliceDss@example.com', body_smime_part = '2')
>>> str(authres.AuthenticationResultsHeader(authserv_id='example.net',results = [smime_fail]))
'Authentication-Results: example.net; smime=fail (certificate is revoked by CRL) body.smime-identifier=aliceDss@example.com body.smime-part=2'

"""

# RFC 7293, The Require-Recipient-Valid-Since Header Field  and SMTP Service Extension, header field types

# Example 12.3 from RFC 7293
>>> import authres.rrvs
>>> rrvsarobj = authres_context.parse('Authentication-Results: mx.example.com; rrvs=pass smtp.rcptto=user@example.com')
>>> str(rrvsarobj.authserv_id)
'mx.example.com'
>>> str(rrvsarobj.results[0].method)
'rrvs'
>>> str(rrvsarobj.results[0].result)
'pass'
>>> str(rrvsarobj.results[0].reason)
'None'
>>> str(rrvsarobj.results[0].properties[0].type)
'smtp'
>>> str(rrvsarobj.results[0].properties[0].name)
'rcptto'
>>> str(rrvsarobj.results[0].properties[0].value)
'user@example.com'

>>> import authres.rrvs
>>> rrvs_fail = authres.rrvs.RRVSAuthenticationResult(result = 'fail', result_comment = 'Mail box expired.', smtp_rrvs = 'user@example.com', smtp_rrvs_comment = "These are not the droids you're looking for.")
>>> str(authres.AuthenticationResultsHeader(authserv_id='example.net',results = [rrvs_fail]))
"Authentication-Results: example.net; rrvs=fail (Mail box expired.) smtp.rrvs=user@example.com (These are not the droids you're looking for.)"

# New for RFC 7601 SMTP Auth Mail From

>>> import authres
>>> arobj = authres.AuthenticationResultsHeader.parse('Authentication-Results: example.com; auth=pass smtp.mailfrom=sender@example.net')
>>> str(arobj.authserv_id)
'example.com'
>>> str(arobj.results[0])
'auth=pass smtp.mailfrom=sender@example.net'
>>> str(arobj.results[0].method)
'auth'
>>> str(arobj.results[0].result)
'pass'
>>> str(arobj.results[0].smtp_mailfrom)
'sender@example.net'
>>> str(arobj.results[0].properties[0].type)
'smtp'
>>> str(arobj.results[0].properties[0].name)
'mailfrom'
>>> str(arobj.results[0].properties[0].value)
'sender@example.net'

# Create header field with RFC 7601 SMTP Auth Mail From
>>> import authres
>>> mfrom_auth = authres.SMTPAUTHAuthenticationResult(result = 'pass',
... smtp_mailfrom = 'mailauth@example.net')
>>> str(authres.AuthenticationResultsHeader(authserv_id = 'example.com',
... results = [mfrom_auth]))
'Authentication-Results: example.com; auth=pass smtp.mailfrom=mailauth@example.net'

# Ignore unknown method (RFC 7601 2.7.6 SHOULD)
>>> import authres
>>> arobj = authres.AuthenticationResultsHeader.parse('Authentication-Results: mail.example.org; tls=pass smtp.TLSversion=TLSv1.2 smtp.TLScyper=ECDHE-RSA-CHACHA20-POLY1305 smtp.TLSbits=256')
>>> str(arobj.authserv_id)
'mail.example.org'
>>> str(arobj.results[0])
'tls=pass smtp.tlsversion=TLSv1.2 smtp.tlscyper=ECDHE-RSA-CHACHA20-POLY1305 smtp.tlsbits=256'
>>> str(arobj.results[0].method)
'tls'
>>> str(arobj.results[0].result)
'pass'
>>> try: str(arobj.results[0].smtp_mailfrom)
... except AttributeError as e: print(e)
'AuthenticationResult' object has no attribute 'smtp_mailfrom'
>>> str(arobj.results[0].properties[0].type)
'smtp'
>>> str(arobj.results[0].properties[0].name)
'tlsversion'
>>> str(arobj.results[0].properties[0].value)
'TLSv1.2'


# Invalid ptype (error) and unknown method (OK)
>>> import authres
>>> try: arobj = authres.AuthenticationResultsHeader.parse('Authentication-Results: mail.example.org; x-tls=pass version=TLSv1.2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256')
... except authres.SyntaxError as e: print(e)

>>> str(arobj.authserv_id)
'mail.example.org'
>>> str(arobj.results[0])
'x-tls=pass'

# Valid ptype (OK), unknown method (OK), unknown property (OKish)
>>> import authres
>>> try: arobj = authres.AuthenticationResultsHeader.parse('Authentication-Results: mail.example.org; x-tls=pass smtp.tlsversion=TLSv1.2')
... except authres.SyntaxError as e: print(e)
>>> str(arobj.authserv_id)
'mail.example.org'
>>> str(arobj.results[0])
'x-tls=pass smtp.tlsversion=TLSv1.2'
>>> str(arobj.results[0].method)
'x-tls'
>>> str(arobj.results[0].result)
'pass'
>>> try: str(arobj.results[0].smtp_mailfrom)
... except AttributeError as e: print(e)
'AuthenticationResult' object has no attribute 'smtp_mailfrom'
>>> try: str(arobj.results[0].smtp_tlsversion)
... except AttributeError as e: print(e)
'AuthenticationResult' object has no attribute 'smtp_tlsversion'
>>> str(arobj.results[0].properties[0].type)
'smtp'
>>> str(arobj.results[0].properties[0].name)
'tlsversion'
>>> str(arobj.results[0].properties[0].value)
'TLSv1.2'

# Parse multiple result header field and toss out unknown ptype
>>> import authres
>>> arobj = authres.AuthenticationResultsHeader.parse('Authentication-Results: mail.example.org; arc=none (no signatures found); dkim=pass (1024-bit rsa key sha256) header.d=example.net header.i=@example.net header.b=Qgi/FoC0; dmarc=none (p=none) header.from=example.net; spf=none smtp.mailfrom=test@example.net smtp.helo=mail-wm0-x232.example.com; x-tls=pass version=TLSv1.2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256')
>>> for result in arobj.results:
...     result.method
...     result.result
'arc'
'none'
'dkim'
'pass'
'dmarc'
'none'
'spf'
'none'
'x-tls'
'pass'

# Repeat authserv_id for each result (invalid)
>>> import authres
>>> try: arobj = authres.AuthenticationResultsHeader.parse('authentication-results: thehesiod.com; dkim=none (message not signed) header.d=none;thehesiod.com; dmarc=none action=none header.from=hotmail.com;')
... except authres.SyntaxError as e: print(e)
Syntax error: Expected "=" at: ; dmarc=none action=none header.from=hot...

# vim:sw=4 sts=4