mirror of
https://github.com/jazzband/django-analytical.git
synced 2026-03-16 22:20:25 +00:00
Intercom: Add support for HMAC authentication of identified users
Documentation: https://www.intercom.com/help/configure-intercom-for-your-product-or-site/staying-secure/enable-identity-verification-on-your-web-product
This commit is contained in:
parent
47cf9aac3e
commit
4b4f26f54e
3 changed files with 119 additions and 1 deletions
|
|
@ -3,10 +3,14 @@ intercom.io template tags and filters.
|
|||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
import time
|
||||
import re
|
||||
|
||||
from django.conf import settings
|
||||
from django.template import Library, Node, TemplateSyntaxError
|
||||
|
||||
from analytical.utils import disable_html, get_required_setting, \
|
||||
|
|
@ -24,6 +28,34 @@ TRACKING_CODE = """
|
|||
register = Library()
|
||||
|
||||
|
||||
def _hashable_bytes(data): # type: (AnyStr) -> bytes
|
||||
"""
|
||||
Coerce strings to hashable bytes.
|
||||
"""
|
||||
if isinstance(data, bytes):
|
||||
return data
|
||||
elif isinstance(data, str):
|
||||
return data.encode('ascii') # Fail on anything non-ASCII.
|
||||
else:
|
||||
raise TypeError(data)
|
||||
|
||||
|
||||
def intercom_user_hash(data): # type: (AnyStr) -> Optional[str]
|
||||
"""
|
||||
Return a SHA-256 HMAC `user_hash` as expected by Intercom, if configured.
|
||||
|
||||
Return None if the `INTERCOM_HMAC_SECRET_KEY` setting is not configured.
|
||||
"""
|
||||
if getattr(settings, 'INTERCOM_HMAC_SECRET_KEY', None):
|
||||
return hmac.new(
|
||||
key=_hashable_bytes(settings.INTERCOM_HMAC_SECRET_KEY),
|
||||
msg=_hashable_bytes(data),
|
||||
digestmod=hashlib.sha256,
|
||||
).hexdigest()
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
@register.tag
|
||||
def intercom(parser, token):
|
||||
"""
|
||||
|
|
@ -73,6 +105,16 @@ class IntercomNode(Node):
|
|||
else:
|
||||
params['created_at'] = None
|
||||
|
||||
# Generate a user_hash HMAC to verify the user's identity, if configured.
|
||||
# (If both user_id and email are present, the user_id field takes precedence.)
|
||||
# See:
|
||||
# https://www.intercom.com/help/configure-intercom-for-your-product-or-site/staying-secure/enable-identity-verification-on-your-web-product
|
||||
user_hash_data = params.get('user_id', params.get('email')) # type: Optional[str]
|
||||
if user_hash_data:
|
||||
user_hash = intercom_user_hash(str(user_hash_data)) # type: Optional[str]
|
||||
if user_hash is not None:
|
||||
params.setdefault('user_hash', user_hash)
|
||||
|
||||
return params
|
||||
|
||||
def render(self, context):
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ from django.http import HttpRequest
|
|||
from django.template import Context
|
||||
from django.test.utils import override_settings
|
||||
|
||||
from analytical.templatetags.intercom import IntercomNode
|
||||
from analytical.templatetags.intercom import IntercomNode, intercom_user_hash
|
||||
from analytical.tests.utils import TagTestCase
|
||||
from analytical.utils import AnalyticalException
|
||||
|
||||
|
|
@ -103,6 +103,65 @@ class IntercomTagTestCase(TagTestCase):
|
|||
}))
|
||||
self.assertTrue('"email": "explicit"' in r, r)
|
||||
|
||||
@override_settings(INTERCOM_HMAC_SECRET_KEY='secret')
|
||||
def test_user_hash__without_user_details(self):
|
||||
"""
|
||||
No `user_hash` without `user_id` or `email`.
|
||||
"""
|
||||
attrs = IntercomNode()._get_custom_attrs(Context())
|
||||
self.assertEqual({
|
||||
'created_at': None,
|
||||
}, attrs)
|
||||
|
||||
@override_settings(INTERCOM_HMAC_SECRET_KEY='secret')
|
||||
def test_user_hash__with_user(self):
|
||||
"""
|
||||
'user_hash' of default `user_id`.
|
||||
"""
|
||||
user = User.objects.create(
|
||||
email='test@example.com',
|
||||
) # type: User
|
||||
attrs = IntercomNode()._get_custom_attrs(Context({'user': user}))
|
||||
self.assertEqual({
|
||||
'created_at': int(user.date_joined.timestamp()),
|
||||
'email': 'test@example.com',
|
||||
'name': '',
|
||||
'user_hash': intercom_user_hash(str(user.pk)),
|
||||
'user_id': user.pk,
|
||||
}, attrs)
|
||||
|
||||
@override_settings(INTERCOM_HMAC_SECRET_KEY='secret')
|
||||
def test_user_hash__with_explicit_user_id(self):
|
||||
"""
|
||||
'user_hash' of context-provided `user_id`.
|
||||
"""
|
||||
attrs = IntercomNode()._get_custom_attrs(Context({
|
||||
'intercom_email': 'test@example.com',
|
||||
'intercom_user_id': '5',
|
||||
}))
|
||||
self.assertEqual({
|
||||
'created_at': None,
|
||||
'email': 'test@example.com',
|
||||
# HMAC for user_id:
|
||||
'user_hash': 'd3123a7052b42272d9b520235008c248a5aff3221cc0c530b754702ad91ab102',
|
||||
'user_id': '5',
|
||||
}, attrs)
|
||||
|
||||
@override_settings(INTERCOM_HMAC_SECRET_KEY='secret')
|
||||
def test_user_hash__with_explicit_email(self):
|
||||
"""
|
||||
'user_hash' of context-provided `email`.
|
||||
"""
|
||||
attrs = IntercomNode()._get_custom_attrs(Context({
|
||||
'intercom_email': 'test@example.com',
|
||||
}))
|
||||
self.assertEqual({
|
||||
'created_at': None,
|
||||
'email': 'test@example.com',
|
||||
# HMAC for email:
|
||||
'user_hash': '49e43229ee99dca2565241719b8341b04e71dd4de0628f991b5bea30a526e153',
|
||||
}, attrs)
|
||||
|
||||
@override_settings(ANALYTICAL_INTERNAL_IPS=['1.1.1.1'])
|
||||
def test_render_internal_ip(self):
|
||||
req = HttpRequest()
|
||||
|
|
|
|||
|
|
@ -138,6 +138,23 @@ passed to Intercom automatically. See :ref:`identifying-visitors`.
|
|||
|
||||
.. _intercom-internal-ips:
|
||||
|
||||
|
||||
Verifying identified users
|
||||
--------------------------
|
||||
|
||||
Intercom supports HMAC authentication of users identified by user ID or email, in order to prevent impersonation.
|
||||
For more information, see `Enable identity verification on your web product`_ in the Intercom documentation.
|
||||
|
||||
To enable this, configure your Intercom account's HMAC secret key::
|
||||
|
||||
INTERCOM_HMAC_SECRET_KEY = 'XXXXXXXXXXXXXXXXXXXXXXX'
|
||||
|
||||
(You can find this secret key under the "Identity verification" section of your Intercom account settings page.)
|
||||
|
||||
.. _`Enable identity verification on your web product`: https://www.intercom.com/help/configure-intercom-for-your-product-or-site/staying-secure/enable-identity-verification-on-your-web-product
|
||||
|
||||
|
||||
|
||||
Internal IP addresses
|
||||
---------------------
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue