systempayv2: implement HMAC SHA256 signature (#46658)

This commit is contained in:
Serghei Mihai 2020-09-15 14:54:38 +02:00
parent f7d698c71f
commit cae250d132
2 changed files with 37 additions and 4 deletions

View File

@ -15,9 +15,11 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import base64
import pytz
import datetime as dt
import hashlib
import hmac
import string
from six.moves.urllib import parse as urlparse
import warnings
@ -270,6 +272,13 @@ class Payment(PaymentCommon):
{'name': 'secret_production',
'caption': _(u'Secret pour la configuration de PRODUCTION'),
'validation': lambda value: str.isalnum(value), },
{'name': 'signature_algo',
'caption': _(u'Algorithme de signature'),
'default': 'hmac_sha256',
'choices': (
('sha1', 'SHA-1'),
('hmac_sha256', 'HMAC-SHA-256'),
)},
{
'name': 'manual_validation',
'caption': 'Validation manuelle',
@ -462,16 +471,24 @@ class Payment(PaymentCommon):
test=test)
return response
def sha1_sign(self, secret, signed_data):
return hashlib.sha1(signed_data).hexdigest()
def hmac_sha256_sign(self, secret, signed_data):
digest = hmac.HMAC(secret, digestmod=hashlib.sha256, msg=signed_data).digest()
return base64.b64encode(digest)
def signature(self, fields):
self.logger.debug('got fields %s to sign' % fields)
ordered_keys = sorted(
[key for key in fields.keys() if key.startswith('vads_')])
self.logger.debug('ordered keys %s' % ordered_keys)
ordered_fields = [force_byte(fields[key]) for key in ordered_keys]
secret = getattr(self, 'secret_%s' % fields['vads_ctx_mode'].lower())
secret = force_byte(getattr(self, 'secret_%s' % fields['vads_ctx_mode'].lower()))
signed_data = b'+'.join(ordered_fields)
signed_data = b'%s+%s' % (signed_data, force_byte(secret))
signed_data = b'%s+%s' % (signed_data, secret)
self.logger.debug(u'generating signature on «%s»', signed_data)
sign = hashlib.sha1(signed_data).hexdigest()
sign_method = getattr(self, '%s_sign' % self.signature_algo)
sign = sign_method(secret, signed_data)
self.logger.debug(u'signature «%s»', sign)
return sign
return force_text(sign)

View File

@ -31,6 +31,7 @@ PARAMS = {
'vads_site_id': u'12345678',
'vads_ctx_mode': u'TEST',
'vads_trans_date': u'20090501193530',
'signature_algo': 'sha1'
}
@ -80,6 +81,21 @@ def test_systempayv2():
assert response.transaction_date
assert response.transaction_date.isoformat() == '2020-03-30T16:25:30+00:00'
PARAMS['signature_algo'] = 'hmac_sha256'
p = Payment(PARAMS)
assert p.signature(qs) == 'aHrJ7IzSGFa4pcYA8kh99+M/xBzoQ4Odnu3f4BUrpIA='
response_qs = 'vads_amount=1042&vads_auth_mode=FULL&vads_auth_number=3feadf' \
'&vads_auth_result=00&vads_capture_delay=0&vads_card_brand=CB' \
'&vads_card_number=497010XXXXXX0000' \
'&vads_payment_certificate=582ba2b725057618706d7a06e9e59acdbf69ff53' \
'&vads_ctx_mode=TEST&vads_currency=978&vads_effective_amount=1042' \
'&vads_site_id=70168983&vads_trans_date=20161013101355' \
'&vads_trans_id=226787&vads_trans_uuid=4b5053b3b1fe4b02a07753e7a' \
'&vads_effective_creation_date=20200330162530' \
'&signature=PeU30M6ilqwhligBAIMQIR3yqxWFGZHJ8Hwtb%2B3IrOM%3D'
response = p.response(response_qs)
assert response.signed
# bad response
with pytest.raises(ResponseError, match='missing signature, vads_ctx_mode or vads_auth_result'):
p.response('foo=bar')