Commit fad3d37b authored by Łukasz Nowak's avatar Łukasz Nowak

Improve token management.

BearerTokenModule_addNewToken allows to add token for Person passed as
destination_reference. In case if Person has no key assigned new one is
generated.

BearerToken_isValid allows to validate token against (possibly) related person
object.

Base_getHMAC is low level interface to hmac module.

In order to made tokens unique use User-Agent and REMOTE_ADDR in token
generation body. Thanks to this token will be narrowed to one broswer. In order
to avoid reuse token on different servers add Host.

Key to generate HMAC are stored on Person object using bearer_token_key property.
parent 78363299
import hmac
def getHMAC(self, key, body):
digest = hmac.new(key, body)
return digest.hexdigest()
...@@ -4,4 +4,7 @@ ...@@ -4,4 +4,7 @@
<item>Reference</item> <item>Reference</item>
<item>Version</item> <item>Version</item>
</portal_type> </portal_type>
<portal_type id="Person">
<item>BearerToken</item>
</portal_type>
</property_sheet_list> </property_sheet_list>
\ No newline at end of file
<workflow_chain> <workflow_chain>
<chain> <chain>
<type>Bearer Token</type> <type>Bearer Token</type>
<workflow>edit_workflow</workflow> <workflow>edit_workflow, validation_workflow</workflow>
</chain> </chain>
</workflow_chain> </workflow_chain>
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Property Sheet" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_count</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_mt_index</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>_tree</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>BearerToken</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Property Sheet</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Length" module="BTrees.Length"/>
</pickle>
<pickle> <int>0</int> </pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="OOBTree" module="BTrees.OOBTree"/>
</pickle>
<pickle>
<none/>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="OOBTree" module="BTrees.OOBTree"/>
</pickle>
<pickle>
<none/>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Standard Property" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>elementary_type/string</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>bearer_token_key_property</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ExternalMethod" module="Products.ExternalMethod.ExternalMethod"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_function</string> </key>
<value> <string>getHMAC</string> </value>
</item>
<item>
<key> <string>_module</string> </key>
<value> <string>BearerToken</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Base_getHMAC</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>from DateTime import DateTime\n
if context.getPortalType() != \'Bearer Token Module\':\n
raise TypeError(\'Call me on module\')\n
\n
person = context.getPortalObject().portal_catalog.getResultValue(portal_type=\'Person\', reference=destination_reference)\n
\n
if person is None:\n
raise ValueError(\'Cannot find Person with reference %r\' % destination_reference)\n
\n
key = person.getBearerTokenKey()\n
if not key:\n
key = context.Person_resetBearerTokenKey()\n
\n
token = context.newContent(portal_type=\'Bearer Token\',\n
destination_reference=destination_reference,\n
expiration_date=DateTime() + (1./24) # 1 hour of validity\n
)\n
\n
hmac = None\n
for i in range(10):\n
fuzzy = context.Base_generateRandomString()\n
possible_hmac = token.BearerToken_getHMAC(key, fuzzy)\n
if len(context.searchFolder(portal_type=\'Bearer Token\', reference=possible_hmac)) == 0 \\\n
and context.getPortalObject().portal_activities.countMessageWithTag(possible_hmac) == 0:\n
hmac = possible_hmac\n
break\n
\n
if hmac is None:\n
raise ValueError(\'It was not possible to generate valid hmac\')\n
\n
token.edit(\n
source_reference=fuzzy,\n
reference=hmac\n
)\n
token.validate()\n
token.reindexObject(activate_kw={\'tag\': hmac})\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>destination_reference</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>BearerTokenModule_addNewToken</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -81,6 +81,10 @@ ...@@ -81,6 +81,10 @@
<string>title</string> <string>title</string>
<string>Title</string> <string>Title</string>
</tuple> </tuple>
<tuple>
<string>source_reference</string>
<string>Source Reference</string>
</tuple>
<tuple> <tuple>
<string>reference</string> <string>reference</string>
<string>Reference</string> <string>Reference</string>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>return context.Base_getHMAC(key,\n
"""%s\\n%s\\n%s\\n%s\\n%s""" % (\n
context.REQUEST.getHeader(\'User-Agent\'),\n
context.REQUEST.getHeader(\'Host\'),\n
context.REQUEST.get(\'REMOTE_ADDR\'),\n
context.getCreationDate().timeTime(),\n
fuzzy)\n
)\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>key, fuzzy</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>BearerToken_getHMAC</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -56,7 +56,7 @@ context.setVersion(1)\n ...@@ -56,7 +56,7 @@ context.setVersion(1)\n
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string></string> </value> <value> <string>*args, **kwargs</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string encoding="cdata"><![CDATA[
from DateTime import DateTime\n
if context.getPortalType() != \'Bearer Token\':\n
raise TypeError(\'Call me on token\')\n
\n
person = context.getPortalObject().portal_catalog.getResultValue(portal_type=\'Person\', reference=context.getDestinationReference())\n
\n
if person is None:\n
return False\n
\n
script.log(context.BearerToken_getHMAC(person.getBearerTokenKey(), context.getSourceReference()))\n
script.log(context.getReference())\n
if context.BearerToken_getHMAC(person.getBearerTokenKey(), context.getSourceReference()) == context.getReference() \\\n
and context.getExpirationDate() >= DateTime() and context.getValidationState() == \'validated\' \\\n
and context.getDestinationReference() is not None:\n
return True\n
\n
return False\n
]]></string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>BearerToken_isValid</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -94,6 +94,7 @@ ...@@ -94,6 +94,7 @@
<value> <value>
<list> <list>
<string>my_title</string> <string>my_title</string>
<string>my_source_reference</string>
<string>my_reference</string> <string>my_reference</string>
<string>my_destination_reference</string> <string>my_destination_reference</string>
</list> </list>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_source_reference</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_reference</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Source Reference</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>if context.getPortalType() != \'Person\':\n
raise TypeError(\'Shall be called on Person\')\n
\n
token_key = context.Base_generateRandomString()\n
person.setBearerTokenKey(token_key)\n
return token_key\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Person_resetBearerTokenKey</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
1 2
\ No newline at end of file \ No newline at end of file
BearerToken
\ No newline at end of file
Bearer Token | DublinCore Bearer Token | DublinCore
Bearer Token | Reference Bearer Token | Reference
Bearer Token | Version Bearer Token | Version
Person | BearerToken
\ No newline at end of file
Bearer Token | edit_workflow Bearer Token | edit_workflow
Bearer Token | validation_workflow
\ No newline at end of file
BearerToken
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment